Merge branch 'develop' of github.com:MetaMask/metamask-extension into network-remove-provider-engine

feature/default_network_editable
kumavis 6 years ago
commit 77daed5c74
  1. 16
      .eslintignore
  2. 5
      .eslintrc
  3. 3
      .nsprc
  4. 2
      app/scripts/background.js
  5. 4
      app/scripts/contentscript.js
  6. 2
      app/scripts/controllers/blacklist.js
  7. 2
      app/scripts/controllers/computed-balances.js
  8. 6
      app/scripts/controllers/preferences.js
  9. 2
      app/scripts/controllers/recent-blocks.js
  10. 2
      app/scripts/controllers/transactions/index.js
  11. 2
      app/scripts/lib/cleanErrorStack.js
  12. 2
      app/scripts/lib/createErrorMiddleware.js
  13. 2
      app/scripts/lib/createStreamSink.js
  14. 6
      app/scripts/lib/diagnostics-reporter.js
  15. 4
      app/scripts/lib/extractEthjsErrorMessage.js
  16. 2
      app/scripts/lib/get-first-preferred-lang-code.js
  17. 6
      app/scripts/lib/getObjStructure.js
  18. 12
      app/scripts/lib/local-store.js
  19. 8
      app/scripts/lib/notification-manager.js
  20. 2
      app/scripts/lib/port-stream.js
  21. 2
      app/scripts/lib/reportFailedTxToSentry.js
  22. 2
      app/scripts/lib/setupMetamaskMeshMetrics.js
  23. 14
      app/scripts/lib/setupRaven.js
  24. 7
      app/scripts/metamask-controller.js
  25. 2
      app/scripts/migrations/013.js
  26. 4
      app/scripts/migrations/023.js
  27. 2
      app/scripts/popup-core.js
  28. 2
      app/scripts/ui.js
  29. 2
      development/announcer.js
  30. 2
      development/backGroundConnectionModifiers.js
  31. 15
      development/beefy.js
  32. 4
      development/metamaskbot-build-announce.js
  33. 10
      development/mock-dev.js
  34. 4
      development/mockExtension.js
  35. 2
      development/run-version-bump.js
  36. 4
      development/selector.js
  37. 8
      development/sentry-publish.js
  38. 21
      development/sourcemap-validator.js
  39. 11
      development/ui-dev.js
  40. 24
      development/verify-locale-strings.js
  41. 10
      development/version-bump.js
  42. 157
      gentests.js
  43. 107
      gulpfile.js
  44. 6
      mascara/example/app.js
  45. 4
      mascara/example/server.js
  46. 4
      mascara/src/app/first-time/breadcrumbs.js
  47. 76
      mascara/src/app/first-time/buy-ether-screen.js
  48. 2
      mascara/src/app/first-time/loading-screen.js
  49. 42
      mascara/src/app/shapeshift-form/index.js
  50. 2
      mascara/src/background.js
  51. 2
      mascara/src/ui.js
  52. 6
      mascara/test/helpers.js
  53. 8
      mascara/test/index.js
  54. 2
      mascara/test/test-ui.js
  55. 18
      mascara/test/util/mascara-test-helper.js
  56. 11
      notices/notices.js
  57. 2
      old-ui/app/components/ens-input.js
  58. 2
      old-ui/app/components/loading.js
  59. 4
      old-ui/app/components/transaction-list-item.js
  60. 2
      old-ui/app/config.js
  61. 42
      package-lock.json
  62. 6
      package.json
  63. 2
      test/base.conf.js
  64. 19
      test/e2e/beta/contract-test/contract.js
  65. 20
      test/e2e/beta/from-import-beta-ui.spec.js
  66. 9
      test/e2e/beta/metamask-beta-ui.spec.js
  67. 2
      test/e2e/func.js
  68. 5
      test/e2e/metamask.spec.js
  69. 2
      test/flat.conf.js
  70. 2
      test/integration/lib/add-token.js
  71. 11
      test/integration/lib/confirm-sig-requests.js
  72. 2
      test/integration/lib/currency-localization.js
  73. 2
      test/integration/lib/mascara-first-time.js
  74. 6
      test/integration/lib/send-new-ui.js
  75. 3
      test/integration/lib/tx-list-items.js
  76. 2
      test/lib/createTxMeta.js
  77. 2
      test/lib/mock-encryptor.js
  78. 6
      test/lib/mock-tx-gen.js
  79. 112
      test/lib/react-trigger-change.js
  80. 6
      test/lib/util.js
  81. 4
      test/mascara.conf.js
  82. 30
      test/screens/new-ui.js
  83. 3
      test/unit/app/account-import-strategies.spec.js
  84. 2
      test/unit/app/controllers/address-book-controller.js
  85. 3
      test/unit/app/controllers/network-contoller-test.js
  86. 14
      test/unit/app/controllers/transactions/nonce-tracker-test.js
  87. 94
      test/unit/app/controllers/transactions/pending-tx-test.js
  88. 6
      test/unit/app/controllers/transactions/recipient-blacklist-checker-test.js
  89. 8
      test/unit/app/controllers/transactions/tx-controller-test.js
  90. 1
      test/unit/app/controllers/transactions/tx-gas-util-test.js
  91. 41
      test/unit/app/controllers/transactions/tx-state-history-helper-test.js
  92. 53
      test/unit/app/controllers/transactions/tx-state-manager-test.js
  93. 4
      test/unit/app/controllers/transactions/tx-utils-test.js
  94. 10
      test/unit/app/edge-encryptor-test.js
  95. 8
      test/unit/app/nodeify-test.js
  96. 7
      test/unit/app/pending-balance-test.js
  97. 93
      test/unit/app/seed-phrase-verifier-test.js
  98. 2
      test/unit/app/util-test.js
  99. 2
      test/unit/components/balance-component-test.js
  100. 4
      test/unit/components/bn-as-decimal-input-test.js
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,6 +1,20 @@
node_modules/**
dist/**
builds/**
docs/**
development/bundle.js
development/states.js
app/scripts/lib/extension-instance.js app/scripts/lib/extension-instance.js
app/scripts/chromereload.js
ui/lib/blockies.js
mascara/src/app/first-time/spinner.js
mascara/test/jquery-3.1.0.min.js
test/integration/bundle.js test/integration/bundle.js
test/integration/jquery-3.1.0.min.js test/integration/jquery-3.1.0.min.js
test/integration/helpers.js test/integration/helpers.js
test/integration/lib/first-time.js test/integration/lib/first-time.js
ui/lib/blockies.js

@ -37,7 +37,9 @@
"document": false, "document": false,
"navigator": false, "navigator": false,
"web3": true, "web3": true,
"window": false "window": false,
"$": false,
"QUnit": false
}, },
"rules": { "rules": {
@ -159,5 +161,6 @@
"yield-star-spacing": [2, "both"], "yield-star-spacing": [2, "both"],
"yoda": [2, "never"], "yoda": [2, "never"],
"prefer-const": 1, "prefer-const": 1,
"mocha/no-exclusive-tests": "error"
} }
} }

@ -1,6 +1,7 @@
{ {
"exceptions": [ "exceptions": [
"https://nodesecurity.io/advisories/566", "https://nodesecurity.io/advisories/566",
"https://nodesecurity.io/advisories/157" "https://nodesecurity.io/advisories/157",
"https://nodesecurity.io/advisories/577"
] ]
} }

@ -381,7 +381,7 @@ function setupController (initState, initLangCode) {
} }
// communication with page or other extension // communication with page or other extension
function connectExternal(remotePort) { function connectExternal (remotePort) {
const originDomain = urlUtil.parse(remotePort.sender.url).hostname const originDomain = urlUtil.parse(remotePort.sender.url).hostname
const portStream = new PortStream(remotePort) const portStream = new PortStream(remotePort)
controller.setupUntrustedCommunication(portStream, originDomain) controller.setupUntrustedCommunication(portStream, originDomain)

@ -115,8 +115,8 @@ function logStreamDisconnectWarning (remoteLabel, err) {
* @returns {boolean} {@code true} if Web3 should be injected * @returns {boolean} {@code true} if Web3 should be injected
*/ */
function shouldInjectWeb3 () { function shouldInjectWeb3 () {
return doctypeCheck() && suffixCheck() return doctypeCheck() && suffixCheck() &&
&& documentElementCheck() && !blacklistedDomainCheck() documentElementCheck() && !blacklistedDomainCheck()
} }
/** /**

@ -87,7 +87,7 @@ class BlacklistController {
* *
* @private * @private
* @param {object} config A config object like that found at {@link https://github.com/MetaMask/eth-phishing-detect/blob/master/src/config.json} * @param {object} config A config object like that found at {@link https://github.com/MetaMask/eth-phishing-detect/blob/master/src/config.json}
* *
*/ */
_setupPhishingDetector (config) { _setupPhishingDetector (config) {
this._phishingDetector = new PhishingDetector(config) this._phishingDetector = new PhishingDetector(config)

@ -18,7 +18,7 @@ class ComputedbalancesController {
/** /**
* Creates a new controller instance * Creates a new controller instance
* *
* @param {ComputedBalancesOptions} [opts] Controller configuration parameters * @param {ComputedBalancesOptions} [opts] Controller configuration parameters
*/ */
constructor (opts = {}) { constructor (opts = {}) {
const { accountTracker, txController, blockTracker } = opts const { accountTracker, txController, blockTracker } = opts

@ -111,9 +111,9 @@ class PreferencesController {
* @returns {Promise<string>} selectedAddress the selected address. * @returns {Promise<string>} selectedAddress the selected address.
*/ */
syncAddresses (addresses) { syncAddresses (addresses) {
let { identities, lostIdentities } = this.store.getState() const { identities, lostIdentities } = this.store.getState()
let newlyLost = {} const newlyLost = {}
Object.keys(identities).forEach((identity) => { Object.keys(identities).forEach((identity) => {
if (!addresses.includes(identity)) { if (!addresses.includes(identity)) {
newlyLost[identity] = identities[identity] newlyLost[identity] = identities[identity]
@ -128,7 +128,7 @@ class PreferencesController {
if (this.diagnostics) this.diagnostics.reportOrphans(newlyLost) if (this.diagnostics) this.diagnostics.reportOrphans(newlyLost)
// store lost accounts // store lost accounts
for (let key in newlyLost) { for (const key in newlyLost) {
lostIdentities[key] = newlyLost[key] lostIdentities[key] = newlyLost[key]
} }
} }

@ -127,7 +127,7 @@ class RecentBlocksController {
* *
* @returns {Promise<void>} Promises undefined * @returns {Promise<void>} Promises undefined
*/ */
async backfill() { async backfill () {
this.blockTracker.once('latest', async (blockNumberHex) => { this.blockTracker.once('latest', async (blockNumberHex) => {
const currentBlockNumber = Number.parseInt(blockNumberHex, 16) const currentBlockNumber = Number.parseInt(blockNumberHex, 16)
const blocksToFetch = Math.min(currentBlockNumber, this.historyLength) const blocksToFetch = Math.min(currentBlockNumber, this.historyLength)

@ -455,7 +455,7 @@ class TransactionController extends EventEmitter {
txStateManager.on('tx:status-update', updateSubscription) txStateManager.on('tx:status-update', updateSubscription)
updateSubscription() updateSubscription()
function updateSubscription() { function updateSubscription () {
const pendingTxs = txStateManager.getPendingTransactions() const pendingTxs = txStateManager.getPendingTransactions()
if (!listenersAreActive && pendingTxs.length > 0) { if (!listenersAreActive && pendingTxs.length > 0) {
blockTracker.on('latest', latestBlockHandler) blockTracker.on('latest', latestBlockHandler)

@ -3,7 +3,7 @@
* @param {Error} err - error * @param {Error} err - error
* @returns {Error} Error with clean stack trace. * @returns {Error} Error with clean stack trace.
*/ */
function cleanErrorStack(err){ function cleanErrorStack (err) {
var name = err.name var name = err.name
name = (name === undefined) ? 'Error' : String(name) name = (name === undefined) ? 'Error' : String(name)

@ -64,4 +64,4 @@ function createErrorMiddleware ({ override = true } = {}) {
} }
} }
module.exports = createErrorMiddleware module.exports = createErrorMiddleware

@ -4,7 +4,7 @@ const promiseToCallback = require('promise-to-callback')
module.exports = createStreamSink module.exports = createStreamSink
function createStreamSink(asyncWriteFn, _opts) { function createStreamSink (asyncWriteFn, _opts) {
return new AsyncWritableStream(asyncWriteFn, _opts) return new AsyncWritableStream(asyncWriteFn, _opts)
} }

@ -5,7 +5,7 @@ class DiagnosticsReporter {
this.version = version this.version = version
} }
async reportOrphans(orphans) { async reportOrphans (orphans) {
try { try {
return await this.submit({ return await this.submit({
accounts: Object.keys(orphans), accounts: Object.keys(orphans),
@ -19,7 +19,7 @@ class DiagnosticsReporter {
} }
} }
async reportMultipleKeyrings(rawKeyrings) { async reportMultipleKeyrings (rawKeyrings) {
try { try {
const keyrings = await Promise.all(rawKeyrings.map(async (keyring, index) => { const keyrings = await Promise.all(rawKeyrings.map(async (keyring, index) => {
return { return {
@ -55,7 +55,7 @@ class DiagnosticsReporter {
} }
function postData(data) { function postData (data) {
const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts' const uri = 'https://diagnostics.metamask.io/v1/orphanedAccounts'
return fetch(uri, { return fetch(uri, {
body: JSON.stringify(data), // must match 'Content-Type' header body: JSON.stringify(data), // must match 'Content-Type' header

@ -10,13 +10,13 @@ module.exports = extractEthjsErrorMessage
* *
* @param {string} errorMessage The error message to parse * @param {string} errorMessage The error message to parse
* @returns {string} Returns an error message, either the same as was passed, or the ending message portion of an isEthjsRpcError * @returns {string} Returns an error message, either the same as was passed, or the ending message portion of an isEthjsRpcError
* *
* @example * @example
* // returns 'Transaction Failed: replacement transaction underpriced' * // returns 'Transaction Failed: replacement transaction underpriced'
* extractEthjsErrorMessage(`Error: [ethjs-rpc] rpc error with payload {"id":3947817945380,"jsonrpc":"2.0","params":["0xf8eb8208708477359400830398539406012c8cf97bead5deae237070f9587f8e7a266d80b8843d7d3f5a0000000000000000000000000000000000000000000000000000000000081d1a000000000000000000000000000000000000000000000000001ff973cafa800000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000003f48025a04c32a9b630e0d9e7ff361562d850c86b7a884908135956a7e4a336fa0300d19ca06830776423f25218e8d19b267161db526e66895567147015b1f3fc47aef9a3c7"],"method":"eth_sendRawTransaction"} Error: replacement transaction underpriced`) * extractEthjsErrorMessage(`Error: [ethjs-rpc] rpc error with payload {"id":3947817945380,"jsonrpc":"2.0","params":["0xf8eb8208708477359400830398539406012c8cf97bead5deae237070f9587f8e7a266d80b8843d7d3f5a0000000000000000000000000000000000000000000000000000000000081d1a000000000000000000000000000000000000000000000000001ff973cafa800000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000003f48025a04c32a9b630e0d9e7ff361562d850c86b7a884908135956a7e4a336fa0300d19ca06830776423f25218e8d19b267161db526e66895567147015b1f3fc47aef9a3c7"],"method":"eth_sendRawTransaction"} Error: replacement transaction underpriced`)
* *
*/ */
function extractEthjsErrorMessage(errorMessage) { function extractEthjsErrorMessage (errorMessage) {
const isEthjsRpcError = errorMessage.includes(ethJsRpcSlug) const isEthjsRpcError = errorMessage.includes(ethJsRpcSlug)
if (isEthjsRpcError) { if (isEthjsRpcError) {
const payloadAndError = errorMessage.slice(ethJsRpcSlug.length) const payloadAndError = errorMessage.slice(ethJsRpcSlug.length)

@ -28,7 +28,7 @@ async function getFirstPreferredLangCode () {
// safeguard for Brave Browser until they implement chrome.i18n.getAcceptLanguages // safeguard for Brave Browser until they implement chrome.i18n.getAcceptLanguages
// https://github.com/MetaMask/metamask-extension/issues/4270 // https://github.com/MetaMask/metamask-extension/issues/4270
if (!userPreferredLocaleCodes){ if (!userPreferredLocaleCodes) {
userPreferredLocaleCodes = [] userPreferredLocaleCodes = []
} }

@ -18,12 +18,12 @@ module.exports = getObjStructure
* Creates an object that represents the structure of the given object. It replaces all values with the result of their * Creates an object that represents the structure of the given object. It replaces all values with the result of their
* type. * type.
* *
* @param {object} obj The object for which a 'structure' will be returned. Usually a plain object and not a class. * @param {object} obj The object for which a 'structure' will be returned. Usually a plain object and not a class.
* @returns {object} The "mapped" version of a deep clone of the passed object, with each non-object property value * @returns {object} The "mapped" version of a deep clone of the passed object, with each non-object property value
* replaced with the javascript type of that value. * replaced with the javascript type of that value.
* *
*/ */
function getObjStructure(obj) { function getObjStructure (obj) {
const structure = clone(obj) const structure = clone(obj)
return deepMap(structure, (value) => { return deepMap(structure, (value) => {
return value === null ? 'null' : typeof value return value === null ? 'null' : typeof value
@ -38,7 +38,7 @@ function getObjStructure(obj) {
* @param {Function} visit The modifier to apply to each non-object property value * @param {Function} visit The modifier to apply to each non-object property value
* @returns {object} The modified object * @returns {object} The modified object
*/ */
function deepMap(target = {}, visit) { function deepMap (target = {}, visit) {
Object.entries(target).forEach(([key, value]) => { Object.entries(target).forEach(([key, value]) => {
if (typeof value === 'object' && value !== null) { if (typeof value === 'object' && value !== null) {
target[key] = deepMap(value, visit) target[key] = deepMap(value, visit)

@ -8,7 +8,7 @@ module.exports = class ExtensionStore {
/** /**
* @constructor * @constructor
*/ */
constructor() { constructor () {
this.isSupported = !!(extension.storage.local) this.isSupported = !!(extension.storage.local)
if (!this.isSupported) { if (!this.isSupported) {
log.error('Storage local API not available.') log.error('Storage local API not available.')
@ -19,7 +19,7 @@ module.exports = class ExtensionStore {
* Returns all of the keys currently saved * Returns all of the keys currently saved
* @return {Promise<*>} * @return {Promise<*>}
*/ */
async get() { async get () {
if (!this.isSupported) return undefined if (!this.isSupported) return undefined
const result = await this._get() const result = await this._get()
// extension.storage.local always returns an obj // extension.storage.local always returns an obj
@ -36,7 +36,7 @@ module.exports = class ExtensionStore {
* @param {object} state - The state to set * @param {object} state - The state to set
* @return {Promise<void>} * @return {Promise<void>}
*/ */
async set(state) { async set (state) {
return this._set(state) return this._set(state)
} }
@ -45,7 +45,7 @@ module.exports = class ExtensionStore {
* @private * @private
* @return {object} the key-value map from local storage * @return {object} the key-value map from local storage
*/ */
_get() { _get () {
const local = extension.storage.local const local = extension.storage.local
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
local.get(null, (/** @type {any} */ result) => { local.get(null, (/** @type {any} */ result) => {
@ -65,7 +65,7 @@ module.exports = class ExtensionStore {
* @return {Promise<void>} * @return {Promise<void>}
* @private * @private
*/ */
_set(obj) { _set (obj) {
const local = extension.storage.local const local = extension.storage.local
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
local.set(obj, () => { local.set(obj, () => {
@ -85,6 +85,6 @@ module.exports = class ExtensionStore {
* @param {object} obj - The object to check * @param {object} obj - The object to check
* @returns {boolean} * @returns {boolean}
*/ */
function isEmpty(obj) { function isEmpty (obj) {
return Object.keys(obj).length === 0 return Object.keys(obj).length === 0
} }

@ -26,15 +26,15 @@ class NotificationManager {
// bring focus to existing chrome popup // bring focus to existing chrome popup
extension.windows.update(popup.id, { focused: true }) extension.windows.update(popup.id, { focused: true })
} else { } else {
const cb = (currentPopup) => { this._popupId = currentPopup.id }
// create new notification popup // create new notification popup
extension.windows.create({ const creation = extension.windows.create({
url: 'notification.html', url: 'notification.html',
type: 'popup', type: 'popup',
width, width,
height, height,
}).then((currentPopup) => { }, cb)
this._popupId = currentPopup.id creation && creation.then && creation.then(cb)
})
} }
}) })
} }

@ -58,7 +58,7 @@ PortDuplexStream.prototype._read = noop
/** /**
* Called internally when data should be written to * Called internally when data should be written to
* this writable stream. * this writable stream.
* *
* @private * @private
* @param {*} msg Arbitrary object to write * @param {*} msg Arbitrary object to write
* @param {string} encoding Encoding to use when writing payload * @param {string} encoding Encoding to use when writing payload

@ -7,7 +7,7 @@ module.exports = reportFailedTxToSentry
// for sending to sentry // for sending to sentry
// //
function reportFailedTxToSentry({ raven, txMeta }) { function reportFailedTxToSentry ({ raven, txMeta }) {
const errorMessage = 'Transaction Failed: ' + extractEthjsErrorMessage(txMeta.err.message) const errorMessage = 'Transaction Failed: ' + extractEthjsErrorMessage(txMeta.err.message)
raven.captureMessage(errorMessage, { raven.captureMessage(errorMessage, {
// "extra" key is required by Sentry // "extra" key is required by Sentry

@ -4,7 +4,7 @@ module.exports = setupMetamaskMeshMetrics
/** /**
* Injects an iframe into the current document for testing * Injects an iframe into the current document for testing
*/ */
function setupMetamaskMeshMetrics() { function setupMetamaskMeshMetrics () {
const testingContainer = document.createElement('iframe') const testingContainer = document.createElement('iframe')
testingContainer.src = 'https://metamask.github.io/mesh-testing/' testingContainer.src = 'https://metamask.github.io/mesh-testing/'
console.log('Injecting MetaMask Mesh testing client') console.log('Injecting MetaMask Mesh testing client')

@ -7,7 +7,7 @@ const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496'
module.exports = setupRaven module.exports = setupRaven
// Setup raven / sentry remote error reporting // Setup raven / sentry remote error reporting
function setupRaven(opts) { function setupRaven (opts) {
const { release } = opts const { release } = opts
let ravenTarget let ravenTarget
@ -21,7 +21,7 @@ function setupRaven(opts) {
const client = Raven.config(ravenTarget, { const client = Raven.config(ravenTarget, {
release, release,
transport: function(opts) { transport: function (opts) {
const report = opts.data const report = opts.data
try { try {
// handle error-like non-error exceptions // handle error-like non-error exceptions
@ -42,7 +42,7 @@ function setupRaven(opts) {
return Raven return Raven
} }
function rewriteErrorLikeExceptions(report) { function rewriteErrorLikeExceptions (report) {
// handle errors that lost their error-ness in serialization (e.g. dnode) // handle errors that lost their error-ness in serialization (e.g. dnode)
rewriteErrorMessages(report, (errorMessage) => { rewriteErrorMessages(report, (errorMessage) => {
if (!errorMessage.includes('Non-Error exception captured with keys:')) return errorMessage if (!errorMessage.includes('Non-Error exception captured with keys:')) return errorMessage
@ -51,7 +51,7 @@ function rewriteErrorLikeExceptions(report) {
}) })
} }
function simplifyErrorMessages(report) { function simplifyErrorMessages (report) {
rewriteErrorMessages(report, (errorMessage) => { rewriteErrorMessages(report, (errorMessage) => {
// simplify ethjs error messages // simplify ethjs error messages
errorMessage = extractEthjsErrorMessage(errorMessage) errorMessage = extractEthjsErrorMessage(errorMessage)
@ -64,7 +64,7 @@ function simplifyErrorMessages(report) {
}) })
} }
function rewriteErrorMessages(report, rewriteFn) { function rewriteErrorMessages (report, rewriteFn) {
// rewrite top level message // rewrite top level message
if (typeof report.message === 'string') report.message = rewriteFn(report.message) if (typeof report.message === 'string') report.message = rewriteFn(report.message)
// rewrite each exception message // rewrite each exception message
@ -75,7 +75,7 @@ function rewriteErrorMessages(report, rewriteFn) {
} }
} }
function rewriteReportUrls(report) { function rewriteReportUrls (report) {
// update request url // update request url
report.request.url = toMetamaskUrl(report.request.url) report.request.url = toMetamaskUrl(report.request.url)
// update exception stack trace // update exception stack trace
@ -88,7 +88,7 @@ function rewriteReportUrls(report) {
} }
} }
function toMetamaskUrl(origUrl) { function toMetamaskUrl (origUrl) {
const filePath = origUrl.split(location.origin)[1] const filePath = origUrl.split(location.origin)[1]
if (!filePath) return origUrl if (!filePath) return origUrl
const metamaskUrl = `metamask${filePath}` const metamaskUrl = `metamask${filePath}`

@ -399,7 +399,6 @@ module.exports = class MetamaskController extends EventEmitter {
} }
//============================================================================= //=============================================================================
// VAULT / KEYRING RELATED METHODS // VAULT / KEYRING RELATED METHODS
//============================================================================= //=============================================================================
@ -645,7 +644,7 @@ module.exports = class MetamaskController extends EventEmitter {
* @param {Object} msgParams - The params passed to eth_sign. * @param {Object} msgParams - The params passed to eth_sign.
* @param {Object} req - (optional) the original request, containing the origin * @param {Object} req - (optional) the original request, containing the origin
*/ */
async newUnapprovedTransaction(txParams, req) { async newUnapprovedTransaction (txParams, req) {
return await this.txController.newUnapprovedTransaction(txParams, req) return await this.txController.newUnapprovedTransaction(txParams, req)
} }
@ -931,7 +930,7 @@ module.exports = class MetamaskController extends EventEmitter {
* Allows a user to begin the seed phrase recovery process. * Allows a user to begin the seed phrase recovery process.
* @param {Function} cb - A callback function called when complete. * @param {Function} cb - A callback function called when complete.
*/ */
markPasswordForgotten(cb) { markPasswordForgotten (cb) {
this.configManager.setPasswordForgotten(true) this.configManager.setPasswordForgotten(true)
this.sendUpdate() this.sendUpdate()
cb() cb()
@ -941,7 +940,7 @@ module.exports = class MetamaskController extends EventEmitter {
* Allows a user to end the seed phrase recovery process. * Allows a user to end the seed phrase recovery process.
* @param {Function} cb - A callback function called when complete. * @param {Function} cb - A callback function called when complete.
*/ */
unMarkPasswordForgotten(cb) { unMarkPasswordForgotten (cb) {
this.configManager.setPasswordForgotten(false) this.configManager.setPasswordForgotten(false)
this.sendUpdate() this.sendUpdate()
cb() cb()

@ -28,7 +28,7 @@ module.exports = {
function transformState (state) { function transformState (state) {
const newState = state const newState = state
const { config } = newState const { config } = newState
if ( config && config.provider ) { if (config && config.provider) {
if (config.provider.type === 'testnet') { if (config.provider.type === 'testnet') {
newState.config.provider.type = 'ropsten' newState.config.provider.type = 'ropsten'
} }

@ -35,10 +35,10 @@ function transformState (state) {
if (transactions.length <= 40) return newState if (transactions.length <= 40) return newState
let reverseTxList = transactions.reverse() const reverseTxList = transactions.reverse()
let stripping = true let stripping = true
while (reverseTxList.length > 40 && stripping) { while (reverseTxList.length > 40 && stripping) {
let txIndex = reverseTxList.findIndex((txMeta) => { const txIndex = reverseTxList.findIndex((txMeta) => {
return (txMeta.status === 'failed' || return (txMeta.status === 'failed' ||
txMeta.status === 'rejected' || txMeta.status === 'rejected' ||
txMeta.status === 'confirmed' || txMeta.status === 'confirmed' ||

@ -12,7 +12,7 @@ module.exports = initializePopup
/** /**
* Asynchronously initializes the MetaMask popup UI * Asynchronously initializes the MetaMask popup UI
* *
* @param {{ container: Element, connectionStream: * }} config Popup configuration object * @param {{ container: Element, connectionStream: * }} config Popup configuration object
* @param {Function} cb Called when initialization is complete * @param {Function} cb Called when initialization is complete
*/ */
function initializePopup ({ container, connectionStream }, cb) { function initializePopup ({ container, connectionStream }, cb) {

@ -14,7 +14,7 @@ const log = require('loglevel')
start().catch(log.error) start().catch(log.error)
async function start() { async function start () {
// create platform global // create platform global
global.platform = new ExtensionPlatform() global.platform = new ExtensionPlatform()

@ -7,6 +7,6 @@ var changelog = fs.readFileSync(path.join(__dirname, '..', 'CHANGELOG.md')).toSt
var log = changelog.split(version)[1].split('##')[0].trim() var log = changelog.split(version)[1].split('##')[0].trim()
let msg = `*MetaMask ${version}* now published! It should auto-update soon!\n${log}` const msg = `*MetaMask ${version}* now published! It should auto-update soon!\n${log}`
console.log(msg) console.log(msg)

@ -1,5 +1,5 @@
module.exports = { module.exports = {
"confirm sig requests": { 'confirm sig requests': {
signMessage: (msgData, cb) => { signMessage: (msgData, cb) => {
const stateUpdate = { const stateUpdate = {
unapprovedMsgs: {}, unapprovedMsgs: {},

@ -1,17 +1,14 @@
const beefy = require('beefy') const beefy = require('beefy')
const http = require('http') const http = require('http')
const fs = require('fs')
const path = require('path')
const port = 8124 const port = 8124
const handler = beefy({ const handler = beefy({
entries: {'mocker.js': 'bundle.js'} entries: {'mocker.js': 'bundle.js'},
, cwd: __dirname cwd: __dirname,
, live: true live: true,
, open: true open: true,
, quiet: false quiet: false,
, bundlerFlags: ['-t', 'brfs'] bundlerFlags: ['-t', 'brfs'],
}) })

@ -4,7 +4,7 @@ const VERSION = require('../dist/chrome/manifest.json').version
start().catch(console.error) start().catch(console.error)
async function start() { async function start () {
const GITHUB_COMMENT_TOKEN = process.env.GITHUB_COMMENT_TOKEN const GITHUB_COMMENT_TOKEN = process.env.GITHUB_COMMENT_TOKEN
const CIRCLE_PULL_REQUEST = process.env.CIRCLE_PULL_REQUEST const CIRCLE_PULL_REQUEST = process.env.CIRCLE_PULL_REQUEST
@ -20,7 +20,7 @@ async function start() {
} }
const CIRCLE_PR_NUMBER = CIRCLE_PULL_REQUEST.split('/').pop() const CIRCLE_PR_NUMBER = CIRCLE_PULL_REQUEST.split('/').pop()
const SHORT_SHA1 = CIRCLE_SHA1.slice(0,7) const SHORT_SHA1 = CIRCLE_SHA1.slice(0, 7)
const BUILD_LINK_BASE = `https://${CIRCLE_BUILD_NUM}-42009758-gh.circle-artifacts.com/0` const BUILD_LINK_BASE = `https://${CIRCLE_BUILD_NUM}-42009758-gh.circle-artifacts.com/0`
const MASCARA = `${BUILD_LINK_BASE}/builds/mascara/home.html` const MASCARA = `${BUILD_LINK_BASE}/builds/mascara/home.html`

@ -12,7 +12,6 @@
* To use, run `npm run mock`. * To use, run `npm run mock`.
*/ */
const extend = require('xtend')
const render = require('react-dom').render const render = require('react-dom').render
const h = require('react-hyperscript') const h = require('react-hyperscript')
const Root = require('../ui/app/root') const Root = require('../ui/app/root')
@ -24,7 +23,6 @@ const Selector = require('./selector')
const MetamaskController = require('../app/scripts/metamask-controller') const MetamaskController = require('../app/scripts/metamask-controller')
const firstTimeState = require('../app/scripts/first-time-state') const firstTimeState = require('../app/scripts/first-time-state')
const ExtensionPlatform = require('../app/scripts/platforms/extension') const ExtensionPlatform = require('../app/scripts/platforms/extension')
const extension = require('./mockExtension')
const noop = function () {} const noop = function () {}
const log = require('loglevel') const log = require('loglevel')
@ -81,14 +79,14 @@ const controller = new MetamaskController({
initState: firstTimeState, initState: firstTimeState,
}) })
global.metamaskController = controller global.metamaskController = controller
global.platform = new ExtensionPlatform global.platform = new ExtensionPlatform()
// //
// User Interface // User Interface
// //
actions._setBackgroundConnection(controller.getApi()) actions._setBackgroundConnection(controller.getApi())
actions.update = function(stateName) { actions.update = function (stateName) {
selectedView = stateName selectedView = stateName
updateQueryParams(stateName) updateQueryParams(stateName)
const newState = states[selectedView] const newState = states[selectedView]
@ -98,7 +96,7 @@ actions.update = function(stateName) {
} }
} }
function modifyBackgroundConnection(backgroundConnectionModifier) { function modifyBackgroundConnection (backgroundConnectionModifier) {
const modifiedBackgroundConnection = Object.assign({}, controller.getApi(), backgroundConnectionModifier) const modifiedBackgroundConnection = Object.assign({}, controller.getApi(), backgroundConnectionModifier)
actions._setBackgroundConnection(modifiedBackgroundConnection) actions._setBackgroundConnection(modifiedBackgroundConnection)
} }
@ -112,7 +110,7 @@ var store = configureStore(firstState)
// start app // start app
startApp() startApp()
function startApp(){ function startApp () {
const body = document.body const body = document.body
const container = document.createElement('div') const container = document.createElement('div')
container.id = 'test-container' container.id = 'test-container'

@ -39,6 +39,6 @@ extension.runtime.reload = noop
extension.tabs.create = noop extension.tabs.create = noop
extension.runtime.getManifest = function () { extension.runtime.getManifest = function () {
return { return {
version: 'development' version: 'development',
} }
} }

@ -11,7 +11,7 @@ const bumpType = normalizeType(process.argv[2])
start().catch(console.error) start().catch(console.error)
async function start() { async function start () {
const changeBuffer = await readFile(changelogPath) const changeBuffer = await readFile(changelogPath)
const changelog = changeBuffer.toString() const changelog = changeBuffer.toString()

@ -11,7 +11,7 @@ function NewComponent () {
NewComponent.prototype.render = function () { NewComponent.prototype.render = function () {
const props = this.props const props = this.props
let { const {
states, states,
selectedKey, selectedKey,
actions, actions,
@ -28,7 +28,7 @@ NewComponent.prototype.render = function () {
margin: '20px 20px 0px', margin: '20px 20px 0px',
}, },
value: selected, value: selected,
onChange:(event) => { onChange: (event) => {
const selectedKey = event.target.value const selectedKey = event.target.value
const backgroundConnectionModifier = backGroundConnectionModifiers[selectedKey] const backgroundConnectionModifier = backGroundConnectionModifiers[selectedKey]
modifyBackgroundConnection(backgroundConnectionModifier || {}) modifyBackgroundConnection(backgroundConnectionModifier || {})

@ -5,7 +5,7 @@ const VERSION = require('../dist/chrome/manifest.json').version
start().catch(console.error) start().catch(console.error)
async function start(){ async function start () {
const authWorked = await checkIfAuthWorks() const authWorked = await checkIfAuthWorks()
if (!authWorked) { if (!authWorked) {
console.log(`Sentry auth failed...`) console.log(`Sentry auth failed...`)
@ -31,21 +31,21 @@ async function start(){
console.log('all done!') console.log('all done!')
} }
async function checkIfAuthWorks() { async function checkIfAuthWorks () {
const itWorked = await doesNotFail(async () => { const itWorked = await doesNotFail(async () => {
await exec(`sentry-cli releases --org 'metamask' --project 'metamask' list`) await exec(`sentry-cli releases --org 'metamask' --project 'metamask' list`)
}) })
return itWorked return itWorked
} }
async function checkIfVersionExists() { async function checkIfVersionExists () {
const versionAlreadyExists = await doesNotFail(async () => { const versionAlreadyExists = await doesNotFail(async () => {
await exec(`sentry-cli releases --org 'metamask' --project 'metamask' info ${VERSION}`) await exec(`sentry-cli releases --org 'metamask' --project 'metamask' info ${VERSION}`)
}) })
return versionAlreadyExists return versionAlreadyExists
} }
async function doesNotFail(asyncFn) { async function doesNotFail (asyncFn) {
try { try {
await asyncFn() await asyncFn()
return true return true

@ -1,6 +1,6 @@
const fs = require('fs') const fs = require('fs')
const { SourceMapConsumer } = require('source-map') const { SourceMapConsumer } = require('source-map')
const path = require('path')
// //
// Utility to help check if sourcemaps are working // Utility to help check if sourcemaps are working
// //
@ -11,9 +11,11 @@ const { SourceMapConsumer } = require('source-map')
start() start()
async function start() {
const rawBuild = fs.readFileSync(__dirname + '/../dist/chrome/inpage.js', 'utf8') async function start () {
const rawSourceMap = fs.readFileSync(__dirname + '/../dist/sourcemaps/inpage.js.map', 'utf8') const rawBuild = fs.readFileSync(path.join(__dirname, '/../dist/chrome/', 'inpage.js')
, 'utf8')
const rawSourceMap = fs.readFileSync(path.join(__dirname, '/../dist/sourcemaps/', 'inpage.js.map'), 'utf8')
const consumer = await new SourceMapConsumer(rawSourceMap) const consumer = await new SourceMapConsumer(rawSourceMap)
console.log('hasContentsOfAllSources:', consumer.hasContentsOfAllSources(), '\n') console.log('hasContentsOfAllSources:', consumer.hasContentsOfAllSources(), '\n')
@ -34,7 +36,7 @@ async function start() {
if (result.source === 'node_modules/web3/dist/web3.min.js') return // minified mess if (result.source === 'node_modules/web3/dist/web3.min.js') return // minified mess
const sourceContent = consumer.sourceContentFor(result.source) const sourceContent = consumer.sourceContentFor(result.source)
const sourceLines = sourceContent.split('\n') const sourceLines = sourceContent.split('\n')
const line = sourceLines[result.line-1] const line = sourceLines[result.line - 1]
console.log(`\n========================== ${result.source} ====================================\n`) console.log(`\n========================== ${result.source} ====================================\n`)
console.log(line) console.log(line)
console.log(`\n==============================================================================\n`) console.log(`\n==============================================================================\n`)
@ -42,8 +44,9 @@ async function start() {
}) })
} }
function indicesOf(substring, string) { function indicesOf (substring, string) {
var a=[],i=-1; var a = []
while((i=string.indexOf(substring,i+1)) >= 0) a.push(i); var i = -1
return a; while ((i = string.indexOf(substring, i + 1)) >= 0) a.push(i)
return a
} }

@ -29,9 +29,8 @@ log.setDefaultLevel(1)
// Query String // Query String
const qs = require('qs') const qs = require('qs')
let queryString = qs.parse(window.location.href.split('#')[1]) const queryString = qs.parse(window.location.href.split('#')[1])
let selectedView = queryString.view || 'first time' let selectedView = queryString.view || 'first time'
const firstState = states[selectedView]
updateQueryParams(selectedView) updateQueryParams(selectedView)
// CSS // CSS
@ -39,15 +38,15 @@ const MetaMaskUiCss = require('../ui/css')
const injectCss = require('inject-css') const injectCss = require('inject-css')
function updateQueryParams(newView) { function updateQueryParams (newView) {
queryString.view = newView queryString.view = newView
const params = qs.stringify(queryString) const params = qs.stringify(queryString)
window.location.href = window.location.href.split('#')[0] + `#${params}` window.location.href = window.location.href.split('#')[0] + `#${params}`
} }
const actions = { const actions = {
_setBackgroundConnection(){}, _setBackgroundConnection () {},
update: function(stateName) { update: function (stateName) {
selectedView = stateName selectedView = stateName
updateQueryParams(stateName) updateQueryParams(stateName)
const newState = states[selectedView] const newState = states[selectedView]
@ -67,7 +66,7 @@ var store = configureStore(states[selectedView])
// start app // start app
startApp() startApp()
function startApp(){ function startApp () {
const body = document.body const body = document.body
const container = document.createElement('div') const container = document.createElement('div')
container.id = 'test-container' container.id = 'test-container'

@ -1,4 +1,4 @@
//////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////
// //
// Locale verification script // Locale verification script
// //
@ -8,7 +8,7 @@
// //
// will check the given locale against the strings in english // will check the given locale against the strings in english
// //
//////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
@ -20,7 +20,7 @@ const specifiedLocale = process.argv[2]
if (specifiedLocale) { if (specifiedLocale) {
console.log(`Verifying selected locale "${specifiedLocale}":\n\n`) console.log(`Verifying selected locale "${specifiedLocale}":\n\n`)
const locale = localeIndex.find(localeMeta => localeMeta.code === specifiedLocale) const locale = localeIndex.find(localeMeta => localeMeta.code === specifiedLocale)
verifyLocale({ localeMeta }) verifyLocale({ locale })
} else { } else {
console.log('Verifying all locales:\n\n') console.log('Verifying all locales:\n\n')
localeIndex.forEach(localeMeta => { localeIndex.forEach(localeMeta => {
@ -30,16 +30,16 @@ if (specifiedLocale) {
} }
function verifyLocale ({ localeMeta }) {
function verifyLocale({ localeMeta }) {
const localeCode = localeMeta.code const localeCode = localeMeta.code
const localeName = localeMeta.name const localeName = localeMeta.name
let targetLocale, englishLocale
try { try {
const localeFilePath = path.join(process.cwd(), 'app', '_locales', localeCode, 'messages.json') const localeFilePath = path.join(process.cwd(), 'app', '_locales', localeCode, 'messages.json')
targetLocale = JSON.parse(fs.readFileSync(localeFilePath, 'utf8')); targetLocale = JSON.parse(fs.readFileSync(localeFilePath, 'utf8'))
} catch (e) { } catch (e) {
if (e.code == 'ENOENT') { if (e.code === 'ENOENT') {
console.log('Locale file not found') console.log('Locale file not found')
} else { } else {
console.log(`Error opening your locale ("${localeCode}") file: `, e) console.log(`Error opening your locale ("${localeCode}") file: `, e)
@ -49,9 +49,9 @@ function verifyLocale({ localeMeta }) {
try { try {
const englishFilePath = path.join(process.cwd(), 'app', '_locales', 'en', 'messages.json') const englishFilePath = path.join(process.cwd(), 'app', '_locales', 'en', 'messages.json')
englishLocale = JSON.parse(fs.readFileSync(englishFilePath, 'utf8')); englishLocale = JSON.parse(fs.readFileSync(englishFilePath, 'utf8'))
} catch (e) { } catch (e) {
if(e.code == 'ENOENT') { if (e.code === 'ENOENT') {
console.log('English File not found') console.log('English File not found')
} else { } else {
console.log('Error opening english locale file: ', e) console.log('Error opening english locale file: ', e)
@ -71,7 +71,7 @@ function verifyLocale({ localeMeta }) {
if (extraItems.length) { if (extraItems.length) {
console.log('\nMissing from english locale:') console.log('\nMissing from english locale:')
extraItems.forEach(function(key) { extraItems.forEach(function (key) {
console.log(` - [ ] ${key}`) console.log(` - [ ] ${key}`)
}) })
} else { } else {
@ -80,7 +80,7 @@ function verifyLocale({ localeMeta }) {
if (missingItems.length) { if (missingItems.length) {
console.log(`\nMissing:`) console.log(`\nMissing:`)
missingItems.forEach(function(key) { missingItems.forEach(function (key) {
console.log(` - [ ] ${key}`) console.log(` - [ ] ${key}`)
}) })
} else { } else {
@ -92,6 +92,6 @@ function verifyLocale({ localeMeta }) {
} }
} }
function compareLocalesForMissingItems({ base, subject }) { function compareLocalesForMissingItems ({ base, subject }) {
return Object.keys(base).filter((key) => !subject[key]) return Object.keys(base).filter((key) => !subject[key])
} }

@ -1,6 +1,6 @@
const clone = require('clone') const clone = require('clone')
async function versionBump(bumpType, changelog, oldManifest) { async function versionBump (bumpType, changelog, oldManifest) {
const manifest = clone(oldManifest) const manifest = clone(oldManifest)
const newVersion = newVersionFrom(manifest, bumpType) const newVersion = newVersionFrom(manifest, bumpType)
@ -19,13 +19,13 @@ async function versionBump(bumpType, changelog, oldManifest) {
return { return {
version: newVersion, version: newVersion,
manifest: manifest, manifest: manifest,
changelog: logLines.join('\n') changelog: logLines.join('\n'),
} }
} }
function newVersionFrom (manifest, bumpType) { function newVersionFrom (manifest, bumpType) {
const string = manifest.version const string = manifest.version
let segments = string.split('.').map((str) => parseInt(str)) const segments = string.split('.').map((str) => parseInt(str))
switch (bumpType) { switch (bumpType) {
case 'major': case 'major':
@ -45,8 +45,4 @@ function newVersionFrom (manifest, bumpType) {
return segments.map(String).join('.') return segments.map(String).join('.')
} }
function bumpManifest (manifest, bumpType) {
}
module.exports = versionBump module.exports = versionBump

@ -1,6 +1,6 @@
const fs = require('fs') const fs = require('fs')
const async = require('async')
const path = require('path') const path = require('path')
const async = require('async')
const promisify = require('pify') const promisify = require('pify')
// start(/\.selectors.js/, generateSelectorTest).catch(console.error) // start(/\.selectors.js/, generateSelectorTest).catch(console.error)
@ -8,7 +8,6 @@ const promisify = require('pify')
startContainer(/\.container.js/, generateContainerTest).catch(console.error) startContainer(/\.container.js/, generateContainerTest).catch(console.error)
async function getAllFileNames (dirName) { async function getAllFileNames (dirName) {
const rootPath = path.join(__dirname, dirName)
const allNames = (await promisify(fs.readdir)(dirName)) const allNames = (await promisify(fs.readdir)(dirName))
const fileNames = allNames.filter(name => name.match(/^.+\./)) const fileNames = allNames.filter(name => name.match(/^.+\./))
const dirNames = allNames.filter(name => name.match(/^[^.]+$/)) const dirNames = allNames.filter(name => name.match(/^[^.]+$/))
@ -16,7 +15,7 @@ async function getAllFileNames (dirName) {
const fullPathDirNames = dirNames.map(d => `${dirName}/${d}`) const fullPathDirNames = dirNames.map(d => `${dirName}/${d}`)
const subNameArrays = await promisify(async.map)(fullPathDirNames, getAllFileNames) const subNameArrays = await promisify(async.map)(fullPathDirNames, getAllFileNames)
let subNames = [] let subNames = []
subNameArrays.forEach(subNameArray => subNames = [...subNames, ...subNameArray]) subNameArrays.forEach(subNameArray => { subNames = [...subNames, ...subNameArray] })
return [ return [
...fileNames.map(name => dirName + '/' + name), ...fileNames.map(name => dirName + '/' + name),
@ -24,14 +23,15 @@ async function getAllFileNames (dirName) {
] ]
} }
/*
async function start (fileRegEx, testGenerator) { async function start (fileRegEx, testGenerator) {
const fileNames = await getAllFileNames('./ui/app') const fileNames = await getAllFileNames('./ui/app')
const sFiles = fileNames.filter(name => name.match(fileRegEx)) const sFiles = fileNames.filter(name => name.match(fileRegEx))
let sFileMethodNames let sFileMethodNames
let testFilePath let testFilePath
async.each(sFiles, async (sFile, cb) => { async.each(sFiles, async (sFile, cb) => {
let [, sRootPath, sPath] = sFile.match(/^(.+\/)([^/]+)$/) const [, sRootPath, sPath] = sFile.match(/^(.+\/)([^/]+)$/)
sFileMethodNames = Object.keys(require(__dirname + '/' + sFile)) sFileMethodNames = Object.keys(require(__dirname + '/' + sFile))
testFilePath = sPath.replace('.', '-').replace('.', '.test.') testFilePath = sPath.replace('.', '-').replace('.', '.test.')
@ -44,92 +44,96 @@ async function start (fileRegEx, testGenerator) {
}, (err) => { }, (err) => {
console.log(err) console.log(err)
}) })
} }
*/
async function startContainer (fileRegEx, testGenerator) { async function startContainer (fileRegEx, testGenerator) {
const fileNames = await getAllFileNames('./ui/app') const fileNames = await getAllFileNames('./ui/app')
const sFiles = fileNames.filter(name => name.match(fileRegEx)) const sFiles = fileNames.filter(name => name.match(fileRegEx))
let sFileMethodNames
async.each(sFiles, async (sFile, cb) => { async.each(sFiles, async (sFile, cb) => {
console.log(`sFile`, sFile); console.log(`sFile`, sFile)
let [, sRootPath, sPath] = sFile.match(/^(.+\/)([^/]+)$/) const [, sRootPath, sPath] = sFile.match(/^(.+\/)([^/]+)$/)
let testFilePath = sPath.replace('.', '-').replace('.', '.test.') const testFilePath = sPath.replace('.', '-').replace('.', '.test.')
await promisify(fs.readFile)( await promisify(fs.readFile)(
__dirname + '/' + sFile, path.join(__dirname, sFile),
'utf8', 'utf8',
async (err, result) => { async (err, result) => {
console.log(`result`, result.length); if (err) {
const returnObjectStrings = result console.log('Error: ', err)
.match(/return\s(\{[\s\S]+?})\n}/g) } else {
.map(str => { console.log(`result`, result.length)
return str const returnObjectStrings = result
.slice(0, str.length - 1) .match(/return\s(\{[\s\S]+?})\n}/g)
.slice(7) .map(str => {
.replace(/\n/g, '') return str
.replace(/\s\s+/g, ' ') .slice(0, str.length - 1)
.slice(7)
.replace(/\n/g, '')
.replace(/\s\s+/g, ' ')
})
const mapStateToPropsAssertionObject = returnObjectStrings[0]
.replace(/\w+:\s\w+\([\w,\s]+\),/g, str => {
const strKey = str.match(/^\w+/)[0]
return strKey + ': \'mock' + str.match(/^\w+/)[0].replace(/^./, c => c.toUpperCase()) + ':mockState\',\n'
})
.replace(/{\s\w.+/, firstLinePair => `{\n ${firstLinePair.slice(2)}`)
.replace(/\w+:.+,/g, s => ` ${s}`)
.replace(/}/g, s => ` ${s}`)
let mapDispatchToPropsMethodNames
if (returnObjectStrings[1]) {
mapDispatchToPropsMethodNames = returnObjectStrings[1].match(/\s\w+:\s/g).map(str => str.match(/\w+/)[0])
}
const proxyquireObject = ('{\n ' + result
.match(/import\s{[\s\S]+?}\sfrom\s.+/g)
.map(s => s.replace(/\n/g, ''))
.map((s, i) => {
const proxyKeys = s.match(/{.+}/)[0].match(/\w+/g)
return '\'' + s.match(/'(.+)'/)[1] + '\': { ' + (proxyKeys.length > 1
? '\n ' + proxyKeys.join(': () => {},\n ') + ': () => {},\n '
: proxyKeys[0] + ': () => {},') + ' }'
})
.join(',\n ') + '\n}')
.replace('{ connect: () => {}, },', `{
connect: (ms, md) => {
mapStateToProps = ms
mapDispatchToProps = md
return () => ({})
},
},`)
// console.log(`proxyquireObject`, proxyquireObject);
// console.log(`mapStateToPropsAssertionObject`, mapStateToPropsAssertionObject);
// console.log(`mapDispatchToPropsMethodNames`, mapDispatchToPropsMethodNames);
const containerTest = generateContainerTest(sPath, {
mapStateToPropsAssertionObject,
mapDispatchToPropsMethodNames,
proxyquireObject,
}) })
const mapStateToPropsAssertionObject = returnObjectStrings[0] // console.log(`containerTest`, `${__dirname}/${sRootPath}tests/${testFilePath}`, containerTest);
.replace(/\w+:\s\w+\([\w,\s]+\),/g, str => { console.log('----')
const strKey = str.match(/^\w+/)[0] console.log(`sRootPath`, sRootPath)
return strKey + ': \'mock' + str.match(/^\w+/)[0].replace(/^./, c => c.toUpperCase()) + ':mockState\',\n' console.log(`testFilePath`, testFilePath)
}) await promisify(fs.writeFile)(
.replace(/{\s\w.+/, firstLinePair => `{\n ${firstLinePair.slice(2)}`) `${__dirname}/${sRootPath}tests/${testFilePath}`,
.replace(/\w+:.+,/g, s => ` ${s}`) containerTest,
.replace(/}/g, s => ` ${s}`) 'utf8'
let mapDispatchToPropsMethodNames )
if (returnObjectStrings[1]) {
mapDispatchToPropsMethodNames = returnObjectStrings[1].match(/\s\w+:\s/g).map(str => str.match(/\w+/)[0])
} }
const proxyquireObject = ('{\n ' + result
.match(/import\s{[\s\S]+?}\sfrom\s.+/g)
.map(s => s.replace(/\n/g, ''))
.map((s, i) => {
const proxyKeys = s.match(/{.+}/)[0].match(/\w+/g)
return '\'' + s.match(/'(.+)'/)[1] + '\': { ' + (proxyKeys.length > 1
? '\n ' + proxyKeys.join(': () => {},\n ') + ': () => {},\n '
: proxyKeys[0] + ': () => {},') + ' }'
})
.join(',\n ') + '\n}')
.replace('{ connect: () => {}, },', `{
connect: (ms, md) => {
mapStateToProps = ms
mapDispatchToProps = md
return () => ({})
},
},`)
// console.log(`proxyquireObject`, proxyquireObject);
// console.log(`mapStateToPropsAssertionObject`, mapStateToPropsAssertionObject);
// console.log(`mapDispatchToPropsMethodNames`, mapDispatchToPropsMethodNames);
const containerTest = generateContainerTest(sPath, {
mapStateToPropsAssertionObject,
mapDispatchToPropsMethodNames,
proxyquireObject,
})
// console.log(`containerTest`, `${__dirname}/${sRootPath}tests/${testFilePath}`, containerTest);
console.log('----')
console.log(`sRootPath`, sRootPath);
console.log(`testFilePath`, testFilePath);
await promisify(fs.writeFile)(
`${__dirname}/${sRootPath}tests/${testFilePath}`,
containerTest,
'utf8'
)
} }
) )
}, (err) => { }, (err) => {
console.log('123', err) console.log('123', err)
}) })
}
}
/*
function generateMethodList (methodArray) { function generateMethodList (methodArray) {
return methodArray.map(n => ' ' + n).join(',\n') + ',' return methodArray.map(n => ' ' + n).join(',\n') + ','
} }
function generateMethodDescribeBlock (methodName, index) { function generateMethodDescribeBlock (methodName, index) {
@ -143,7 +147,7 @@ function generateMethodDescribeBlock (methodName, index) {
})` })`
return describeBlock return describeBlock
} }
*/
function generateDispatchMethodDescribeBlock (methodName, index) { function generateDispatchMethodDescribeBlock (methodName, index) {
const describeBlock = const describeBlock =
`${index ? ' ' : ''}describe('${methodName}()', () => { `${index ? ' ' : ''}describe('${methodName}()', () => {
@ -154,12 +158,13 @@ function generateDispatchMethodDescribeBlock (methodName, index) {
})` })`
return describeBlock return describeBlock
} }
/*
function generateMethodDescribeBlocks (methodArray) { function generateMethodDescribeBlocks (methodArray) {
return methodArray return methodArray
.map((methodName, index) => generateMethodDescribeBlock(methodName, index)) .map((methodName, index) => generateMethodDescribeBlock(methodName, index))
.join('\n\n') .join('\n\n')
} }
*/
function generateDispatchMethodDescribeBlocks (methodArray) { function generateDispatchMethodDescribeBlocks (methodArray) {
return methodArray return methodArray
@ -167,6 +172,7 @@ function generateDispatchMethodDescribeBlocks (methodArray) {
.join('\n\n') .join('\n\n')
} }
/*
function generateSelectorTest (name, methodArray) { function generateSelectorTest (name, methodArray) {
return `import assert from 'assert' return `import assert from 'assert'
import { import {
@ -192,6 +198,7 @@ describe('${name.match(/^[^.]+/)} utils', () => {
})` })`
} }
*/
function generateContainerTest (sPath, { function generateContainerTest (sPath, {
mapStateToPropsAssertionObject, mapStateToPropsAssertionObject,
@ -231,4 +238,4 @@ describe('${sPath.match(/^[^.]+/)} container', () => {
}) })
})` })`
} }

@ -13,27 +13,21 @@ const zip = require('gulp-zip')
const assign = require('lodash.assign') const assign = require('lodash.assign')
const livereload = require('gulp-livereload') const livereload = require('gulp-livereload')
const del = require('del') const del = require('del')
const eslint = require('gulp-eslint')
const fs = require('fs') const fs = require('fs')
const path = require('path') const path = require('path')
const manifest = require('./app/manifest.json') const manifest = require('./app/manifest.json')
const replace = require('gulp-replace')
const mkdirp = require('mkdirp') const mkdirp = require('mkdirp')
const asyncEach = require('async/each')
const exec = require('child_process').exec
const sass = require('gulp-sass') const sass = require('gulp-sass')
const autoprefixer = require('gulp-autoprefixer') const autoprefixer = require('gulp-autoprefixer')
const gulpStylelint = require('gulp-stylelint') const gulpStylelint = require('gulp-stylelint')
const stylefmt = require('gulp-stylefmt') const stylefmt = require('gulp-stylefmt')
const uglify = require('gulp-uglify-es').default const uglify = require('gulp-uglify-es').default
const babel = require('gulp-babel')
const debug = require('gulp-debug')
const pify = require('pify') const pify = require('pify')
const gulpMultiProcess = require('gulp-multi-process') const gulpMultiProcess = require('gulp-multi-process')
const endOfStream = pify(require('end-of-stream')) const endOfStream = pify(require('end-of-stream'))
function gulpParallel (...args) { function gulpParallel (...args) {
return function spawnGulpChildProcess(cb) { return function spawnGulpChildProcess (cb) {
return gulpMultiProcess(args, cb, true) return gulpMultiProcess(args, cb, true)
} }
} }
@ -48,12 +42,12 @@ const commonPlatforms = [
// browser webapp // browser webapp
'mascara', 'mascara',
// browser extensions // browser extensions
...browserPlatforms ...browserPlatforms,
] ]
// browser reload // browser reload
gulp.task('dev:reload', function() { gulp.task('dev:reload', function () {
livereload.listen({ livereload.listen({
port: 35729, port: 35729,
}) })
@ -108,7 +102,7 @@ createCopyTasks('html:mascara', {
destinations: [`./dist/mascara/`], destinations: [`./dist/mascara/`],
}) })
function createCopyTasks(label, opts) { function createCopyTasks (label, opts) {
if (!opts.devOnly) { if (!opts.devOnly) {
const copyTaskName = `copy:${label}` const copyTaskName = `copy:${label}`
copyTask(copyTaskName, opts) copyTask(copyTaskName, opts)
@ -119,7 +113,7 @@ function createCopyTasks(label, opts) {
copyDevTaskNames.push(copyDevTaskName) copyDevTaskNames.push(copyDevTaskName)
} }
function copyTask(taskName, opts){ function copyTask (taskName, opts) {
const source = opts.source const source = opts.source
const destination = opts.destination const destination = opts.destination
const destinations = opts.destinations || [destination] const destinations = opts.destinations || [destination]
@ -137,12 +131,12 @@ function copyTask(taskName, opts){
return performCopy() return performCopy()
}) })
function performCopy() { function performCopy () {
// stream from source // stream from source
let stream = gulp.src(source + pattern, { base: source }) let stream = gulp.src(source + pattern, { base: source })
// copy to destinations // copy to destinations
destinations.forEach(function(destination) { destinations.forEach(function (destination) {
stream = stream.pipe(gulp.dest(destination)) stream = stream.pipe(gulp.dest(destination))
}) })
@ -152,40 +146,40 @@ function copyTask(taskName, opts){
// manifest tinkering // manifest tinkering
gulp.task('manifest:chrome', function() { gulp.task('manifest:chrome', function () {
return gulp.src('./dist/chrome/manifest.json') return gulp.src('./dist/chrome/manifest.json')
.pipe(jsoneditor(function(json) { .pipe(jsoneditor(function (json) {
delete json.applications delete json.applications
return json return json
})) }))
.pipe(gulp.dest('./dist/chrome', { overwrite: true })) .pipe(gulp.dest('./dist/chrome', { overwrite: true }))
}) })
gulp.task('manifest:opera', function() { gulp.task('manifest:opera', function () {
return gulp.src('./dist/opera/manifest.json') return gulp.src('./dist/opera/manifest.json')
.pipe(jsoneditor(function(json) { .pipe(jsoneditor(function (json) {
json.permissions = [ json.permissions = [
"storage", 'storage',
"tabs", 'tabs',
"clipboardWrite", 'clipboardWrite',
"clipboardRead", 'clipboardRead',
"http://localhost:8545/" 'http://localhost:8545/',
] ]
return json return json
})) }))
.pipe(gulp.dest('./dist/opera', { overwrite: true })) .pipe(gulp.dest('./dist/opera', { overwrite: true }))
}) })
gulp.task('manifest:production', function() { gulp.task('manifest:production', function () {
return gulp.src([ return gulp.src([
'./dist/firefox/manifest.json', './dist/firefox/manifest.json',
'./dist/chrome/manifest.json', './dist/chrome/manifest.json',
'./dist/edge/manifest.json', './dist/edge/manifest.json',
'./dist/opera/manifest.json', './dist/opera/manifest.json',
],{base: './dist/'}) ], {base: './dist/'})
// Exclude chromereload script in production: // Exclude chromereload script in production:
.pipe(jsoneditor(function(json) { .pipe(jsoneditor(function (json) {
json.background.scripts = json.background.scripts.filter((script) => { json.background.scripts = json.background.scripts.filter((script) => {
return !script.includes('chromereload') return !script.includes('chromereload')
}) })
@ -212,29 +206,6 @@ gulp.task('dev:copy',
) )
) )
// lint js
const lintTargets = ['app/**/*.json', 'app/**/*.js', '!app/scripts/vendor/**/*.js', 'ui/**/*.js', 'old-ui/**/*.js', 'mascara/src/*.js', 'mascara/server/*.js', '!node_modules/**', '!dist/firefox/**', '!docs/**', '!app/scripts/chromereload.js', '!mascara/test/jquery-3.1.0.min.js']
gulp.task('lint', function () {
// Ignoring node_modules, dist/firefox, and docs folders:
return gulp.src(lintTargets)
.pipe(eslint(fs.readFileSync(path.join(__dirname, '.eslintrc'))))
// eslint.format() outputs the lint results to the console.
// Alternatively use eslint.formatEach() (see Docs).
.pipe(eslint.format())
// To have the process exit with an error code (1) on
// lint error, return the stream and pipe to failAfterError last.
.pipe(eslint.failAfterError())
});
gulp.task('lint:fix', function () {
return gulp.src(lintTargets)
.pipe(eslint(Object.assign(fs.readFileSync(path.join(__dirname, '.eslintrc')), {fix: true})))
.pipe(eslint.format())
.pipe(eslint.failAfterError())
});
// scss compilation and autoprefixing tasks // scss compilation and autoprefixing tasks
gulp.task('build:scss', createScssBuildTask({ gulp.task('build:scss', createScssBuildTask({
@ -250,7 +221,7 @@ gulp.task('dev:scss', createScssBuildTask({
pattern: 'ui/app/**/*.scss', pattern: 'ui/app/**/*.scss',
})) }))
function createScssBuildTask({ src, dest, devMode, pattern }) { function createScssBuildTask ({ src, dest, devMode, pattern }) {
return function () { return function () {
if (devMode) { if (devMode) {
watch(pattern, async (event) => { watch(pattern, async (event) => {
@ -262,7 +233,7 @@ function createScssBuildTask({ src, dest, devMode, pattern }) {
return buildScss() return buildScss()
} }
function buildScss() { function buildScss () {
return gulp.src(src) return gulp.src(src)
.pipe(sourcemaps.init()) .pipe(sourcemaps.init())
.pipe(sass().on('error', sass.logError)) .pipe(sass().on('error', sass.logError))
@ -272,22 +243,22 @@ function createScssBuildTask({ src, dest, devMode, pattern }) {
} }
} }
gulp.task('lint-scss', function() { gulp.task('lint-scss', function () {
return gulp return gulp
.src('ui/app/css/itcss/**/*.scss') .src('ui/app/css/itcss/**/*.scss')
.pipe(gulpStylelint({ .pipe(gulpStylelint({
reporters: [ reporters: [
{ formatter: 'string', console: true } { formatter: 'string', console: true },
], ],
fix: true, fix: true,
})); }))
}); })
gulp.task('fmt-scss', function () { gulp.task('fmt-scss', function () {
return gulp.src('ui/app/css/itcss/**/*.scss') return gulp.src('ui/app/css/itcss/**/*.scss')
.pipe(stylefmt()) .pipe(stylefmt())
.pipe(gulp.dest('ui/app/css/itcss')); .pipe(gulp.dest('ui/app/css/itcss'))
}); })
// build js // build js
@ -300,11 +271,11 @@ const buildJsFiles = [
// bundle tasks // bundle tasks
createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'dev:extension:js', devMode: true }) createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'dev:extension:js', devMode: true })
createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'build:extension:js' }) createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'build:extension:js' })
createTasksForBuildJsMascara({ taskPrefix: 'build:mascara:js' }) createTasksForBuildJsMascara({ taskPrefix: 'build:mascara:js' })
createTasksForBuildJsMascara({ taskPrefix: 'dev:mascara:js', devMode: true }) createTasksForBuildJsMascara({ taskPrefix: 'dev:mascara:js', devMode: true })
function createTasksForBuildJsExtension({ buildJsFiles, taskPrefix, devMode, bundleTaskOpts = {} }) { function createTasksForBuildJsExtension ({ buildJsFiles, taskPrefix, devMode, bundleTaskOpts = {} }) {
// inpage must be built before all other scripts: // inpage must be built before all other scripts:
const rootDir = './app/scripts' const rootDir = './app/scripts'
const nonInpageFiles = buildJsFiles.filter(file => file !== 'inpage') const nonInpageFiles = buildJsFiles.filter(file => file !== 'inpage')
@ -322,7 +293,7 @@ function createTasksForBuildJsExtension({ buildJsFiles, taskPrefix, devMode, bun
createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1, buildPhase2 }) createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1, buildPhase2 })
} }
function createTasksForBuildJsMascara({ taskPrefix, devMode, bundleTaskOpts = {} }) { function createTasksForBuildJsMascara ({ taskPrefix, devMode, bundleTaskOpts = {} }) {
// inpage must be built before all other scripts: // inpage must be built before all other scripts:
const rootDir = './mascara/src/' const rootDir = './mascara/src/'
const buildPhase1 = ['ui', 'proxy', 'background', 'metamascara'] const buildPhase1 = ['ui', 'proxy', 'background', 'metamascara']
@ -338,7 +309,7 @@ function createTasksForBuildJsMascara({ taskPrefix, devMode, bundleTaskOpts = {}
createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1 }) createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1 })
} }
function createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1 = [], buildPhase2 = [] }) { function createTasksForBuildJs ({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1 = [], buildPhase2 = [] }) {
// bundle task for each file // bundle task for each file
const jsFiles = [].concat(buildPhase1, buildPhase2) const jsFiles = [].concat(buildPhase1, buildPhase2)
jsFiles.forEach((jsFile) => { jsFiles.forEach((jsFile) => {
@ -367,7 +338,7 @@ gulp.task('disc', gulp.parallel(buildJsFiles.map(jsFile => `disc:${jsFile}`)))
// clean dist // clean dist
gulp.task('clean', function clean() { gulp.task('clean', function clean () {
return del(['./dist/*']) return del(['./dist/*'])
}) })
@ -460,7 +431,7 @@ gulp.task('dist',
// task generators // task generators
function zipTask(target) { function zipTask (target) {
return () => { return () => {
return gulp.src(`dist/${target}/**`) return gulp.src(`dist/${target}/**`)
.pipe(zip(`metamask-${target}-${manifest.version}.zip`)) .pipe(zip(`metamask-${target}-${manifest.version}.zip`))
@ -468,7 +439,7 @@ function zipTask(target) {
} }
} }
function generateBundler(opts, performBundle) { function generateBundler (opts, performBundle) {
const browserifyOpts = assign({}, watchify.args, { const browserifyOpts = assign({}, watchify.args, {
entries: [opts.filepath], entries: [opts.filepath],
plugin: 'browserify-derequire', plugin: 'browserify-derequire',
@ -497,7 +468,7 @@ function generateBundler(opts, performBundle) {
return bundler return bundler
} }
function discTask(opts) { function discTask (opts) {
opts = Object.assign({ opts = Object.assign({
buildWithFullPaths: true, buildWithFullPaths: true,
}, opts) }, opts)
@ -508,7 +479,7 @@ function discTask(opts) {
return performBundle return performBundle
function performBundle(){ function performBundle () {
// start "disc" build // start "disc" build
const discDir = path.join(__dirname, 'disc') const discDir = path.join(__dirname, 'disc')
mkdirp.sync(discDir) mkdirp.sync(discDir)
@ -523,14 +494,14 @@ function discTask(opts) {
} }
function bundleTask(opts) { function bundleTask (opts) {
const bundler = generateBundler(opts, performBundle) const bundler = generateBundler(opts, performBundle)
// output build logs to terminal // output build logs to terminal
bundler.on('log', gutil.log) bundler.on('log', gutil.log)
return performBundle return performBundle
function performBundle(){ function performBundle () {
let buildStream = bundler.bundle() let buildStream = bundler.bundle()
// handle errors // handle errors
@ -562,7 +533,7 @@ function bundleTask(opts) {
buildStream = buildStream buildStream = buildStream
.pipe(uglify({ .pipe(uglify({
mangle: { mangle: {
reserved: [ 'MetamaskInpageProvider' ] reserved: [ 'MetamaskInpageProvider' ],
}, },
})) }))
} }

@ -3,7 +3,7 @@ const EthQuery = require('ethjs-query')
window.addEventListener('load', loadProvider) window.addEventListener('load', loadProvider)
window.addEventListener('message', console.warn) window.addEventListener('message', console.warn)
async function loadProvider() { async function loadProvider () {
const ethereumProvider = window.metamask.createDefaultProvider({ host: 'http://localhost:9001' }) const ethereumProvider = window.metamask.createDefaultProvider({ host: 'http://localhost:9001' })
const ethQuery = new EthQuery(ethereumProvider) const ethQuery = new EthQuery(ethereumProvider)
const accounts = await ethQuery.accounts() const accounts = await ethQuery.accounts()
@ -13,7 +13,7 @@ async function loadProvider() {
} }
function logToDom(message, context){ function logToDom (message, context) {
document.getElementById(context).innerText = message document.getElementById(context).innerText = message
console.log(message) console.log(message)
} }
@ -35,4 +35,4 @@ function setupButtons (ethQuery) {
}) })
logToDom(txHash, 'cb-value') logToDom(txHash, 'cb-value')
}) })
} }

@ -1,8 +1,8 @@
const express = require('express') const express = require('express')
const path = require('path')
const createMetamascaraServer = require('../server/') const createMetamascaraServer = require('../server/')
const createBundle = require('../server/util').createBundle const createBundle = require('../server/util').createBundle
const serveBundle = require('../server/util').serveBundle const serveBundle = require('../server/util').serveBundle
// //
// Iframe Server // Iframe Server
// //
@ -23,7 +23,7 @@ const dappServer = express()
// serve dapp bundle // serve dapp bundle
serveBundle(dappServer, '/app.js', createBundle(require.resolve('./app.js'))) serveBundle(dappServer, '/app.js', createBundle(require.resolve('./app.js')))
dappServer.use(express.static(__dirname + '/app/')) dappServer.use(express.static(path.join(__dirname, '/app/')))
// start the server // start the server
const dappPort = '9002' const dappPort = '9002'

@ -8,7 +8,7 @@ export default class Breadcrumbs extends Component {
currentIndex: PropTypes.number, currentIndex: PropTypes.number,
}; };
render() { render () {
const {total, currentIndex} = this.props const {total, currentIndex} = this.props
return ( return (
<div className="breadcrumbs"> <div className="breadcrumbs">
@ -20,7 +20,7 @@ export default class Breadcrumbs extends Component {
/> />
))} ))}
</div> </div>
); )
} }
} }

@ -54,7 +54,7 @@ class BuyEtherScreen extends Component {
return ( return (
<div <div
className='buy-ether__do-it-later' className="buy-ether__do-it-later"
onClick={() => showAccountDetail(address)} onClick={() => showAccountDetail(address)}
> >
Do it later Do it later
@ -64,17 +64,17 @@ class BuyEtherScreen extends Component {
renderCoinbaseLogo () { renderCoinbaseLogo () {
return ( return (
<svg width='140px' height='49px' viewBox='0 0 579 126' version='1.1'> <svg width="140px" height="49px" viewBox="0 0 579 126" version="1.1">
<g id='Page-1' stroke='none' strokeWidth={1} fill='none' fillRule='evenodd'> <g id="Page-1" stroke="none" strokeWidth={1} fill="none" fillRule="evenodd">
<g id='Imported-Layers' fill='#0081C9'> <g id="Imported-Layers" fill="#0081C9">
<path d='M37.752,125.873 C18.824,125.873 0.369,112.307 0.369,81.549 C0.369,50.79 18.824,37.382 37.752,37.382 C47.059,37.382 54.315,39.749 59.52,43.219 L53.841,55.68 C50.371,53.156 45.166,51.579 39.961,51.579 C28.604,51.579 18.193,60.57 18.193,81.391 C18.193,102.212 28.919,111.361 39.961,111.361 C45.166,111.361 50.371,109.783 53.841,107.26 L59.52,120.036 C54.157,123.664 47.059,125.873 37.752,125.873' id='Fill-1' /> <path d="M37.752,125.873 C18.824,125.873 0.369,112.307 0.369,81.549 C0.369,50.79 18.824,37.382 37.752,37.382 C47.059,37.382 54.315,39.749 59.52,43.219 L53.841,55.68 C50.371,53.156 45.166,51.579 39.961,51.579 C28.604,51.579 18.193,60.57 18.193,81.391 C18.193,102.212 28.919,111.361 39.961,111.361 C45.166,111.361 50.371,109.783 53.841,107.26 L59.52,120.036 C54.157,123.664 47.059,125.873 37.752,125.873" id="Fill-1" />
<path d='M102.898,125.873 C78.765,125.873 65.515,106.786 65.515,81.549 C65.515,56.311 78.765,37.382 102.898,37.382 C127.032,37.382 140.282,56.311 140.282,81.549 C140.282,106.786 127.032,125.873 102.898,125.873 L102.898,125.873 Z M102.898,51.105 C89.491,51.105 82.866,63.093 82.866,81.391 C82.866,99.688 89.491,111.834 102.898,111.834 C116.306,111.834 122.931,99.688 122.931,81.391 C122.931,63.093 116.306,51.105 102.898,51.105 L102.898,51.105 Z' id='Fill-2' /> <path d="M102.898,125.873 C78.765,125.873 65.515,106.786 65.515,81.549 C65.515,56.311 78.765,37.382 102.898,37.382 C127.032,37.382 140.282,56.311 140.282,81.549 C140.282,106.786 127.032,125.873 102.898,125.873 L102.898,125.873 Z M102.898,51.105 C89.491,51.105 82.866,63.093 82.866,81.391 C82.866,99.688 89.491,111.834 102.898,111.834 C116.306,111.834 122.931,99.688 122.931,81.391 C122.931,63.093 116.306,51.105 102.898,51.105 L102.898,51.105 Z" id="Fill-2" />
<path d='M163.468,23.659 C157.79,23.659 153.215,19.243 153.215,13.88 C153.215,8.517 157.79,4.1 163.468,4.1 C169.146,4.1 173.721,8.517 173.721,13.88 C173.721,19.243 169.146,23.659 163.468,23.659 L163.468,23.659 Z M154.793,39.118 L172.144,39.118 L172.144,124.138 L154.793,124.138 L154.793,39.118 Z' id='Fill-3' /> <path d="M163.468,23.659 C157.79,23.659 153.215,19.243 153.215,13.88 C153.215,8.517 157.79,4.1 163.468,4.1 C169.146,4.1 173.721,8.517 173.721,13.88 C173.721,19.243 169.146,23.659 163.468,23.659 L163.468,23.659 Z M154.793,39.118 L172.144,39.118 L172.144,124.138 L154.793,124.138 L154.793,39.118 Z" id="Fill-3" />
<path d='M240.443,124.137 L240.443,67.352 C240.443,57.415 234.449,51.263 222.619,51.263 C216.31,51.263 210.473,52.367 207.003,53.787 L207.003,124.137 L189.81,124.137 L189.81,43.376 C198.328,39.906 209.212,37.382 222.461,37.382 C246.28,37.382 257.794,47.793 257.794,65.775 L257.794,124.137 L240.443,124.137' id='Fill-4' /> <path d="M240.443,124.137 L240.443,67.352 C240.443,57.415 234.449,51.263 222.619,51.263 C216.31,51.263 210.473,52.367 207.003,53.787 L207.003,124.137 L189.81,124.137 L189.81,43.376 C198.328,39.906 209.212,37.382 222.461,37.382 C246.28,37.382 257.794,47.793 257.794,65.775 L257.794,124.137 L240.443,124.137" id="Fill-4" />
<path d='M303.536,125.873 C292.494,125.873 281.611,123.191 274.986,119.879 L274.986,0.314 L292.179,0.314 L292.179,41.326 C296.28,39.433 302.905,37.856 308.741,37.856 C330.667,37.856 345.494,53.629 345.494,79.656 C345.494,111.676 328.931,125.873 303.536,125.873 L303.536,125.873 Z M305.744,51.263 C301.012,51.263 295.491,52.367 292.179,54.103 L292.179,109.941 C294.703,111.045 299.593,112.149 304.482,112.149 C318.205,112.149 328.301,102.685 328.301,80.918 C328.301,62.305 319.467,51.263 305.744,51.263 L305.744,51.263 Z' id='Fill-5' /> <path d="M303.536,125.873 C292.494,125.873 281.611,123.191 274.986,119.879 L274.986,0.314 L292.179,0.314 L292.179,41.326 C296.28,39.433 302.905,37.856 308.741,37.856 C330.667,37.856 345.494,53.629 345.494,79.656 C345.494,111.676 328.931,125.873 303.536,125.873 L303.536,125.873 Z M305.744,51.263 C301.012,51.263 295.491,52.367 292.179,54.103 L292.179,109.941 C294.703,111.045 299.593,112.149 304.482,112.149 C318.205,112.149 328.301,102.685 328.301,80.918 C328.301,62.305 319.467,51.263 305.744,51.263 L305.744,51.263 Z" id="Fill-5" />
<path d='M392.341,125.873 C367.892,125.873 355.589,115.935 355.589,99.215 C355.589,75.555 380.826,71.296 406.537,69.876 L406.537,64.513 C406.537,53.787 399.439,50.001 388.555,50.001 C380.511,50.001 370.731,52.525 365.053,55.207 L360.636,43.376 C367.419,40.379 378.933,37.382 390.29,37.382 C410.638,37.382 422.942,45.269 422.942,66.248 L422.942,119.879 C416.79,123.191 404.329,125.873 392.341,125.873 L392.341,125.873 Z M406.537,81.391 C389.186,82.337 371.835,83.757 371.835,98.9 C371.835,107.89 378.776,113.411 391.868,113.411 C397.389,113.411 403.856,112.465 406.537,111.203 L406.537,81.391 L406.537,81.391 Z' id='Fill-6' /> <path d="M392.341,125.873 C367.892,125.873 355.589,115.935 355.589,99.215 C355.589,75.555 380.826,71.296 406.537,69.876 L406.537,64.513 C406.537,53.787 399.439,50.001 388.555,50.001 C380.511,50.001 370.731,52.525 365.053,55.207 L360.636,43.376 C367.419,40.379 378.933,37.382 390.29,37.382 C410.638,37.382 422.942,45.269 422.942,66.248 L422.942,119.879 C416.79,123.191 404.329,125.873 392.341,125.873 L392.341,125.873 Z M406.537,81.391 C389.186,82.337 371.835,83.757 371.835,98.9 C371.835,107.89 378.776,113.411 391.868,113.411 C397.389,113.411 403.856,112.465 406.537,111.203 L406.537,81.391 L406.537,81.391 Z" id="Fill-6" />
<path d='M461.743,125.873 C451.806,125.873 441.395,123.191 435.244,119.879 L441.08,106.629 C445.496,109.31 454.803,112.149 461.27,112.149 C470.576,112.149 476.728,107.575 476.728,100.477 C476.728,92.748 470.261,89.751 461.586,86.596 C450.228,82.337 437.452,77.132 437.452,61.201 C437.452,47.162 448.336,37.382 467.264,37.382 C477.517,37.382 486.035,39.906 492.029,43.376 L486.665,55.364 C482.88,52.998 475.309,50.317 469.157,50.317 C460.166,50.317 455.118,55.049 455.118,61.201 C455.118,68.93 461.428,71.611 469.788,74.766 C481.618,79.183 494.71,84.072 494.71,100.635 C494.71,115.935 483.038,125.873 461.743,125.873' id='Fill-7' /> <path d="M461.743,125.873 C451.806,125.873 441.395,123.191 435.244,119.879 L441.08,106.629 C445.496,109.31 454.803,112.149 461.27,112.149 C470.576,112.149 476.728,107.575 476.728,100.477 C476.728,92.748 470.261,89.751 461.586,86.596 C450.228,82.337 437.452,77.132 437.452,61.201 C437.452,47.162 448.336,37.382 467.264,37.382 C477.517,37.382 486.035,39.906 492.029,43.376 L486.665,55.364 C482.88,52.998 475.309,50.317 469.157,50.317 C460.166,50.317 455.118,55.049 455.118,61.201 C455.118,68.93 461.428,71.611 469.788,74.766 C481.618,79.183 494.71,84.072 494.71,100.635 C494.71,115.935 483.038,125.873 461.743,125.873" id="Fill-7" />
<path d='M578.625,81.233 L522.155,89.12 C523.89,104.42 533.828,112.149 548.182,112.149 C556.699,112.149 565.848,110.099 571.684,106.944 L576.732,119.879 C570.107,123.349 558.75,125.873 547.078,125.873 C520.262,125.873 505.277,108.679 505.277,81.549 C505.277,55.522 519.789,37.382 543.607,37.382 C565.69,37.382 578.782,51.894 578.782,74.766 C578.782,76.816 578.782,79.025 578.625,81.233 L578.625,81.233 Z M543.292,50.001 C530.042,50.001 521.367,60.097 521.051,77.763 L562.22,72.084 C562.062,57.257 554.649,50.001 543.292,50.001 L543.292,50.001 Z' id='Fill-8' /> <path d="M578.625,81.233 L522.155,89.12 C523.89,104.42 533.828,112.149 548.182,112.149 C556.699,112.149 565.848,110.099 571.684,106.944 L576.732,119.879 C570.107,123.349 558.75,125.873 547.078,125.873 C520.262,125.873 505.277,108.679 505.277,81.549 C505.277,55.522 519.789,37.382 543.607,37.382 C565.69,37.382 578.782,51.894 578.782,74.766 C578.782,76.816 578.782,79.025 578.625,81.233 L578.625,81.233 Z M543.292,50.001 C530.042,50.001 521.367,60.097 521.051,77.763 L562.22,72.084 C562.062,57.257 554.649,50.001 543.292,50.001 L543.292,50.001 Z" id="Fill-8" />
</g> </g>
</g> </g>
</svg> </svg>
@ -85,13 +85,13 @@ class BuyEtherScreen extends Component {
const {goToCoinbase, address} = this.props const {goToCoinbase, address} = this.props
return ( return (
<div className='buy-ether__action-content-wrapper'> <div className="buy-ether__action-content-wrapper">
<div>{this.renderCoinbaseLogo()}</div> <div>{this.renderCoinbaseLogo()}</div>
<div className='buy-ether__body-text'>Coinbase is the worlds most popular way to buy and sell bitcoin, ethereum, and litecoin.</div> <div className="buy-ether__body-text">Coinbase is the worlds most popular way to buy and sell bitcoin, ethereum, and litecoin.</div>
<a className='first-time-flow__link buy-ether__faq-link'>What is Ethereum?</a> <a className="first-time-flow__link buy-ether__faq-link">What is Ethereum?</a>
<div className='buy-ether__buttons'> <div className="buy-ether__buttons">
<button <button
className='first-time-flow__button' className="first-time-flow__button"
onClick={() => goToCoinbase(address)} onClick={() => goToCoinbase(address)}
> >
Buy Buy
@ -114,23 +114,23 @@ class BuyEtherScreen extends Component {
return this.renderCoinbaseForm() return this.renderCoinbaseForm()
case OPTION_VALUES.SHAPESHIFT: case OPTION_VALUES.SHAPESHIFT:
return ( return (
<div className='buy-ether__action-content-wrapper'> <div className="buy-ether__action-content-wrapper">
<div className='shapeshift-logo' /> <div className="shapeshift-logo" />
<div className='buy-ether__body-text'> <div className="buy-ether__body-text">
Trade any leading blockchain asset for any other. Protection by Design. No Account Needed. Trade any leading blockchain asset for any other. Protection by Design. No Account Needed.
</div> </div>
<ShapeShiftForm btnClass='first-time-flow__button' /> <ShapeShiftForm btnClass="first-time-flow__button" />
</div> </div>
) )
case OPTION_VALUES.QR_CODE: case OPTION_VALUES.QR_CODE:
return ( return (
<div className='buy-ether__action-content-wrapper'> <div className="buy-ether__action-content-wrapper">
<div dangerouslySetInnerHTML={{ __html: qrImage.createTableTag(4) }} /> <div dangerouslySetInnerHTML={{ __html: qrImage.createTableTag(4) }} />
<div className='buy-ether__body-text'>Deposit Ether directly into your account.</div> <div className="buy-ether__body-text">Deposit Ether directly into your account.</div>
<div className='buy-ether__small-body-text'>(This is the account address that MetaMask created for you to recieve funds.)</div> <div className="buy-ether__small-body-text">(This is the account address that MetaMask created for you to recieve funds.)</div>
<div className='buy-ether__buttons'> <div className="buy-ether__buttons">
<button <button
className='first-time-flow__button' className="first-time-flow__button"
onClick={this.copyToClipboard} onClick={this.copyToClipboard}
disabled={justCopied} disabled={justCopied}
> >
@ -149,19 +149,19 @@ class BuyEtherScreen extends Component {
const { selectedOption } = this.state const { selectedOption } = this.state
return ( return (
<div className='buy-ether'> <div className="buy-ether">
<Identicon address={this.props.address} diameter={70} /> <Identicon address={this.props.address} diameter={70} />
<div className='buy-ether__title'>Deposit Ether</div> <div className="buy-ether__title">Deposit Ether</div>
<div className='buy-ether__body-text'> <div className="buy-ether__body-text">
MetaMask works best if you have Ether in your account to pay for transaction gas fees and more. To get Ether, choose from one of these methods. MetaMask works best if you have Ether in your account to pay for transaction gas fees and more. To get Ether, choose from one of these methods.
</div> </div>
<div className='buy-ether__content-wrapper'> <div className="buy-ether__content-wrapper">
<div className='buy-ether__content-headline-wrapper'> <div className="buy-ether__content-headline-wrapper">
<div className='buy-ether__content-headline'>Deposit Options</div> <div className="buy-ether__content-headline">Deposit Options</div>
{this.renderSkip()} {this.renderSkip()}
</div> </div>
<div className='buy-ether__content'> <div className="buy-ether__content">
<div className='buy-ether__side-panel'> <div className="buy-ether__side-panel">
{OPTIONS.map(({ name, value }) => ( {OPTIONS.map(({ name, value }) => (
<div <div
key={value} key={value}
@ -170,16 +170,16 @@ class BuyEtherScreen extends Component {
})} })}
onClick={() => this.setState({ selectedOption: value })} onClick={() => this.setState({ selectedOption: value })}
> >
<div className='buy-ether__side-panel-item-name'>{name}</div> <div className="buy-ether__side-panel-item-name">{name}</div>
{value === selectedOption && ( {value === selectedOption && (
<svg viewBox='0 0 574 1024' id='si-ant-right' width='15px' height='15px'> <svg viewBox="0 0 574 1024" id="si-ant-right" width="15px" height="15px">
<path d='M10 9Q0 19 0 32t10 23l482 457L10 969Q0 979 0 992t10 23q10 9 24 9t24-9l506-480q10-10 10-23t-10-23L58 9Q48 0 34 0T10 9z' /> <path d="M10 9Q0 19 0 32t10 23l482 457L10 969Q0 979 0 992t10 23q10 9 24 9t24-9l506-480q10-10 10-23t-10-23L58 9Q48 0 34 0T10 9z" />
</svg> </svg>
)} )}
</div> </div>
))} ))}
</div> </div>
<div className='buy-ether__action-content'> <div className="buy-ether__action-content">
{this.renderContent()} {this.renderContent()}
</div> </div>
</div> </div>

@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Spinner from './spinner' import Spinner from './spinner'
export default function LoadingScreen({ className = '', loadingMessage }) { export default function LoadingScreen ({ className = '', loadingMessage }) {
return ( return (
<div className={`${className} loading-screen`}> <div className={`${className} loading-screen`}>
<Spinner color="#1B344D" /> <Spinner color="#1B344D" />

@ -79,11 +79,11 @@ export class ShapeShiftForm extends Component {
renderMetadata (label, value) { renderMetadata (label, value) {
return ( return (
<div className='shapeshift-form__metadata-wrapper'> <div className="shapeshift-form__metadata-wrapper">
<div className='shapeshift-form__metadata-label'> <div className="shapeshift-form__metadata-label">
{label}: {label}:
</div> </div>
<div className='shapeshift-form__metadata-value'> <div className="shapeshift-form__metadata-value">
{value} {value}
</div> </div>
</div> </div>
@ -101,7 +101,7 @@ export class ShapeShiftForm extends Component {
} = tokenExchangeRates[coinPair] || {} } = tokenExchangeRates[coinPair] || {}
return ( return (
<div className='shapeshift-form__metadata'> <div className="shapeshift-form__metadata">
{this.renderMetadata('Status', limit ? 'Available' : 'Unavailable')} {this.renderMetadata('Status', limit ? 'Available' : 'Unavailable')}
{this.renderMetadata('Limit', limit)} {this.renderMetadata('Limit', limit)}
{this.renderMetadata('Exchange Rate', rate)} {this.renderMetadata('Exchange Rate', rate)}
@ -117,13 +117,13 @@ export class ShapeShiftForm extends Component {
qrImage.make() qrImage.make()
return ( return (
<div className='shapeshift-form'> <div className="shapeshift-form">
<div className='shapeshift-form__deposit-instruction'> <div className="shapeshift-form__deposit-instruction">
Deposit your BTC to the address bellow: Deposit your BTC to the address bellow:
</div> </div>
<div className='shapeshift-form__qr-code'> <div className="shapeshift-form__qr-code">
{isLoading {isLoading
? <img src='images/loading.svg' style={{ width: '60px' }} /> ? <img src="images/loading.svg" style={{ width: '60px' }} />
: <div dangerouslySetInnerHTML={{ __html: qrImage.createTableTag(4) }} /> : <div dangerouslySetInnerHTML={{ __html: qrImage.createTableTag(4) }} />
} }
</div> </div>
@ -141,14 +141,14 @@ export class ShapeShiftForm extends Component {
return showQrCode ? this.renderQrCode() : ( return showQrCode ? this.renderQrCode() : (
<div> <div>
<div className='shapeshift-form'> <div className="shapeshift-form">
<div className='shapeshift-form__selectors'> <div className="shapeshift-form__selectors">
<div className='shapeshift-form__selector'> <div className="shapeshift-form__selector">
<div className='shapeshift-form__selector-label'> <div className="shapeshift-form__selector-label">
Deposit Deposit
</div> </div>
<select <select
className='shapeshift-form__selector-input' className="shapeshift-form__selector-input"
value={this.state.depositCoin} value={this.state.depositCoin}
onChange={this.onCoinChange} onChange={this.onCoinChange}
> >
@ -160,14 +160,14 @@ export class ShapeShiftForm extends Component {
</select> </select>
</div> </div>
<div <div
className='icon shapeshift-form__caret' className="icon shapeshift-form__caret"
style={{ backgroundImage: 'url(images/caret-right.svg)'}} style={{ backgroundImage: 'url(images/caret-right.svg)'}}
/> />
<div className='shapeshift-form__selector'> <div className="shapeshift-form__selector">
<div className='shapeshift-form__selector-label'> <div className="shapeshift-form__selector-label">
Receive Receive
</div> </div>
<div className='shapeshift-form__selector-input'> <div className="shapeshift-form__selector-input">
ETH ETH
</div> </div>
</div> </div>
@ -177,18 +177,18 @@ export class ShapeShiftForm extends Component {
'shapeshift-form__address-input-wrapper--error': errorMessage, 'shapeshift-form__address-input-wrapper--error': errorMessage,
})} })}
> >
<div className='shapeshift-form__address-input-label'> <div className="shapeshift-form__address-input-label">
Your Refund Address Your Refund Address
</div> </div>
<input <input
type='text' type="text"
className='shapeshift-form__address-input' className="shapeshift-form__address-input"
onChange={e => this.setState({ onChange={e => this.setState({
refundAddress: e.target.value, refundAddress: e.target.value,
errorMessage: '', errorMessage: '',
})} })}
/> />
<div className='shapeshift-form__address-input-error-message'> <div className="shapeshift-form__address-input-error-message">
{errorMessage} {errorMessage}
</div> </div>
</div> </div>

@ -37,7 +37,7 @@ const dbController = new DbController({
start().catch(log.error) start().catch(log.error)
async function start() { async function start () {
log.debug('MetaMask initializing...') log.debug('MetaMask initializing...')
const initState = await loadStateFromPersistence() const initState = await loadStateFromPersistence()
await setupController(initState) await setupController(initState)

@ -43,7 +43,7 @@ console.log('starting service worker')
swController.startWorker() swController.startWorker()
// Setup listener for when the service worker is read // Setup listener for when the service worker is read
function connectApp() { function connectApp () {
const connectionStream = SwStream({ const connectionStream = SwStream({
serviceWorker: swController.getWorker(), serviceWorker: swController.getWorker(),
context: name, context: name,

@ -1,6 +1,6 @@
function wait(time) { export default function wait (time) {
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
setTimeout(function() { setTimeout(function () {
resolve() resolve()
}, time * 3 || 1500) }, time * 3 || 1500)
}) })

@ -1,9 +1,9 @@
var fs = require('fs') var fs = require('fs')
var path = require('path') var path = require('path')
var browserify = require('browserify'); var browserify = require('browserify')
var tests = fs.readdirSync(path.join(__dirname, 'lib')) var tests = fs.readdirSync(path.join(__dirname, 'lib'))
var bundlePath = path.join(__dirname, 'test-bundle.js') var bundlePath = path.join(__dirname, 'test-bundle.js')
var b = browserify(); var b = browserify()
// Remove old bundle // Remove old bundle
try { try {
@ -14,9 +14,9 @@ try {
var writeStream = fs.createWriteStream(bundlePath) var writeStream = fs.createWriteStream(bundlePath)
tests.forEach(function(fileName) { tests.forEach(function (fileName) {
b.add(path.join(__dirname, 'lib', fileName)) b.add(path.join(__dirname, 'lib', fileName))
}) })
b.bundle().pipe(writeStream); b.bundle().pipe(writeStream)

@ -1,5 +1,3 @@
const Helper = require('./util/mascara-test-helper.js')
window.addEventListener('load', () => { window.addEventListener('load', () => {
window.METAMASK_SKIP_RELOAD = true window.METAMASK_SKIP_RELOAD = true
// inject app container // inject app container

@ -2,27 +2,29 @@ const EventEmitter = require('events')
const IDB = require('idb-global') const IDB = require('idb-global')
const KEY = 'metamask-test-config' const KEY = 'metamask-test-config'
module.exports = class Helper extends EventEmitter { module.exports = class Helper extends EventEmitter {
constructor () {
super()
}
tryToCleanContext () { tryToCleanContext () {
this.unregister() this.unregister()
.then(() => this.clearDb()) .then(() => this.clearDb())
.then(() => super.emit('complete')) .then(() => super.emit('complete'))
.catch((err) => super.emit('complete')) .catch((err) => {
if (err) {
super.emit('complete')
}
})
} }
unregister () { unregister () {
return global.navigator.serviceWorker.getRegistration() return global.navigator.serviceWorker.getRegistration()
.then((registration) => { .then((registration) => {
if (registration) return registration.unregister() if (registration) {
return registration.unregister()
.then((b) => b ? Promise.resolve() : Promise.reject()) .then((b) => b ? Promise.resolve() : Promise.reject())
else return Promise.resolve() } else return Promise.resolve()
}) })
} }
clearDb () { clearDb () {
return new Promise ((resolve, reject) => { return new Promise((resolve, reject) => {
const deleteRequest = global.indexDB.deleteDatabase(KEY) const deleteRequest = global.indexDB.deleteDatabase(KEY)
deleteRequest.addEventListener('success', resolve) deleteRequest.addEventListener('success', resolve)
deleteRequest.addEventListener('error', reject) deleteRequest.addEventListener('error', reject)
@ -33,7 +35,7 @@ module.exports = class Helper extends EventEmitter {
const db = new IDB({ const db = new IDB({
version: 2, version: 2,
key: KEY, key: KEY,
initialState: state initialState: state,
}) })
return db.open() return db.open()
} }

@ -1,5 +1,6 @@
// fs.readFileSync is inlined by browserify transform "brfs" // fs.readFileSync is inlined by browserify transform "brfs"
const fs = require('fs') const fs = require('fs')
const path = require('path')
module.exports = [ module.exports = [
{ {
@ -7,14 +8,14 @@ module.exports = [
read: false, read: false,
date: 'Thu Feb 09 2017', date: 'Thu Feb 09 2017',
title: 'Terms of Use', title: 'Terms of Use',
body: fs.readFileSync(__dirname + '/archive/notice_0.md', 'utf8'), body: fs.readFileSync(path.join(__dirname, '/archive', 'notice_0.md'), 'utf8'),
}, },
{ {
id: 2, id: 2,
read: false, read: false,
date: 'Mon May 08 2017', date: 'Mon May 08 2017',
title: 'Privacy Notice', title: 'Privacy Notice',
body: fs.readFileSync(__dirname + '/archive/notice_2.md', 'utf8'), body: fs.readFileSync(path.join(__dirname, '/archive', 'notice_2.md'), 'utf8'),
}, },
{ {
id: 3, id: 3,
@ -22,13 +23,13 @@ module.exports = [
date: 'Tue Nov 28 2017', date: 'Tue Nov 28 2017',
title: 'Seed Phrase Alert', title: 'Seed Phrase Alert',
firstVersion: '<=3.12.0', firstVersion: '<=3.12.0',
body: fs.readFileSync(__dirname + '/archive/notice_3.md', 'utf8'), body: fs.readFileSync(path.join(__dirname, '/archive', 'notice_3.md'), 'utf8'),
}, },
{ {
id: 4, id: 4,
read: false, read: false,
date: 'Wed Jun 13 2018', date: 'Wed Jun 13 2018',
title: 'Phishing Warning', title: 'Phishing Warning',
body: fs.readFileSync(__dirname + '/archive/notice_4.md', 'utf8'), body: fs.readFileSync(path.join(__dirname, '/archive', 'notice_4.md'), 'utf8'),
} },
] ]

@ -20,7 +20,7 @@ function EnsInput () {
EnsInput.prototype.render = function () { EnsInput.prototype.render = function () {
const props = this.props const props = this.props
function onInputChange() { function onInputChange () {
const network = this.props.network const network = this.props.network
const networkHasEnsSupport = getNetworkEnsSupport(network) const networkHasEnsSupport = getNetworkEnsSupport(network)
if (!networkHasEnsSupport) return if (!networkHasEnsSupport) return

@ -28,7 +28,7 @@ LoadingIndicator.prototype.render = function () {
background: 'rgba(255, 255, 255, 0.8)', background: 'rgba(255, 255, 255, 0.8)',
}, },
}, [ }, [
canBypass ? h( 'i.fa.fa-close.cursor-pointer.close-loading', { canBypass ? h('i.fa.fa-close.cursor-pointer.close-loading', {
style: { style: {
position: 'absolute', position: 'absolute',
top: '1px', top: '1px',

@ -40,8 +40,8 @@ TransactionListItem.prototype.showRetryButton = function () {
const currentNonceTxs = transactions.filter(tx => tx.txParams.nonce === currentNonce) const currentNonceTxs = transactions.filter(tx => tx.txParams.nonce === currentNonce)
const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted') const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted')
const lastSubmittedTxWithCurrentNonce = currentNonceSubmittedTxs[0] const lastSubmittedTxWithCurrentNonce = currentNonceSubmittedTxs[0]
const currentTxIsLatestWithNonce = lastSubmittedTxWithCurrentNonce const currentTxIsLatestWithNonce = lastSubmittedTxWithCurrentNonce &&
&& lastSubmittedTxWithCurrentNonce.id === transaction.id lastSubmittedTxWithCurrentNonce.id === transaction.id
return currentTxIsLatestWithNonce && Date.now() - submittedTime > 30000 return currentTxIsLatestWithNonce && Date.now() - submittedTime > 30000
} }

@ -31,7 +31,7 @@ ConfigScreen.prototype.render = function () {
return ( return (
h('.flex-column.flex-grow', { h('.flex-column.flex-grow', {
style:{ style: {
maxHeight: '585px', maxHeight: '585px',
overflowY: 'auto', overflowY: 'auto',
}, },

42
package-lock.json generated

@ -8940,20 +8940,6 @@
} }
} }
}, },
"ethereumjs-util": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz",
"integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==",
"requires": {
"bn.js": "^4.11.0",
"create-hash": "^1.1.2",
"ethjs-util": "^0.1.3",
"keccak": "^1.0.2",
"rlp": "^2.0.0",
"safe-buffer": "^5.1.1",
"secp256k1": "^3.0.1"
}
},
"ethereumjs-vm": { "ethereumjs-vm": {
"version": "2.3.4", "version": "2.3.4",
"resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.3.4.tgz", "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.3.4.tgz",
@ -16976,6 +16962,7 @@
"version": "2.4.0", "version": "2.4.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
"dev": true,
"requires": { "requires": {
"graceful-fs": "^4.1.6" "graceful-fs": "^4.1.6"
} }
@ -17771,6 +17758,7 @@
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
"integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=",
"dev": true,
"requires": { "requires": {
"graceful-fs": "^4.1.9" "graceful-fs": "^4.1.9"
} }
@ -28439,25 +28427,12 @@
"resolved": "https://registry.npmjs.org/solc/-/solc-0.4.24.tgz", "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.24.tgz",
"integrity": "sha512-2xd7Cf1HeVwrIb6Bu1cwY2/TaLRodrppCq3l7rhLimFQgmxptXhTC3+/wesVLpB09F1A2kZgvbMOgH7wvhFnBQ==", "integrity": "sha512-2xd7Cf1HeVwrIb6Bu1cwY2/TaLRodrppCq3l7rhLimFQgmxptXhTC3+/wesVLpB09F1A2kZgvbMOgH7wvhFnBQ==",
"requires": { "requires": {
"fs-extra": "^0.30.0",
"memorystream": "^0.3.1", "memorystream": "^0.3.1",
"require-from-string": "^1.1.0", "require-from-string": "^1.1.0",
"semver": "^5.3.0", "semver": "^5.3.0",
"yargs": "^4.7.1" "yargs": "^4.7.1"
}, },
"dependencies": { "dependencies": {
"fs-extra": {
"version": "0.30.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
"integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=",
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^2.1.0",
"klaw": "^1.0.0",
"path-is-absolute": "^1.0.0",
"rimraf": "^2.2.8"
}
},
"yargs": { "yargs": {
"version": "4.8.1", "version": "4.8.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz",
@ -29740,7 +29715,6 @@
"connect-query": "^1.0.0", "connect-query": "^1.0.0",
"destroy": "^1.0.4", "destroy": "^1.0.4",
"fast-url-parser": "^1.1.3", "fast-url-parser": "^1.1.3",
"fs-extra": "^0.30.0",
"glob": "^7.1.2", "glob": "^7.1.2",
"glob-slasher": "^1.0.1", "glob-slasher": "^1.0.1",
"home-dir": "^1.0.0", "home-dir": "^1.0.0",
@ -29766,18 +29740,6 @@
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
}, },
"fs-extra": {
"version": "0.30.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
"integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=",
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^2.1.0",
"klaw": "^1.0.0",
"path-is-absolute": "^1.0.0",
"rimraf": "^2.2.8"
}
},
"isarray": { "isarray": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",

@ -38,8 +38,8 @@
"test:mascara:build:tests": "browserify test/integration/lib/first-time.js -o dist/mascara/tests.js", "test:mascara:build:tests": "browserify test/integration/lib/first-time.js -o dist/mascara/tests.js",
"ganache:start": "ganache-cli -m 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'", "ganache:start": "ganache-cli -m 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'",
"sentry:publish": "node ./development/sentry-publish.js", "sentry:publish": "node ./development/sentry-publish.js",
"lint": "gulp lint", "lint": "eslint .",
"lint:fix": "gulp lint:fix", "lint:fix": "eslint . --fix",
"ui": "npm run test:flat:build:states && beefy development/ui-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./", "ui": "npm run test:flat:build:states && beefy development/ui-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
"mock": "beefy development/mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./", "mock": "beefy development/mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
"watch": "mocha watch --recursive \"test/unit/**/*.js\"", "watch": "mocha watch --recursive \"test/unit/**/*.js\"",
@ -94,7 +94,6 @@
"eslint-plugin-react": "^7.4.0", "eslint-plugin-react": "^7.4.0",
"eth-bin-to-ops": "^1.0.1", "eth-bin-to-ops": "^1.0.1",
"eth-block-tracker": "^4.0.1", "eth-block-tracker": "^4.0.1",
"eth-contract-metadata": "^1.1.5",
"eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master", "eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master",
"eth-hd-keyring": "^1.2.1", "eth-hd-keyring": "^1.2.1",
"eth-json-rpc-filters": "^2.1.1", "eth-json-rpc-filters": "^2.1.1",
@ -242,7 +241,6 @@
"gifencoder": "^1.1.0", "gifencoder": "^1.1.0",
"gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed", "gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed",
"gulp-babel": "^7.0.0", "gulp-babel": "^7.0.0",
"gulp-eslint": "^4.0.0",
"gulp-json-editor": "^2.2.1", "gulp-json-editor": "^2.2.1",
"gulp-livereload": "^3.8.1", "gulp-livereload": "^3.8.1",
"gulp-multi-process": "^1.3.1", "gulp-multi-process": "^1.3.1",

@ -1,7 +1,7 @@
// Karma configuration // Karma configuration
// Generated on Mon Sep 11 2017 18:45:48 GMT-0700 (PDT) // Generated on Mon Sep 11 2017 18:45:48 GMT-0700 (PDT)
module.exports = function(config) { module.exports = function (config) {
return { return {
// base path that will be used to resolve all patterns (eg. files, exclude) // base path that will be used to resolve all patterns (eg. files, exclude)
basePath: process.cwd(), basePath: process.cwd(),

@ -28,22 +28,25 @@ The `piggybankContract` is compiled from:
} }
*/ */
var piggybankContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"withdrawAmount","type":"uint256"}],"name":"withdraw","outputs":[{"name":"remainingBal","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]); var piggybankContract = web3.eth.contract([{'constant': false, 'inputs': [{'name': 'withdrawAmount', 'type': 'uint256'}], 'name': 'withdraw', 'outputs': [{'name': 'remainingBal', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'owner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [], 'name': 'deposit', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}])
const deployButton = document.getElementById('deployButton')
const depositButton = document.getElementById('depositButton')
const withdrawButton = document.getElementById('withdrawButton')
deployButton.addEventListener('click', function (event) { deployButton.addEventListener('click', function (event) {
var piggybank = piggybankContract.new( piggybankContract.new(
{ {
from: web3.eth.accounts[0], from: web3.eth.accounts[0],
data: '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029', data: '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029',
gas: '4700000' gas: '4700000',
}, function (e, contract){ }, function (e, contract) {
console.log(e, contract); console.log(e, contract)
console.log('deployed!', contract); console.log('deployed!', contract)
if (typeof contract.address !== 'undefined') { if (typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash); console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash)
console.log(`contract`, contract); console.log(`contract`, contract)
depositButton.addEventListener('click', function (event) { depositButton.addEventListener('click', function (event) {
console.log('contract.deposit', { from: web3.eth.accounts[0], value: '0x29a2241af62c0000' }) console.log('contract.deposit', { from: web3.eth.accounts[0], value: '0x29a2241af62c0000' })

@ -19,7 +19,6 @@ describe('Using MetaMask with an existing account', function () {
const browser = process.env.SELENIUM_BROWSER const browser = process.env.SELENIUM_BROWSER
let driver let driver
let extensionUri let extensionUri
let tokenAddress
const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent' const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'
const testAddress = '0xE18035BF8712672935FDB4e5e431b1a0183d2DFC' const testAddress = '0xE18035BF8712672935FDB4e5e431b1a0183d2DFC'
@ -73,15 +72,16 @@ describe('Using MetaMask with an existing account', function () {
await delay(regularDelayMs) await delay(regularDelayMs)
// Close all other tabs // Close all other tabs
let [oldUi, infoPage, newUi] = await driver.getAllWindowHandles() const [oldUi, infoPage, newUi] = await driver.getAllWindowHandles()
newUi = newUi || infoPage
const newUiOrInfoPage = newUi || infoPage
await driver.switchTo().window(oldUi) await driver.switchTo().window(oldUi)
await driver.close() await driver.close()
if (infoPage !== newUi) { if (infoPage !== newUiOrInfoPage) {
await driver.switchTo().window(infoPage) await driver.switchTo().window(infoPage)
await driver.close() await driver.close()
} }
await driver.switchTo().window(newUi) await driver.switchTo().window(newUiOrInfoPage)
await delay(regularDelayMs) await delay(regularDelayMs)
const continueBtn = await findElement(driver, By.css('.welcome-screen__button')) const continueBtn = await findElement(driver, By.css('.welcome-screen__button'))
@ -325,11 +325,16 @@ describe('Using MetaMask with an existing account', function () {
}) })
describe('Add a custom token from TokenFactory', () => { describe('Add a custom token from TokenFactory', () => {
let extension, tokenFactory
it('creates a new token', async () => { it('creates a new token', async () => {
await driver.executeScript('window.open("https://tokenfactory.surge.sh/#/factory")') await driver.executeScript('window.open("https://tokenfactory.surge.sh/#/factory")')
await delay(waitingNewPageDelayMs) await delay(waitingNewPageDelayMs)
const [extension, tokenFactory] = await driver.getAllWindowHandles() const windowHandles = await driver.getAllWindowHandles()
extension = windowHandles[0]
tokenFactory = windowHandles[1]
await driver.switchTo().window(tokenFactory) await driver.switchTo().window(tokenFactory)
const [ const [
totalSupply, totalSupply,
@ -350,6 +355,7 @@ describe('Using MetaMask with an existing account', function () {
await driver.switchTo().window(extension) await driver.switchTo().window(extension)
await driver.get(extensionUri) await driver.get(extensionUri)
await delay(regularDelayMs) await delay(regularDelayMs)
})
it('enter private key', async () => { it('enter private key', async () => {
const privateKeyInput = await findElement(driver, By.css('#private-key-box')) const privateKeyInput = await findElement(driver, By.css('#private-key-box'))
@ -359,7 +365,7 @@ describe('Using MetaMask with an existing account', function () {
await driver.switchTo().window(tokenFactory) await driver.switchTo().window(tokenFactory)
await delay(regularDelayMs) await delay(regularDelayMs)
const tokenContactAddress = await driver.findElement(By.css('div > div > div:nth-child(2) > span:nth-child(3)')) const tokenContactAddress = await driver.findElement(By.css('div > div > div:nth-child(2) > span:nth-child(3)'))
tokenAddress = await tokenContactAddress.getText() await tokenContactAddress.getText()
await driver.close() await driver.close()
await driver.switchTo().window(extension) await driver.switchTo().window(extension)
await driver.get(extensionUri) await driver.get(extensionUri)

@ -25,7 +25,6 @@ describe('MetaMask', function () {
const tinyDelayMs = 1000 const tinyDelayMs = 1000
const regularDelayMs = tinyDelayMs * 2 const regularDelayMs = tinyDelayMs * 2
const largeDelayMs = regularDelayMs * 2 const largeDelayMs = regularDelayMs * 2
const waitingNewPageDelayMs = regularDelayMs * 30
this.timeout(0) this.timeout(0)
this.bail(true) this.bail(true)
@ -88,7 +87,7 @@ describe('MetaMask', function () {
await delay(regularDelayMs) await delay(regularDelayMs)
// Close all other tabs // Close all other tabs
let [oldUi, tab1, tab2] = await driver.getAllWindowHandles() const [oldUi, tab1, tab2] = await driver.getAllWindowHandles()
await driver.switchTo().window(oldUi) await driver.switchTo().window(oldUi)
await driver.close() await driver.close()
@ -269,7 +268,7 @@ describe('MetaMask', function () {
await driver.findElement(By.css('.qr-wrapper')).isDisplayed() await driver.findElement(By.css('.qr-wrapper')).isDisplayed()
await delay(regularDelayMs) await delay(regularDelayMs)
let accountModal = await driver.findElement(By.css('span .modal')) const accountModal = await driver.findElement(By.css('span .modal'))
await driver.executeScript("document.querySelector('.account-modal-close').click()") await driver.executeScript("document.querySelector('.account-modal-close').click()")
@ -487,7 +486,7 @@ describe('MetaMask', function () {
await configureGas.click() await configureGas.click()
await delay(regularDelayMs) await delay(regularDelayMs)
let gasModal = await driver.findElement(By.css('span .modal')) const gasModal = await driver.findElement(By.css('span .modal'))
await driver.wait(until.elementLocated(By.css('.send-v2__customize-gas__title'))) await driver.wait(until.elementLocated(By.css('.send-v2__customize-gas__title')))
const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.customize-gas-input')) const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.customize-gas-input'))
@ -700,7 +699,7 @@ describe('MetaMask', function () {
it('sends an already created token', async () => { it('sends an already created token', async () => {
openNewPage(driver, `https://tokenfactory.surge.sh/#/token/${tokenAddress}`) openNewPage(driver, `https://tokenfactory.surge.sh/#/token/${tokenAddress}`)
const [extension, tokenFactory] = await driver.getAllWindowHandles() const [extension] = await driver.getAllWindowHandles()
const [ const [
transferToAddress, transferToAddress,

@ -37,7 +37,7 @@ async function createModifiedTestBuild ({ browser, srcPath }) {
} }
async function setupBrowserAndExtension ({ browser, extPath }) { async function setupBrowserAndExtension ({ browser, extPath }) {
let drive, extensionId, extensionUri let driver, extensionId, extensionUri
if (browser === 'chrome') { if (browser === 'chrome') {
driver = buildChromeWebDriver(extPath) driver = buildChromeWebDriver(extPath)

@ -1,8 +1,5 @@
const fs = require('fs-extra')
const mkdirp = require('mkdirp')
const path = require('path') const path = require('path')
const assert = require('assert') const assert = require('assert')
const pify = require('pify')
const { By, Key, until } = require('selenium-webdriver') const { By, Key, until } = require('selenium-webdriver')
const { delay, createModifiedTestBuild, setupBrowserAndExtension, verboseReportOnFailure } = require('./func') const { delay, createModifiedTestBuild, setupBrowserAndExtension, verboseReportOnFailure } = require('./func')
@ -315,7 +312,7 @@ describe('Metamask popup page', function () {
}) })
}) })
async function checkBrowserForConsoleErrors() { async function checkBrowserForConsoleErrors () {
const ignoredLogTypes = ['WARNING'] const ignoredLogTypes = ['WARNING']
const ignoredErrorMessages = [ const ignoredErrorMessages = [
// React throws error warnings on "dataset", but still sets the data-* properties correctly // React throws error warnings on "dataset", but still sets the data-* properties correctly

@ -1,6 +1,6 @@
const getBaseConfig = require('./base.conf.js') const getBaseConfig = require('./base.conf.js')
module.exports = function(config) { module.exports = function (config) {
const settings = getBaseConfig(config) const settings = getBaseConfig(config)
settings.files.push('development/bundle.js') settings.files.push('development/bundle.js')
settings.files.push('test/integration/bundle.js') settings.files.push('test/integration/bundle.js')

@ -75,7 +75,7 @@ async function runAddTokenFlowTest (assert, done) {
tokenWrapper[0].click() tokenWrapper[0].click()
// Click Next button // Click Next button
let nextButton = await queryAsync($, 'button.btn-primary.btn--large') const nextButton = await queryAsync($, 'button.btn-primary.btn--large')
assert.equal(nextButton[0].textContent, 'Next', 'next button rendered') assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
nextButton[0].click() nextButton[0].click()

@ -1,10 +1,7 @@
const reactTriggerChange = require('react-trigger-change') const reactTriggerChange = require('react-trigger-change')
const { const {
timeout,
queryAsync, queryAsync,
findAsync,
} = require('../../lib/util') } = require('../../lib/util')
const PASSWORD = 'password123'
QUnit.module('confirm sig requests') QUnit.module('confirm sig requests')
@ -16,8 +13,8 @@ QUnit.test('successful confirmation of sig requests', (assert) => {
}) })
}) })
async function runConfirmSigRequestsTest(assert, done) { async function runConfirmSigRequestsTest (assert, done) {
let selectState = await queryAsync($, 'select') const selectState = await queryAsync($, 'select')
selectState.val('confirm sig requests') selectState.val('confirm sig requests')
reactTriggerChange(selectState[0]) reactTriggerChange(selectState[0])
@ -32,7 +29,7 @@ async function runConfirmSigRequestsTest(assert, done) {
let confirmSigHeadline = await queryAsync($, '.request-signature__headline') let confirmSigHeadline = await queryAsync($, '.request-signature__headline')
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested') assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
let confirmSigMessage = await queryAsync($, '.request-signature__notice') const confirmSigMessage = await queryAsync($, '.request-signature__notice')
assert.ok(confirmSigMessage[0].textContent.match(/^Signing\sthis\smessage/)) assert.ok(confirmSigMessage[0].textContent.match(/^Signing\sthis\smessage/))
let confirmSigRowValue = await queryAsync($, '.request-signature__row-value') let confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
@ -45,7 +42,7 @@ async function runConfirmSigRequestsTest(assert, done) {
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested') assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
confirmSigRowValue = await queryAsync($, '.request-signature__row-value') confirmSigRowValue = await queryAsync($, '.request-signature__row-value')
assert.ok(confirmSigRowValue[0].textContent.match(/^\#\sTerms\sof\sUse/)) assert.ok(confirmSigRowValue[0].textContent.match(/^#\sTerms\sof\sUse/))
confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large') confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large')
confirmSigSignButton[0].click() confirmSigSignButton[0].click()

@ -15,7 +15,7 @@ QUnit.test('renders localized currency', (assert) => {
}) })
}) })
async function runCurrencyLocalizationTest(assert, done) { async function runCurrencyLocalizationTest (assert, done) {
console.log('*** start runCurrencyLocalizationTest') console.log('*** start runCurrencyLocalizationTest')
const selectState = await queryAsync($, 'select') const selectState = await queryAsync($, 'select')
selectState.val('currency localization') selectState.val('currency localization')

@ -42,7 +42,7 @@ async function runFirstTimeUsageTest (assert, done) {
assert.equal(created.textContent, 'Your unique account image', 'unique image screen') assert.equal(created.textContent, 'Your unique account image', 'unique image screen')
// Agree button // Agree button
let button = (await findAsync(app, 'button'))[0] const button = (await findAsync(app, 'button'))[0]
assert.ok(button, 'button present') assert.ok(button, 'button present')
button.click() button.click()

@ -5,8 +5,6 @@ const {
findAsync, findAsync,
} = require('../../lib/util') } = require('../../lib/util')
const PASSWORD = 'password123'
QUnit.module('new ui send flow') QUnit.module('new ui send flow')
QUnit.test('successful send flow', (assert) => { QUnit.test('successful send flow', (assert) => {
@ -54,7 +52,7 @@ async function customizeGas (assert, price, limit, ethFee, usdFee) {
) )
} }
async function runSendFlowTest(assert, done) { async function runSendFlowTest (assert, done) {
console.log('*** start runSendFlowTest') console.log('*** start runSendFlowTest')
const selectState = await queryAsync($, 'select') const selectState = await queryAsync($, 'select')
selectState.val('send new ui') selectState.val('send new ui')
@ -87,7 +85,7 @@ async function runSendFlowTest(assert, done) {
sendFromFieldItemAddress = await queryAsync($, '.account-list-item__account-name') sendFromFieldItemAddress = await queryAsync($, '.account-list-item__account-name')
assert.equal(sendFromFieldItemAddress[0].textContent, 'Send Account 2', 'send from field dropdown changes account name') assert.equal(sendFromFieldItemAddress[0].textContent, 'Send Account 2', 'send from field dropdown changes account name')
let sendToFieldInput = await queryAsync($, '.send-v2__to-autocomplete__input') const sendToFieldInput = await queryAsync($, '.send-v2__to-autocomplete__input')
sendToFieldInput[0].focus() sendToFieldInput[0].focus()
const sendToDropdownList = await queryAsync($, '.send-v2__from-dropdown__list') const sendToDropdownList = await queryAsync($, '.send-v2__from-dropdown__list')

@ -1,6 +1,5 @@
const reactTriggerChange = require('../../lib/react-trigger-change') const reactTriggerChange = require('../../lib/react-trigger-change')
const { const {
timeout,
queryAsync, queryAsync,
findAsync, findAsync,
} = require('../../lib/util') } = require('../../lib/util')
@ -15,7 +14,7 @@ QUnit.test('renders list items successfully', (assert) => {
}) })
}) })
async function runTxListItemsTest(assert, done) { async function runTxListItemsTest (assert, done) {
console.log('*** start runTxListItemsTest') console.log('*** start runTxListItemsTest')
const selectState = await queryAsync($, 'select') const selectState = await queryAsync($, 'select')
selectState.val('tx list items') selectState.val('tx list items')

@ -2,7 +2,7 @@ const txStateHistoryHelper = require('../../app/scripts/controllers/transactions
module.exports = createTxMeta module.exports = createTxMeta
function createTxMeta(partialMeta) { function createTxMeta (partialMeta) {
const txMeta = Object.assign({ const txMeta = Object.assign({
status: 'unapproved', status: 'unapproved',
txParams: {}, txParams: {},

@ -31,6 +31,6 @@ module.exports = {
getRandomValues () { getRandomValues () {
return 'SOO RANDO!!!1' return 'SOO RANDO!!!1'
} },
} }

@ -17,14 +17,14 @@ class TxGenerator {
} }
generate (tx = {}, opts = {}) { generate (tx = {}, opts = {}) {
let { count, fromNonce } = opts const { count, fromNonce } = opts
let nonce = fromNonce || this.txs.length let nonce = fromNonce || this.txs.length
let txs = [] const txs = []
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
txs.push(extend(template, { txs.push(extend(template, {
txParams: { txParams: {
nonce: hexify(nonce++), nonce: hexify(nonce++),
} },
}, tx)) }, tx))
} }
this.txs = this.txs.concat(txs) this.txs = this.txs.concat(txs)

@ -1,7 +1,7 @@
// Trigger React's synthetic change events on input, textarea and select elements // Trigger React's synthetic change events on input, textarea and select elements
// https://github.com/vitalyq/react-trigger-change // https://github.com/vitalyq/react-trigger-change
/******************IMPORTANT NOTE******************/ /** ****************IMPORTANT NOTE******************/
/* This file is a modification of the */ /* This file is a modification of the */
/* 'react-trigger-change' library linked above. */ /* 'react-trigger-change' library linked above. */
/* That library breaks when 'onFocus' events are */ /* That library breaks when 'onFocus' events are */
@ -11,13 +11,13 @@
/* This modification removes the accomodations */ /* This modification removes the accomodations */
/* 'react-trigger-change' makes for IE to ensure */ /* 'react-trigger-change' makes for IE to ensure */
/* our tests can pass in chrome and firefox. */ /* our tests can pass in chrome and firefox. */
/**************************************************/ /** ************************************************/
'use strict'; 'use strict'
// Constants and functions are declared inside the closure. // Constants and functions are declared inside the closure.
// In this way, reactTriggerChange can be passed directly to executeScript in Selenium. // In this way, reactTriggerChange can be passed directly to executeScript in Selenium.
module.exports = function reactTriggerChange(node) { module.exports = function reactTriggerChange (node) {
var supportedInputTypes = { var supportedInputTypes = {
color: true, color: true,
date: true, date: true,
@ -33,47 +33,47 @@ module.exports = function reactTriggerChange(node) {
text: true, text: true,
time: true, time: true,
url: true, url: true,
week: true week: true,
}; }
var nodeName = node.nodeName.toLowerCase(); var nodeName = node.nodeName.toLowerCase()
var type = node.type; var type = node.type
var event; var event
var descriptor; var descriptor
var initialValue; var initialValue
var initialChecked; var initialChecked
var initialCheckedRadio; var initialCheckedRadio
// Do not try to delete non-configurable properties. // Do not try to delete non-configurable properties.
// Value and checked properties on DOM elements are non-configurable in PhantomJS. // Value and checked properties on DOM elements are non-configurable in PhantomJS.
function deletePropertySafe(elem, prop) { function deletePropertySafe (elem, prop) {
var desc = Object.getOwnPropertyDescriptor(elem, prop); var desc = Object.getOwnPropertyDescriptor(elem, prop)
if (desc && desc.configurable) { if (desc && desc.configurable) {
delete elem[prop]; delete elem[prop]
} }
} }
function getCheckedRadio(radio) { function getCheckedRadio (radio) {
var name = radio.name; var name = radio.name
var radios; var radios
var i; var i
if (name) { if (name) {
radios = document.querySelectorAll('input[type="radio"][name="' + name + '"]'); radios = document.querySelectorAll('input[type="radio"][name="' + name + '"]')
for (i = 0; i < radios.length; i += 1) { for (i = 0; i < radios.length; i += 1) {
if (radios[i].checked) { if (radios[i].checked) {
return radios[i] !== radio ? radios[i] : null; return radios[i] !== radio ? radios[i] : null
} }
} }
} }
return null; return null
} }
function preventChecking(e) { function preventChecking (e) {
e.preventDefault(); e.preventDefault()
if (!initialChecked) { if (!initialChecked) {
e.target.checked = false; e.target.checked = false
} }
if (initialCheckedRadio) { if (initialCheckedRadio) {
initialCheckedRadio.checked = true; initialCheckedRadio.checked = true
} }
} }
@ -81,81 +81,81 @@ module.exports = function reactTriggerChange(node) {
(nodeName === 'input' && type === 'file')) { (nodeName === 'input' && type === 'file')) {
// IE9-IE11, non-IE // IE9-IE11, non-IE
// Dispatch change. // Dispatch change.
event = document.createEvent('HTMLEvents'); event = document.createEvent('HTMLEvents')
event.initEvent('change', true, false); event.initEvent('change', true, false)
node.dispatchEvent(event); node.dispatchEvent(event)
} else if ((nodeName === 'input' && supportedInputTypes[type]) || } else if ((nodeName === 'input' && supportedInputTypes[type]) ||
nodeName === 'textarea') { nodeName === 'textarea') {
// React 16 // React 16
// Cache artificial value property descriptor. // Cache artificial value property descriptor.
// Property doesn't exist in React <16, descriptor is undefined. // Property doesn't exist in React <16, descriptor is undefined.
descriptor = Object.getOwnPropertyDescriptor(node, 'value'); descriptor = Object.getOwnPropertyDescriptor(node, 'value')
// Update inputValueTracking cached value. // Update inputValueTracking cached value.
// Remove artificial value property. // Remove artificial value property.
// Restore initial value to trigger event with it. // Restore initial value to trigger event with it.
initialValue = node.value; initialValue = node.value
node.value = initialValue + '#'; node.value = initialValue + '#'
deletePropertySafe(node, 'value'); deletePropertySafe(node, 'value')
node.value = initialValue; node.value = initialValue
// React 0.14: IE10-IE11, non-IE // React 0.14: IE10-IE11, non-IE
// React 15: non-IE // React 15: non-IE
// React 16: IE10-IE11, non-IE // React 16: IE10-IE11, non-IE
event = document.createEvent('HTMLEvents'); event = document.createEvent('HTMLEvents')
event.initEvent('input', true, false); event.initEvent('input', true, false)
node.dispatchEvent(event); node.dispatchEvent(event)
// React 16 // React 16
// Restore artificial value property descriptor. // Restore artificial value property descriptor.
if (descriptor) { if (descriptor) {
Object.defineProperty(node, 'value', descriptor); Object.defineProperty(node, 'value', descriptor)
} }
} else if (nodeName === 'input' && type === 'checkbox') { } else if (nodeName === 'input' && type === 'checkbox') {
// Invert inputValueTracking cached value. // Invert inputValueTracking cached value.
node.checked = !node.checked; node.checked = !node.checked
// Dispatch click. // Dispatch click.
// Click event inverts checked value. // Click event inverts checked value.
event = document.createEvent('MouseEvents'); event = document.createEvent('MouseEvents')
event.initEvent('click', true, true); event.initEvent('click', true, true)
node.dispatchEvent(event); node.dispatchEvent(event)
} else if (nodeName === 'input' && type === 'radio') { } else if (nodeName === 'input' && type === 'radio') {
// Cache initial checked value. // Cache initial checked value.
initialChecked = node.checked; initialChecked = node.checked
// Find and cache initially checked radio in the group. // Find and cache initially checked radio in the group.
initialCheckedRadio = getCheckedRadio(node); initialCheckedRadio = getCheckedRadio(node)
// React 16 // React 16
// Cache property descriptor. // Cache property descriptor.
// Invert inputValueTracking cached value. // Invert inputValueTracking cached value.
// Remove artificial checked property. // Remove artificial checked property.
// Restore initial value, otherwise preventDefault will eventually revert the value. // Restore initial value, otherwise preventDefault will eventually revert the value.
descriptor = Object.getOwnPropertyDescriptor(node, 'checked'); descriptor = Object.getOwnPropertyDescriptor(node, 'checked')
node.checked = !initialChecked; node.checked = !initialChecked
deletePropertySafe(node, 'checked'); deletePropertySafe(node, 'checked')
node.checked = initialChecked; node.checked = initialChecked
// Prevent toggling during event capturing phase. // Prevent toggling during event capturing phase.
// Set checked value to false if initialChecked is false, // Set checked value to false if initialChecked is false,
// otherwise next listeners will see true. // otherwise next listeners will see true.
// Restore initially checked radio in the group. // Restore initially checked radio in the group.
node.addEventListener('click', preventChecking, true); node.addEventListener('click', preventChecking, true)
// Dispatch click. // Dispatch click.
// Click event inverts checked value. // Click event inverts checked value.
event = document.createEvent('MouseEvents'); event = document.createEvent('MouseEvents')
event.initEvent('click', true, true); event.initEvent('click', true, true)
node.dispatchEvent(event); node.dispatchEvent(event)
// Remove listener to stop further change prevention. // Remove listener to stop further change prevention.
node.removeEventListener('click', preventChecking, true); node.removeEventListener('click', preventChecking, true)
// React 16 // React 16
// Restore artificial checked property descriptor. // Restore artificial checked property descriptor.
if (descriptor) { if (descriptor) {
Object.defineProperty(node, 'checked', descriptor); Object.defineProperty(node, 'checked', descriptor)
} }
} }
}; }

@ -11,7 +11,7 @@ function timeout (time) {
}) })
} }
async function findAsync(container, selector, opts) { async function findAsync (container, selector, opts) {
try { try {
return await pollUntilTruthy(() => { return await pollUntilTruthy(() => {
const result = container.find(selector) const result = container.find(selector)
@ -22,7 +22,7 @@ async function findAsync(container, selector, opts) {
} }
} }
async function queryAsync(jQuery, selector, opts) { async function queryAsync (jQuery, selector, opts) {
try { try {
return await pollUntilTruthy(() => { return await pollUntilTruthy(() => {
const result = jQuery(selector) const result = jQuery(selector)
@ -33,7 +33,7 @@ async function queryAsync(jQuery, selector, opts) {
} }
} }
async function pollUntilTruthy(fn, opts = {}){ async function pollUntilTruthy (fn, opts = {}) {
const pollingInterval = opts.pollingInterval || 100 const pollingInterval = opts.pollingInterval || 100
const timeoutInterval = opts.timeoutInterval || 5000 const timeoutInterval = opts.timeoutInterval || 5000
const start = Date.now() const start = Date.now()

@ -1,13 +1,13 @@
const getBaseConfig = require('./base.conf.js') const getBaseConfig = require('./base.conf.js')
module.exports = function(config) { module.exports = function (config) {
const settings = getBaseConfig(config) const settings = getBaseConfig(config)
// ui and tests // ui and tests
settings.files.push('dist/mascara/ui.js') settings.files.push('dist/mascara/ui.js')
settings.files.push('dist/mascara/tests.js') settings.files.push('dist/mascara/tests.js')
// service worker background // service worker background
settings.files.push({ pattern: 'dist/mascara/background.js', watched: false, included: false, served: true }), settings.files.push({ pattern: 'dist/mascara/background.js', watched: false, included: false, served: true })
settings.proxies['/background.js'] = '/base/dist/mascara/background.js' settings.proxies['/background.js'] = '/base/dist/mascara/background.js'
// use this to keep the browser open for debugging // use this to keep the browser open for debugging

@ -12,7 +12,7 @@ const pngFileStream = require('png-file-stream')
const sizeOfPng = require('image-size/lib/types/png') const sizeOfPng = require('image-size/lib/types/png')
const By = webdriver.By const By = webdriver.By
const localesIndex = require('../../app/_locales/index.json') const localesIndex = require('../../app/_locales/index.json')
const { delay, buildChromeWebDriver, buildFirefoxWebdriver, installWebExt, getExtensionIdChrome, getExtensionIdFirefox } = require('../e2e/func') const { delay, buildChromeWebDriver, getExtensionIdChrome } = require('../e2e/func')
const eth = new Ethjs(new Ethjs.HttpProvider('http://localhost:8545')) const eth = new Ethjs(new Ethjs.HttpProvider('http://localhost:8545'))
@ -41,11 +41,9 @@ captureAllScreens()
}) })
async function captureAllScreens() { async function captureAllScreens () {
// common names // common names
let button
let tabs let tabs
let element
await cleanScreenShotDir() await cleanScreenShotDir()
@ -108,7 +106,7 @@ async function captureAllScreens() {
await captureLanguageScreenShots('terms') await captureLanguageScreenShots('terms')
await delay(300) await delay(300)
element = driver.findElement(By.linkText('Attributions')) const element = driver.findElement(By.linkText('Attributions'))
await driver.executeScript('arguments[0].scrollIntoView(true)', element) await driver.executeScript('arguments[0].scrollIntoView(true)', element)
await delay(300) await delay(300)
await captureLanguageScreenShots('terms-scrolled') await captureLanguageScreenShots('terms-scrolled')
@ -134,10 +132,10 @@ async function captureAllScreens() {
// enter seed phrase // enter seed phrase
const seedPhraseButtons = await driver.findElements(By.css('.backup-phrase__confirm-seed-options > button')) const seedPhraseButtons = await driver.findElements(By.css('.backup-phrase__confirm-seed-options > button'))
const seedPhraseButtonWords = await Promise.all(seedPhraseButtons.map(button => button.getText())) const seedPhraseButtonWords = await Promise.all(seedPhraseButtons.map(button => button.getText()))
for (let targetWord of seedPhraseWords) { for (const targetWord of seedPhraseWords) {
const wordIndex = seedPhraseButtonWords.indexOf(targetWord) const wordIndex = seedPhraseButtonWords.indexOf(targetWord)
if (wordIndex === -1) throw new Error(`Captured seed phrase word "${targetWord}" not in found seed phrase button options ${seedPhraseButtonWords.join(' ')}`) if (wordIndex === -1) throw new Error(`Captured seed phrase word "${targetWord}" not in found seed phrase button options ${seedPhraseButtonWords.join(' ')}`)
await driver.findElement(By.css(`.backup-phrase__confirm-seed-options > button:nth-child(${wordIndex+1})`)).click() await driver.findElement(By.css(`.backup-phrase__confirm-seed-options > button:nth-child(${wordIndex + 1})`)).click()
await delay(100) await delay(100)
} }
await captureLanguageScreenShots('confirm secret backup phrase - words selected correctly') await captureLanguageScreenShots('confirm secret backup phrase - words selected correctly')
@ -191,11 +189,11 @@ async function captureAllScreens() {
} }
async function captureLanguageScreenShots(label) { async function captureLanguageScreenShots (label) {
const nonEnglishLocales = localesIndex.filter(localeMeta => localeMeta.code !== 'en') const nonEnglishLocales = localesIndex.filter(localeMeta => localeMeta.code !== 'en')
// take english shot // take english shot
await captureScreenShot(`${label} (en)`) await captureScreenShot(`${label} (en)`)
for (let localeMeta of nonEnglishLocales) { for (const localeMeta of nonEnglishLocales) {
// set locale and take shot // set locale and take shot
await setLocale(localeMeta.code) await setLocale(localeMeta.code)
await delay(300) await delay(300)
@ -206,19 +204,19 @@ async function captureLanguageScreenShots(label) {
await delay(300) await delay(300)
} }
async function setLocale(code) { async function setLocale (code) {
await driver.executeScript('window.metamask.updateCurrentLocale(arguments[0])', code) await driver.executeScript('window.metamask.updateCurrentLocale(arguments[0])', code)
} }
async function setProviderType(type) { async function setProviderType (type) {
await driver.executeScript('window.metamask.setProviderType(arguments[0])', type) await driver.executeScript('window.metamask.setProviderType(arguments[0])', type)
} }
async function cleanScreenShotDir() { async function cleanScreenShotDir () {
await pify(rimraf)(`./test-artifacts/screens/`) await pify(rimraf)(`./test-artifacts/screens/`)
} }
async function captureScreenShot(label) { async function captureScreenShot (label) {
const shotIndex = screenshotCount.toString().padStart(4, '0') const shotIndex = screenshotCount.toString().padStart(4, '0')
screenshotCount++ screenshotCount++
const artifactDir = `./test-artifacts/screens/` const artifactDir = `./test-artifacts/screens/`
@ -228,7 +226,7 @@ async function captureScreenShot(label) {
await pify(fs.writeFile)(`${artifactDir}/${shotIndex} - ${label}.png`, screenshot, { encoding: 'base64' }) await pify(fs.writeFile)(`${artifactDir}/${shotIndex} - ${label}.png`, screenshot, { encoding: 'base64' })
} }
async function generateGif(){ async function generateGif () {
// calculate screenshot size // calculate screenshot size
const screenshot = await driver.takeScreenshot() const screenshot = await driver.takeScreenshot()
const pngBuffer = Buffer.from(screenshot, 'base64') const pngBuffer = Buffer.from(screenshot, 'base64')
@ -244,7 +242,7 @@ async function generateGif(){
await pify(endOfStream)(stream) await pify(endOfStream)(stream)
} }
async function verboseReportOnFailure(test) { async function verboseReportOnFailure (test) {
const artifactDir = `./test-artifacts/${test.title}` const artifactDir = `./test-artifacts/${test.title}`
const filepathBase = `${artifactDir}/test-failure` const filepathBase = `${artifactDir}/test-failure`
await pify(mkdirp)(artifactDir) await pify(mkdirp)(artifactDir)
@ -256,7 +254,7 @@ async function verboseReportOnFailure(test) {
await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource) await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource)
} }
async function requestEther(address) { async function requestEther (address) {
const accounts = await eth.accounts() const accounts = await eth.accounts()
await eth.sendTransaction({ from: accounts[0], to: address, value: 1 * 1e18, data: '0x0' }) await eth.sendTransaction({ from: accounts[0], to: address, value: 1 * 1e18, data: '0x0' })
} }

@ -1,5 +1,4 @@
const assert = require('assert') const assert = require('assert')
const path = require('path')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const accountImporter = require('../../../app/scripts/account-import-strategies/index') const accountImporter = require('../../../app/scripts/account-import-strategies/index')
const { assertRejects } = require('../test-utils') const { assertRejects } = require('../test-utils')
@ -15,7 +14,7 @@ describe('Account Import Strategies', function () {
}) })
it('throws an error for empty string private key', async () => { it('throws an error for empty string private key', async () => {
assertRejects(async function() { assertRejects(async function () {
await accountImporter.importAccount('Private Key', [ '' ]) await accountImporter.importAccount('Private Key', [ '' ])
}, Error, 'no empty strings') }, Error, 'no empty strings')
}) })

@ -12,7 +12,7 @@ const stubPreferencesStore = {
}, },
} }
}, },
}; }
describe('address-book-controller', function () { describe('address-book-controller', function () {
var addressBookController var addressBookController

@ -5,9 +5,6 @@ const {
getNetworkDisplayName, getNetworkDisplayName,
} = require('../../../../app/scripts/controllers/network/util') } = require('../../../../app/scripts/controllers/network/util')
const { createTestProviderTools } = require('../../../stub/provider')
const providerResultStub = {}
describe('# Network Controller', function () { describe('# Network Controller', function () {
let networkController let networkController
const noop = () => {} const noop = () => {}

@ -1,12 +1,10 @@
const assert = require('assert') const assert = require('assert')
const NonceTracker = require('../../../../../app/scripts/controllers/transactions/nonce-tracker') const NonceTracker = require('../../../../../app/scripts/controllers/transactions/nonce-tracker')
const MockTxGen = require('../../../../lib/mock-tx-gen') const MockTxGen = require('../../../../lib/mock-tx-gen')
let providerResultStub = {} const providerResultStub = {}
describe('Nonce Tracker', function () { describe('Nonce Tracker', function () {
let nonceTracker, provider let nonceTracker, pendingTxs, confirmedTxs
let getPendingTransactions, pendingTxs
let getConfirmedTransactions, confirmedTxs
describe('#getNonceLock', function () { describe('#getNonceLock', function () {
@ -182,8 +180,8 @@ describe('Nonce Tracker', function () {
describe('When all three return different values', function () { describe('When all three return different values', function () {
beforeEach(function () { beforeEach(function () {
const txGen = new MockTxGen() const txGen = new MockTxGen()
const confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 10 }) confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 10 })
const pendingTxs = txGen.generate({ pendingTxs = txGen.generate({
status: 'submitted', status: 'submitted',
nonce: 100, nonce: 100,
}, { count: 1 }) }, { count: 1 })
@ -202,8 +200,8 @@ describe('Nonce Tracker', function () {
describe('Faq issue 67', function () { describe('Faq issue 67', function () {
beforeEach(function () { beforeEach(function () {
const txGen = new MockTxGen() const txGen = new MockTxGen()
const confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 64 }) confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 64 })
const pendingTxs = txGen.generate({ pendingTxs = txGen.generate({
status: 'submitted', status: 'submitted',
}, { count: 10 }) }, { count: 10 })
// 0x40 is 64 in hex: // 0x40 is 64 in hex:

@ -1,20 +1,12 @@
const assert = require('assert') const assert = require('assert')
const ethUtil = require('ethereumjs-util')
const EthTx = require('ethereumjs-tx')
const ObservableStore = require('obs-store')
const clone = require('clone')
const { createTestProviderTools } = require('../../../../stub/provider') const { createTestProviderTools } = require('../../../../stub/provider')
const PendingTransactionTracker = require('../../../../../app/scripts/controllers/transactions/pending-tx-tracker') const PendingTransactionTracker = require('../../../../../app/scripts/controllers/transactions/pending-tx-tracker')
const MockTxGen = require('../../../../lib/mock-tx-gen') const MockTxGen = require('../../../../lib/mock-tx-gen')
const sinon = require('sinon') const sinon = require('sinon')
const noop =()=>true
const currentNetworkId = 42
const otherNetworkId = 36
const privKey = new Buffer('8718b9618a37d1fc78c436511fc6df3c8258d3250635bba617f33003270ec03e', 'hex')
describe('PendingTransactionTracker', function () { describe('PendingTransactionTracker', function () {
let pendingTxTracker, txMeta, txMetaNoHash, txMetaNoRawTx, providerResultStub, let pendingTxTracker, txMeta, txMetaNoHash, providerResultStub,
provider, txMeta3, txList, knownErrors provider, txMeta3, txList, knownErrors
this.timeout(10000) this.timeout(10000)
@ -35,11 +27,7 @@ describe('PendingTransactionTracker', function () {
status: 'signed', status: 'signed',
txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d'}, txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d'},
} }
txMetaNoRawTx = {
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: 'signed',
txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d'},
}
providerResultStub = {} providerResultStub = {}
provider = createTestProviderTools({ scaffold: providerResultStub }).provider provider = createTestProviderTools({ scaffold: providerResultStub }).provider
@ -48,10 +36,10 @@ describe('PendingTransactionTracker', function () {
nonceTracker: { nonceTracker: {
getGlobalLock: async () => { getGlobalLock: async () => {
return { releaseLock: () => {} } return { releaseLock: () => {} }
} },
}, },
getPendingTransactions: () => {return []}, getPendingTransactions: () => { return [] },
getCompletedTransactions: () => {return []}, getCompletedTransactions: () => { return [] },
publishTransaction: () => {}, publishTransaction: () => {},
confirmTransaction: () => {}, confirmTransaction: () => {},
}) })
@ -108,6 +96,58 @@ describe('PendingTransactionTracker', function () {
}) })
}) })
describe('#checkForTxInBlock', function () {
it('should return if no pending transactions', function () {
// throw a type error if it trys to do anything on the block
// thus failing the test
const block = Proxy.revocable({}, {}).revoke()
pendingTxTracker.checkForTxInBlock(block)
})
it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) {
const block = Proxy.revocable({}, {}).revoke()
pendingTxTracker.getPendingTransactions = () => [txMetaNoHash]
pendingTxTracker.once('tx:failed', (txId, err) => {
assert(txId, txMetaNoHash.id, 'should pass txId')
done()
})
pendingTxTracker.checkForTxInBlock(block)
})
it('should emit \'txConfirmed\' if the tx is in the block', function (done) {
const block = { transactions: [txMeta]}
pendingTxTracker.getPendingTransactions = () => [txMeta]
pendingTxTracker.once('tx:confirmed', (txId) => {
assert(txId, txMeta.id, 'should pass txId')
done()
})
pendingTxTracker.once('tx:failed', (_, err) => { done(err) })
pendingTxTracker.checkForTxInBlock(block)
})
})
describe('#queryPendingTxs', function () {
it('should call #_checkPendingTxs if their is no oldBlock', function (done) {
let oldBlock
const newBlock = { number: '0x01' }
pendingTxTracker._checkPendingTxs = done
pendingTxTracker.queryPendingTxs({ oldBlock, newBlock })
})
it('should call #_checkPendingTxs if oldBlock and the newBlock have a diff of greater then 1', function (done) {
const oldBlock = { number: '0x01' }
const newBlock = { number: '0x03' }
pendingTxTracker._checkPendingTxs = done
pendingTxTracker.queryPendingTxs({ oldBlock, newBlock })
})
it('should not call #_checkPendingTxs if oldBlock and the newBlock have a diff of 1 or less', function (done) {
const oldBlock = { number: '0x1' }
const newBlock = { number: '0x2' }
pendingTxTracker._checkPendingTxs = () => {
const err = new Error('should not call #_checkPendingTxs if oldBlock and the newBlock have a diff of 1 or less')
done(err)
}
pendingTxTracker.queryPendingTxs({ oldBlock, newBlock })
done()
})
})
describe('#_checkPendingTx', function () { describe('#_checkPendingTx', function () {
it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) { it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) {
pendingTxTracker.once('tx:failed', (txId, err) => { pendingTxTracker.once('tx:failed', (txId, err) => {
@ -129,7 +169,7 @@ describe('PendingTransactionTracker', function () {
txMeta2.id = 2 txMeta2.id = 2
txMeta3.id = 3 txMeta3.id = 3
txList = [txMeta, txMeta2, txMeta3].map((tx) => { txList = [txMeta, txMeta2, txMeta3].map((tx) => {
tx.processed = new Promise ((resolve) => { tx.resolve = resolve }) tx.processed = new Promise((resolve) => { tx.resolve = resolve })
return tx return tx
}) })
}) })
@ -146,7 +186,7 @@ describe('PendingTransactionTracker', function () {
}) })
describe('#resubmitPendingTxs', function () { describe('#resubmitPendingTxs', function () {
const blockNuberStub = '0x0' const blockNumberStub = '0x0'
beforeEach(function () { beforeEach(function () {
const txMeta2 = txMeta3 = txMeta const txMeta2 = txMeta3 = txMeta
txList = [txMeta, txMeta2, txMeta3].map((tx) => { txList = [txMeta, txMeta2, txMeta3].map((tx) => {
@ -164,7 +204,7 @@ describe('PendingTransactionTracker', function () {
Promise.all(txList.map((tx) => tx.processed)) Promise.all(txList.map((tx) => tx.processed))
.then((txCompletedList) => done()) .then((txCompletedList) => done())
.catch(done) .catch(done)
pendingTxTracker.resubmitPendingTxs(blockNuberStub) pendingTxTracker.resubmitPendingTxs(blockNumberStub)
}) })
it('should not emit \'tx:failed\' if the txMeta throws a known txError', function (done) { it('should not emit \'tx:failed\' if the txMeta throws a known txError', function (done) {
knownErrors = [ knownErrors = [
@ -191,7 +231,7 @@ describe('PendingTransactionTracker', function () {
.then((txCompletedList) => done()) .then((txCompletedList) => done())
.catch(done) .catch(done)
pendingTxTracker.resubmitPendingTxs(blockNuberStub) pendingTxTracker.resubmitPendingTxs(blockNumberStub)
}) })
it('should emit \'tx:warning\' if it encountered a real error', function (done) { it('should emit \'tx:warning\' if it encountered a real error', function (done) {
pendingTxTracker.once('tx:warning', (txMeta, err) => { pendingTxTracker.once('tx:warning', (txMeta, err) => {
@ -209,12 +249,12 @@ describe('PendingTransactionTracker', function () {
.then((txCompletedList) => done()) .then((txCompletedList) => done())
.catch(done) .catch(done)
pendingTxTracker.resubmitPendingTxs(blockNuberStub) pendingTxTracker.resubmitPendingTxs(blockNumberStub)
}) })
}) })
describe('#_resubmitTx', function () { describe('#_resubmitTx', function () {
const mockFirstRetryBlockNumber = '0x1' const mockFirstRetryBlockNumber = '0x1'
let txMetaToTestExponentialBackoff let txMetaToTestExponentialBackoff, enoughBalance
beforeEach(() => { beforeEach(() => {
pendingTxTracker.getBalance = (address) => { pendingTxTracker.getBalance = (address) => {
@ -237,7 +277,7 @@ describe('PendingTransactionTracker', function () {
}) })
it('should publish the transaction', function (done) { it('should publish the transaction', function (done) {
const enoughBalance = '0x100000' enoughBalance = '0x100000'
// Stubbing out current account state: // Stubbing out current account state:
// Adding the fake tx: // Adding the fake tx:
@ -252,7 +292,7 @@ describe('PendingTransactionTracker', function () {
}) })
it('should not publish the transaction if the limit of retries has been exceeded', function (done) { it('should not publish the transaction if the limit of retries has been exceeded', function (done) {
const enoughBalance = '0x100000' enoughBalance = '0x100000'
const mockLatestBlockNumber = '0x5' const mockLatestBlockNumber = '0x5'
pendingTxTracker._resubmitTx(txMetaToTestExponentialBackoff, mockLatestBlockNumber) pendingTxTracker._resubmitTx(txMetaToTestExponentialBackoff, mockLatestBlockNumber)
@ -266,7 +306,7 @@ describe('PendingTransactionTracker', function () {
}) })
it('should publish the transaction if the number of blocks since last retry exceeds the last set limit', function (done) { it('should publish the transaction if the number of blocks since last retry exceeds the last set limit', function (done) {
const enoughBalance = '0x100000' enoughBalance = '0x100000'
const mockLatestBlockNumber = '0x11' const mockLatestBlockNumber = '0x11'
pendingTxTracker._resubmitTx(txMetaToTestExponentialBackoff, mockLatestBlockNumber) pendingTxTracker._resubmitTx(txMetaToTestExponentialBackoff, mockLatestBlockNumber)
@ -282,7 +322,7 @@ describe('PendingTransactionTracker', function () {
describe('#_checkIfNonceIsTaken', function () { describe('#_checkIfNonceIsTaken', function () {
beforeEach(function () { beforeEach(function () {
let confirmedTxList = [{ const confirmedTxList = [{
id: 1, id: 1,
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: 'confirmed', status: 'confirmed',

@ -28,7 +28,7 @@ describe('Recipient Blacklist Checker', function () {
it('does not fail on test networks', function () { it('does not fail on test networks', function () {
let callCount = 0 let callCount = 0
const networks = [ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE] const networks = [ROPSTEN_CODE, RINKEYBY_CODE, KOVAN_CODE]
for (let networkId in networks) { for (const networkId in networks) {
publicAccounts.forEach((account) => { publicAccounts.forEach((account) => {
recipientBlackListChecker.checkAccount(networkId, account) recipientBlackListChecker.checkAccount(networkId, account)
callCount++ callCount++
@ -61,7 +61,7 @@ describe('Recipient Blacklist Checker', function () {
} catch (err) { } catch (err) {
assert.equal(err.message, 'Recipient is a public account') assert.equal(err.message, 'Recipient is a public account')
} }
}) })
it('fails for public account - lowercase', async function () { it('fails for public account - lowercase', async function () {
const mainnetId = 1 const mainnetId = 1
@ -72,6 +72,6 @@ describe('Recipient Blacklist Checker', function () {
} catch (err) { } catch (err) {
assert.equal(err.message, 'Recipient is a public account') assert.equal(err.message, 'Recipient is a public account')
} }
}) })
}) })
}) })

@ -2,20 +2,17 @@ const assert = require('assert')
const EventEmitter = require('events') const EventEmitter = require('events')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const EthTx = require('ethereumjs-tx') const EthTx = require('ethereumjs-tx')
const EthjsQuery = require('ethjs-query')
const ObservableStore = require('obs-store') const ObservableStore = require('obs-store')
const sinon = require('sinon') const sinon = require('sinon')
const TransactionController = require('../../../../../app/scripts/controllers/transactions') const TransactionController = require('../../../../../app/scripts/controllers/transactions')
const TxGasUtils = require('../../../../../app/scripts/controllers/transactions/tx-gas-utils')
const { createTestProviderTools, getTestAccounts } = require('../../../../stub/provider') const { createTestProviderTools, getTestAccounts } = require('../../../../stub/provider')
const noop = () => true const noop = () => true
const currentNetworkId = 42 const currentNetworkId = 42
const otherNetworkId = 36
describe('Transaction Controller', function () { describe('Transaction Controller', function () {
let txController, provider, providerResultStub, query, fromAccount let txController, provider, providerResultStub, fromAccount
beforeEach(function () { beforeEach(function () {
providerResultStub = { providerResultStub = {
@ -25,7 +22,6 @@ describe('Transaction Controller', function () {
eth_getCode: '0x', eth_getCode: '0x',
} }
provider = createTestProviderTools({ scaffold: providerResultStub }).provider provider = createTestProviderTools({ scaffold: providerResultStub }).provider
query = new EthjsQuery(provider)
fromAccount = getTestAccounts()[0] fromAccount = getTestAccounts()[0]
const blockTrackerStub = new EventEmitter() const blockTrackerStub = new EventEmitter()
blockTrackerStub.getCurrentBlock = noop blockTrackerStub.getCurrentBlock = noop
@ -389,7 +385,7 @@ describe('Transaction Controller', function () {
describe('#retryTransaction', function () { describe('#retryTransaction', function () {
it('should create a new txMeta with the same txParams as the original one', function (done) { it('should create a new txMeta with the same txParams as the original one', function (done) {
let txParams = { const txParams = {
nonce: '0x00', nonce: '0x00',
from: '0xB09d8505E1F4EF1CeA089D47094f5DD3464083d4', from: '0xB09d8505E1F4EF1CeA089D47094f5DD3464083d4',
to: '0xB09d8505E1F4EF1CeA089D47094f5DD3464083d4', to: '0xB09d8505E1F4EF1CeA089D47094f5DD3464083d4',

@ -1,6 +1,5 @@
const assert = require('assert') const assert = require('assert')
const Transaction = require('ethereumjs-tx') const Transaction = require('ethereumjs-tx')
const BN = require('bn.js')
const { hexToBn, bnToHex } = require('../../../../../app/scripts/lib/util') const { hexToBn, bnToHex } = require('../../../../../app/scripts/lib/util')

@ -2,16 +2,16 @@ const assert = require('assert')
const txStateHistoryHelper = require('../../../../../app/scripts/controllers/transactions/lib/tx-state-history-helper') const txStateHistoryHelper = require('../../../../../app/scripts/controllers/transactions/lib/tx-state-history-helper')
const testVault = require('../../../../data/v17-long-history.json') const testVault = require('../../../../data/v17-long-history.json')
describe ('Transaction state history helper', function () { describe('Transaction state history helper', function () {
describe('#snapshotFromTxMeta', function () { describe('#snapshotFromTxMeta', function () {
it('should clone deep', function () { it('should clone deep', function () {
const input = { const input = {
foo: { foo: {
bar: { bar: {
bam: 'baz' bam: 'baz',
} },
} },
} }
const output = txStateHistoryHelper.snapshotFromTxMeta(input) const output = txStateHistoryHelper.snapshotFromTxMeta(input)
assert('foo' in output, 'has a foo key') assert('foo' in output, 'has a foo key')
@ -50,14 +50,14 @@ describe ('Transaction state history helper', function () {
it('replaying history does not mutate the original obj', function () { it('replaying history does not mutate the original obj', function () {
const initialState = { test: true, message: 'hello', value: 1 } const initialState = { test: true, message: 'hello', value: 1 }
const diff1 = [{ const diff1 = [{
"op": "replace", 'op': 'replace',
"path": "/message", 'path': '/message',
"value": "haay", 'value': 'haay',
}] }]
const diff2 = [{ const diff2 = [{
"op": "replace", 'op': 'replace',
"path": "/value", 'path': '/value',
"value": 2, 'value': 2,
}] }]
const history = [initialState, diff1, diff2] const history = [initialState, diff1, diff2]
@ -72,15 +72,15 @@ describe ('Transaction state history helper', function () {
describe('#generateHistoryEntry', function () { describe('#generateHistoryEntry', function () {
function generateHistoryEntryTest(note) { function generateHistoryEntryTest (note) {
const prevState = { const prevState = {
someValue: 'value 1', someValue: 'value 1',
foo: { foo: {
bar: { bar: {
bam: 'baz' bam: 'baz',
} },
} },
} }
const nextState = { const nextState = {
@ -89,9 +89,9 @@ describe ('Transaction state history helper', function () {
foo: { foo: {
newPropFirstLevel: 'new property - first level', newPropFirstLevel: 'new property - first level',
bar: { bar: {
bam: 'baz' bam: 'baz',
} },
} },
} }
const before = new Date().getTime() const before = new Date().getTime()
@ -106,8 +106,7 @@ describe ('Transaction state history helper', function () {
assert.equal(result[0].path, expectedEntry1.path) assert.equal(result[0].path, expectedEntry1.path)
assert.equal(result[0].value, expectedEntry1.value) assert.equal(result[0].value, expectedEntry1.value)
assert.equal(result[0].value, expectedEntry1.value) assert.equal(result[0].value, expectedEntry1.value)
if (note) if (note) { assert.equal(result[0].note, note) }
assert.equal(result[0].note, note)
assert.ok(result[0].timestamp >= before && result[0].timestamp <= after) assert.ok(result[0].timestamp >= before && result[0].timestamp <= after)
@ -124,6 +123,6 @@ describe ('Transaction state history helper', function () {
it('should add note to first entry', function () { it('should add note to first entry', function () {
generateHistoryEntryTest('custom note') generateHistoryEntryTest('custom note')
}) })
}) })
}) })

@ -1,6 +1,4 @@
const assert = require('assert') const assert = require('assert')
const clone = require('clone')
const ObservableStore = require('obs-store')
const TxStateManager = require('../../../../../app/scripts/controllers/transactions/tx-state-manager') const TxStateManager = require('../../../../../app/scripts/controllers/transactions/tx-state-manager')
const txStateHistoryHelper = require('../../../../../app/scripts/controllers/transactions/lib/tx-state-history-helper') const txStateHistoryHelper = require('../../../../../app/scripts/controllers/transactions/lib/tx-state-history-helper')
const noop = () => true const noop = () => true
@ -16,23 +14,23 @@ describe('TransactionStateManager', function () {
transactions: [], transactions: [],
}, },
txHistoryLimit: 10, txHistoryLimit: 10,
getNetwork: () => currentNetworkId getNetwork: () => currentNetworkId,
}) })
}) })
describe('#setTxStatusSigned', function () { describe('#setTxStatusSigned', function () {
it('sets the tx status to signed', function () { it('sets the tx status to signed', function () {
let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx, noop) txStateManager.addTx(tx, noop)
txStateManager.setTxStatusSigned(1) txStateManager.setTxStatusSigned(1)
let result = txStateManager.getTxList() const result = txStateManager.getTxList()
assert.ok(Array.isArray(result)) assert.ok(Array.isArray(result))
assert.equal(result.length, 1) assert.equal(result.length, 1)
assert.equal(result[0].status, 'signed') assert.equal(result[0].status, 'signed')
}) })
it('should emit a signed event to signal the exciton of callback', (done) => { it('should emit a signed event to signal the exciton of callback', (done) => {
let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
const noop = function () { const noop = function () {
assert(true, 'event listener has been triggered and noop executed') assert(true, 'event listener has been triggered and noop executed')
done() done()
@ -46,21 +44,24 @@ describe('TransactionStateManager', function () {
describe('#setTxStatusRejected', function () { describe('#setTxStatusRejected', function () {
it('sets the tx status to rejected', function () { it('sets the tx status to rejected', function () {
let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx) txStateManager.addTx(tx)
txStateManager.setTxStatusRejected(1) txStateManager.setTxStatusRejected(1)
let result = txStateManager.getTxList() const result = txStateManager.getTxList()
assert.ok(Array.isArray(result)) assert.ok(Array.isArray(result))
assert.equal(result.length, 1) assert.equal(result.length, 1)
assert.equal(result[0].status, 'rejected') assert.equal(result[0].status, 'rejected')
}) })
it('should emit a rejected event to signal the exciton of callback', (done) => { it('should emit a rejected event to signal the exciton of callback', (done) => {
let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx) txStateManager.addTx(tx)
const noop = function (err, txId) { const noop = function (err, txId) {
assert(true, 'event listener has been triggered and noop executed') if (err) {
done() console.log('Error: ', err)
}
assert(true, 'event listener has been triggered and noop executed')
done()
} }
txStateManager.on('1:rejected', noop) txStateManager.on('1:rejected', noop)
txStateManager.setTxStatusRejected(1) txStateManager.setTxStatusRejected(1)
@ -69,7 +70,7 @@ describe('TransactionStateManager', function () {
describe('#getFullTxList', function () { describe('#getFullTxList', function () {
it('when new should return empty array', function () { it('when new should return empty array', function () {
let result = txStateManager.getTxList() const result = txStateManager.getTxList()
assert.ok(Array.isArray(result)) assert.ok(Array.isArray(result))
assert.equal(result.length, 0) assert.equal(result.length, 0)
}) })
@ -77,7 +78,7 @@ describe('TransactionStateManager', function () {
describe('#getTxList', function () { describe('#getTxList', function () {
it('when new should return empty array', function () { it('when new should return empty array', function () {
let result = txStateManager.getTxList() const result = txStateManager.getTxList()
assert.ok(Array.isArray(result)) assert.ok(Array.isArray(result))
assert.equal(result.length, 0) assert.equal(result.length, 0)
}) })
@ -85,21 +86,21 @@ describe('TransactionStateManager', function () {
describe('#addTx', function () { describe('#addTx', function () {
it('adds a tx returned in getTxList', function () { it('adds a tx returned in getTxList', function () {
let tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } const tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx, noop) txStateManager.addTx(tx, noop)
let result = txStateManager.getTxList() const result = txStateManager.getTxList()
assert.ok(Array.isArray(result)) assert.ok(Array.isArray(result))
assert.equal(result.length, 1) assert.equal(result.length, 1)
assert.equal(result[0].id, 1) assert.equal(result[0].id, 1)
}) })
it('does not override txs from other networks', function () { it('does not override txs from other networks', function () {
let tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } const tx = { id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }
let tx2 = { id: 2, status: 'confirmed', metamaskNetworkId: otherNetworkId, txParams: {} } const tx2 = { id: 2, status: 'confirmed', metamaskNetworkId: otherNetworkId, txParams: {} }
txStateManager.addTx(tx, noop) txStateManager.addTx(tx, noop)
txStateManager.addTx(tx2, noop) txStateManager.addTx(tx2, noop)
let result = txStateManager.getFullTxList() const result = txStateManager.getFullTxList()
let result2 = txStateManager.getTxList() const result2 = txStateManager.getTxList()
assert.equal(result.length, 2, 'txs were deleted') assert.equal(result.length, 2, 'txs were deleted')
assert.equal(result2.length, 1, 'incorrect number of txs on network.') assert.equal(result2.length, 1, 'incorrect number of txs on network.')
}) })
@ -110,7 +111,7 @@ describe('TransactionStateManager', function () {
const tx = { id: i, time: new Date(), status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } const tx = { id: i, time: new Date(), status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx, noop) txStateManager.addTx(tx, noop)
} }
let result = txStateManager.getTxList() const result = txStateManager.getTxList()
assert.equal(result.length, limit, `limit of ${limit} txs enforced`) assert.equal(result.length, limit, `limit of ${limit} txs enforced`)
assert.equal(result[0].id, 1, 'early txs truncted') assert.equal(result[0].id, 1, 'early txs truncted')
}) })
@ -121,20 +122,20 @@ describe('TransactionStateManager', function () {
const tx = { id: i, time: new Date(), status: 'rejected', metamaskNetworkId: currentNetworkId, txParams: {} } const tx = { id: i, time: new Date(), status: 'rejected', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx, noop) txStateManager.addTx(tx, noop)
} }
let result = txStateManager.getTxList() const result = txStateManager.getTxList()
assert.equal(result.length, limit, `limit of ${limit} txs enforced`) assert.equal(result.length, limit, `limit of ${limit} txs enforced`)
assert.equal(result[0].id, 1, 'early txs truncted') assert.equal(result[0].id, 1, 'early txs truncted')
}) })
it('cuts off early txs beyond a limit but does not cut unapproved txs', function () { it('cuts off early txs beyond a limit but does not cut unapproved txs', function () {
let unconfirmedTx = { id: 0, time: new Date(), status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } const unconfirmedTx = { id: 0, time: new Date(), status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(unconfirmedTx, noop) txStateManager.addTx(unconfirmedTx, noop)
const limit = txStateManager.txHistoryLimit const limit = txStateManager.txHistoryLimit
for (let i = 1; i < limit + 1; i++) { for (let i = 1; i < limit + 1; i++) {
const tx = { id: i, time: new Date(), status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} } const tx = { id: i, time: new Date(), status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }
txStateManager.addTx(tx, noop) txStateManager.addTx(tx, noop)
} }
let result = txStateManager.getTxList() const result = txStateManager.getTxList()
assert.equal(result.length, limit, `limit of ${limit} txs enforced`) assert.equal(result.length, limit, `limit of ${limit} txs enforced`)
assert.equal(result[0].id, 0, 'first tx should still be there') assert.equal(result[0].id, 0, 'first tx should still be there')
assert.equal(result[0].status, 'unapproved', 'first tx should be unapproved') assert.equal(result[0].status, 'unapproved', 'first tx should be unapproved')
@ -149,7 +150,7 @@ describe('TransactionStateManager', function () {
const txMeta = txStateManager.getTx('1') const txMeta = txStateManager.getTx('1')
txMeta.hash = 'foo' txMeta.hash = 'foo'
txStateManager.updateTx(txMeta) txStateManager.updateTx(txMeta)
let result = txStateManager.getTx('1') const result = txStateManager.getTx('1')
assert.equal(result.hash, 'foo') assert.equal(result.hash, 'foo')
}) })
@ -166,8 +167,6 @@ describe('TransactionStateManager', function () {
}, },
} }
const updatedMeta = clone(txMeta)
txStateManager.addTx(txMeta) txStateManager.addTx(txMeta)
const updatedTx = txStateManager.getTx('1') const updatedTx = txStateManager.getTx('1')
// verify tx was initialized correctly // verify tx was initialized correctly
@ -185,7 +184,7 @@ describe('TransactionStateManager', function () {
// validate history was updated // validate history was updated
assert.equal(result.history.length, 2, 'two history items (initial + diff)') assert.equal(result.history.length, 2, 'two history items (initial + diff)')
assert.equal(result.history[1].length, 1, 'two history state items (initial + diff)') assert.equal(result.history[1].length, 1, 'two history state items (initial + diff)')
const expectedEntry = { op: 'replace', path: '/txParams/gasPrice', value: desiredGasPrice } const expectedEntry = { op: 'replace', path: '/txParams/gasPrice', value: desiredGasPrice }
assert.deepEqual(result.history[1][0].op, expectedEntry.op, 'two history items (initial + diff) operation') assert.deepEqual(result.history[1][0].op, expectedEntry.op, 'two history items (initial + diff) operation')
assert.deepEqual(result.history[1][0].path, expectedEntry.path, 'two history items (initial + diff) path') assert.deepEqual(result.history[1][0].path, expectedEntry.path, 'two history items (initial + diff) path')

@ -27,7 +27,7 @@ describe('txUtils', function () {
describe('#normalizeTxParams', () => { describe('#normalizeTxParams', () => {
it('should normalize txParams', () => { it('should normalize txParams', () => {
let txParams = { const txParams = {
chainId: '0x1', chainId: '0x1',
from: 'a7df1beDBF813f57096dF77FCd515f0B3900e402', from: 'a7df1beDBF813f57096dF77FCd515f0B3900e402',
to: null, to: null,
@ -91,7 +91,7 @@ describe('txUtils', function () {
assert.throws(() => { txUtils.validateFrom(txParams) }, Error, `Invalid from address`) assert.throws(() => { txUtils.validateFrom(txParams) }, Error, `Invalid from address`)
// should run // should run
txParams.from ='0x1678a085c290ebd122dc42cba69373b5953b831d' txParams.from = '0x1678a085c290ebd122dc42cba69373b5953b831d'
txUtils.validateFrom(txParams) txUtils.validateFrom(txParams)
}) })
}) })

@ -11,7 +11,7 @@ global.crypto = global.crypto || {
array[i] = Math.random() * 100 array[i] = Math.random() * 100
} }
return array return array
} },
} }
describe('EdgeEncryptor', function () { describe('EdgeEncryptor', function () {
@ -33,10 +33,10 @@ describe('EdgeEncryptor', function () {
it('should return proper format.', function (done) { it('should return proper format.', function (done) {
edgeEncryptor.encrypt(password, data) edgeEncryptor.encrypt(password, data)
.then(function (encryptedData) { .then(function (encryptedData) {
let encryptedObject = JSON.parse(encryptedData) const encryptedObject = JSON.parse(encryptedData)
assert.ok(encryptedObject.data, 'there is no data') assert.ok(encryptedObject.data, 'there is no data')
assert.ok(encryptedObject.iv && encryptedObject.iv.length != 0, 'there is no iv') assert.ok(encryptedObject.iv && encryptedObject.iv.length !== 0, 'there is no iv')
assert.ok(encryptedObject.salt && encryptedObject.salt.length != 0, 'there is no salt') assert.ok(encryptedObject.salt && encryptedObject.salt.length !== 0, 'there is no salt')
done() done()
}).catch(function (err) { }).catch(function (err) {
done(err) done(err)
@ -56,7 +56,7 @@ describe('EdgeEncryptor', function () {
assert.notEqual(encryptedData[1].length, 0) assert.notEqual(encryptedData[1].length, 0)
done() done()
}) })
}) })
}) })
describe('decrypt', function () { describe('decrypt', function () {

@ -13,8 +13,12 @@ describe('nodeify', function () {
it('should retain original context', function (done) { it('should retain original context', function (done) {
var nodified = nodeify(obj.promiseFunc, obj) var nodified = nodeify(obj.promiseFunc, obj)
nodified('baz', function (err, res) { nodified('baz', function (err, res) {
assert.equal(res, 'barbaz') if (!err) {
done() assert.equal(res, 'barbaz')
done()
} else {
done(new Error(err.toString()))
}
}) })
}) })

@ -2,7 +2,6 @@ const assert = require('assert')
const PendingBalanceCalculator = require('../../../app/scripts/lib/pending-balance-calculator') const PendingBalanceCalculator = require('../../../app/scripts/lib/pending-balance-calculator')
const MockTxGen = require('../../lib/mock-tx-gen') const MockTxGen = require('../../lib/mock-tx-gen')
const BN = require('ethereumjs-util').BN const BN = require('ethereumjs-util').BN
let providerResultStub = {}
const zeroBn = new BN(0) const zeroBn = new BN(0)
const etherBn = new BN(String(1e18)) const etherBn = new BN(String(1e18))
@ -20,7 +19,7 @@ describe('PendingBalanceCalculator', function () {
value: ether, value: ether,
gasPrice: '0x0', gasPrice: '0x0',
gas: '0x0', gas: '0x0',
} },
}, { count: 1 }) }, { count: 1 })
const balanceCalculator = generateBalanceCalcWith([], zeroBn) const balanceCalculator = generateBalanceCalcWith([], zeroBn)
@ -36,7 +35,7 @@ describe('PendingBalanceCalculator', function () {
value: '0x0', value: '0x0',
gasPrice: '0x2', gasPrice: '0x2',
gas: '0x3', gas: '0x3',
} },
}, { count: 1 }) }, { count: 1 })
const balanceCalculator = generateBalanceCalcWith([], zeroBn) const balanceCalculator = generateBalanceCalcWith([], zeroBn)
@ -66,7 +65,7 @@ describe('PendingBalanceCalculator', function () {
value: ether, value: ether,
gasPrice: '0x0', gasPrice: '0x0',
gas: '0x0', gas: '0x0',
} },
}, { count: 1 }) }, { count: 1 })
balanceCalculator = generateBalanceCalcWith(pendingTxs, etherBn) balanceCalculator = generateBalanceCalcWith(pendingTxs, etherBn)

@ -9,11 +9,10 @@ describe('SeedPhraseVerifier', function () {
describe('verifyAccounts', function () { describe('verifyAccounts', function () {
let password = 'passw0rd1' const password = 'passw0rd1'
let hdKeyTree = 'HD Key Tree' const hdKeyTree = 'HD Key Tree'
let keyringController let keyringController
let vault
let primaryKeyring let primaryKeyring
beforeEach(async function () { beforeEach(async function () {
@ -24,60 +23,60 @@ describe('SeedPhraseVerifier', function () {
assert(keyringController) assert(keyringController)
vault = await keyringController.createNewVaultAndKeychain(password) await keyringController.createNewVaultAndKeychain(password)
primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0] primaryKeyring = keyringController.getKeyringsByType(hdKeyTree)[0]
}) })
it('should be able to verify created account with seed words', async function () { it('should be able to verify created account with seed words', async function () {
let createdAccounts = await primaryKeyring.getAccounts() const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 1) assert.equal(createdAccounts.length, 1)
let serialized = await primaryKeyring.serialize() const serialized = await primaryKeyring.serialize()
let seedWords = serialized.mnemonic const seedWords = serialized.mnemonic
assert.notEqual(seedWords.length, 0) assert.notEqual(seedWords.length, 0)
let result = await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords) await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords)
}) })
it('should be able to verify created account (upper case) with seed words', async function () { it('should be able to verify created account (upper case) with seed words', async function () {
let createdAccounts = await primaryKeyring.getAccounts() const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 1) assert.equal(createdAccounts.length, 1)
let upperCaseAccounts = [createdAccounts[0].toUpperCase()] const upperCaseAccounts = [createdAccounts[0].toUpperCase()]
let serialized = await primaryKeyring.serialize() const serialized = await primaryKeyring.serialize()
let seedWords = serialized.mnemonic const seedWords = serialized.mnemonic
assert.notEqual(seedWords.length, 0) assert.notEqual(seedWords.length, 0)
let result = await seedPhraseVerifier.verifyAccounts(upperCaseAccounts, seedWords) await seedPhraseVerifier.verifyAccounts(upperCaseAccounts, seedWords)
}) })
it('should be able to verify created account (lower case) with seed words', async function () { it('should be able to verify created account (lower case) with seed words', async function () {
let createdAccounts = await primaryKeyring.getAccounts() const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 1) assert.equal(createdAccounts.length, 1)
let lowerCaseAccounts = [createdAccounts[0].toLowerCase()] const lowerCaseAccounts = [createdAccounts[0].toLowerCase()]
let serialized = await primaryKeyring.serialize() const serialized = await primaryKeyring.serialize()
let seedWords = serialized.mnemonic const seedWords = serialized.mnemonic
assert.notEqual(seedWords.length, 0) assert.notEqual(seedWords.length, 0)
let result = await seedPhraseVerifier.verifyAccounts(lowerCaseAccounts, seedWords) await seedPhraseVerifier.verifyAccounts(lowerCaseAccounts, seedWords)
}) })
it('should return error with good but different seed words', async function () { it('should return error with good but different seed words', async function () {
let createdAccounts = await primaryKeyring.getAccounts() const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 1) assert.equal(createdAccounts.length, 1)
let serialized = await primaryKeyring.serialize() await primaryKeyring.serialize()
let seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' const seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'
try { try {
let result = await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords) await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords)
assert.fail("Should reject") assert.fail('Should reject')
} catch (err) { } catch (err) {
assert.ok(err.message.indexOf('Not identical accounts!') >= 0, 'Wrong error message') assert.ok(err.message.indexOf('Not identical accounts!') >= 0, 'Wrong error message')
} }
@ -85,15 +84,15 @@ describe('SeedPhraseVerifier', function () {
it('should return error with undefined existing accounts', async function () { it('should return error with undefined existing accounts', async function () {
let createdAccounts = await primaryKeyring.getAccounts() const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 1) assert.equal(createdAccounts.length, 1)
let serialized = await primaryKeyring.serialize() await primaryKeyring.serialize()
let seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' const seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'
try { try {
let result = await seedPhraseVerifier.verifyAccounts(undefined, seedWords) await seedPhraseVerifier.verifyAccounts(undefined, seedWords)
assert.fail("Should reject") assert.fail('Should reject')
} catch (err) { } catch (err) {
assert.equal(err.message, 'No created accounts defined.') assert.equal(err.message, 'No created accounts defined.')
} }
@ -101,15 +100,15 @@ describe('SeedPhraseVerifier', function () {
it('should return error with empty accounts array', async function () { it('should return error with empty accounts array', async function () {
let createdAccounts = await primaryKeyring.getAccounts() const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 1) assert.equal(createdAccounts.length, 1)
let serialized = await primaryKeyring.serialize() await primaryKeyring.serialize()
let seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium' const seedWords = 'debris dizzy just program just float decrease vacant alarm reduce speak stadium'
try { try {
let result = await seedPhraseVerifier.verifyAccounts([], seedWords) await seedPhraseVerifier.verifyAccounts([], seedWords)
assert.fail("Should reject") assert.fail('Should reject')
} catch (err) { } catch (err) {
assert.equal(err.message, 'No created accounts defined.') assert.equal(err.message, 'No created accounts defined.')
} }
@ -117,17 +116,17 @@ describe('SeedPhraseVerifier', function () {
it('should be able to verify more than one created account with seed words', async function () { it('should be able to verify more than one created account with seed words', async function () {
const keyState = await keyringController.addNewAccount(primaryKeyring) await keyringController.addNewAccount(primaryKeyring)
const keyState2 = await keyringController.addNewAccount(primaryKeyring) await keyringController.addNewAccount(primaryKeyring)
let createdAccounts = await primaryKeyring.getAccounts() const createdAccounts = await primaryKeyring.getAccounts()
assert.equal(createdAccounts.length, 3) assert.equal(createdAccounts.length, 3)
let serialized = await primaryKeyring.serialize() const serialized = await primaryKeyring.serialize()
let seedWords = serialized.mnemonic const seedWords = serialized.mnemonic
assert.notEqual(seedWords.length, 0) assert.notEqual(seedWords.length, 0)
let result = await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords) await seedPhraseVerifier.verifyAccounts(createdAccounts, seedWords)
}) })
}) })
}) })

@ -38,4 +38,4 @@ describe('SufficientBalance', function () {
const result = sufficientBalance(tx, balance) const result = sufficientBalance(tx, balance)
assert.ok(!result, 'insufficient balance found.') assert.ok(!result, 'insufficient balance found.')
}) })
}) })

@ -8,7 +8,7 @@ const mockState = {
accounts: { abc: {} }, accounts: { abc: {} },
network: 1, network: 1,
selectedAddress: 'abc', selectedAddress: 'abc',
} },
} }
describe('BalanceComponent', function () { describe('BalanceComponent', function () {

@ -52,13 +52,13 @@ describe('BnInput', function () {
it('can tolerate wei precision', function (done) { it('can tolerate wei precision', function (done) {
const renderer = ReactTestUtils.createRenderer() const renderer = ReactTestUtils.createRenderer()
let valueStr = '1000000000' const valueStr = '1000000000'
const value = new BN(valueStr, 10) const value = new BN(valueStr, 10)
const inputStr = '1.000000001' const inputStr = '1.000000001'
let targetStr = '1000000001' const targetStr = '1000000001'
const target = new BN(targetStr, 10) const target = new BN(targetStr, 10)

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save