From a79b4db06a3f9cc76aa68049dafe2cd2caa564b4 Mon Sep 17 00:00:00 2001 From: tmashuang Date: Tue, 12 Sep 2017 14:14:24 -0700 Subject: [PATCH 001/246] E2E testing with selenium --- package.json | 4 +- test/e2e/func.js | 17 ++++++ test/e2e/metamask.spec.js | 124 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 test/e2e/func.js create mode 100644 test/e2e/metamask.spec.js diff --git a/package.json b/package.json index 12f79ba35..7a1c4b6d2 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dist": "npm run clear && npm install && gulp dist", "test": "npm run lint && npm run test-unit && npm run test-integration", "test-unit": "METAMASK_ENV=test mocha --require test/helper.js --recursive \"test/unit/**/*.js\"", + "test-e2e": "METAMASK_ENV=test mocha test/e2e/metamask.spec --recursive || true", "single-test": "METAMASK_ENV=test mocha --require test/helper.js", "test-integration": "npm run buildMock && npm run buildCiUnits && karma start", "test-coverage": "nyc npm run test-unit && if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi", @@ -167,7 +168,7 @@ "gulp-watch": "^4.3.5", "gulp-zip": "^4.0.0", "isomorphic-fetch": "^2.2.1", - "jsdom": "^11.1.0", + "jsdom": "^11.2.0", "jsdom-global": "^3.0.2", "jshint-stylish": "~2.2.1", "json-rpc-engine": "^3.0.1", @@ -190,6 +191,7 @@ "react-addons-test-utils": "^15.5.1", "react-test-renderer": "^15.5.4", "react-testutils-additions": "^15.2.0", + "selenium-webdriver": "^3.5.0", "sinon": "^3.2.0", "tape": "^4.5.1", "testem": "^1.10.3", diff --git a/test/e2e/func.js b/test/e2e/func.js new file mode 100644 index 000000000..50363ade3 --- /dev/null +++ b/test/e2e/func.js @@ -0,0 +1,17 @@ +const webdriver = require('selenium-webdriver') + +exports.delay = function delay (time) { + return new Promise(resolve => setTimeout(resolve, time)) +} + + +exports.buildWebDriver = function buildWebDriver (extPath) { + return new webdriver.Builder() + .withCapabilities({ + chromeOptions: { + args: [`load-extension=${extPath}`], + }, + }) + .forBrowser('chrome') + .build() +} diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js new file mode 100644 index 000000000..fc748fe18 --- /dev/null +++ b/test/e2e/metamask.spec.js @@ -0,0 +1,124 @@ +const path = require('path') +const assert = require('assert') +const webdriver = require('selenium-webdriver') +const By = webdriver.By +const { delay, buildWebDriver } = require('./func') + +describe('Metamask popup page', function () { + let driver + this.seedPhase + this.accountAddress + this.timeout(0) + + before(async function () { + const extPath = path.resolve('dist/chrome') + driver = buildWebDriver(extPath) + await driver.get('chrome://extensions-frame') + const elems = await driver.findElements(By.xpath( + '//*[@id="jepnlelaaflcpibhckpebdcijgfdfleo"]' + )) + const extensionId = await elems[0].getAttribute('id') + await driver.get(`chrome-extension://${extensionId}/popup.html`) + await delay(500) + }) + + after(async function () { + await driver.quit() + }) + + describe('#onboarding', () => { + it('should open Metamask.io', async function () { + const tabs = await driver.getAllWindowHandles() + await driver.switchTo().window(tabs[0]) + await delay(300) + }) + + it('should match title', async () => { + const title = await driver.getTitle() + assert.equal(title, 'MetaMask Plugin', 'title matches MetaMask Plugin') + }) + + it('should show privacy notice', async () => { + const privacy = await driver.findElement(By.className( + 'terms-header' + )).getText() + assert.equal(privacy, 'PRIVACY NOTICE', 'shows privacy notice') + driver.findElement(By.css( + 'button' + )).click() + }) + + it('should show terms of use', async () => { + await delay(300) + const terms = await driver.findElement(By.className( + 'terms-header' + )).getText() + assert.equal(terms, 'TERMS OF USE', 'shows terms of use') + }) + + it('should be unable to continue without scolling throught the terms of use', async () => { + const button = await driver.findElement(By.css( + 'button' + )).isEnabled() + assert.equal(button, false, 'disabled continue button') + const element = driver.findElement(By.linkText( + 'Attributions' + )) + await driver.executeScript('arguments[0].scrollIntoView(true)', element) + }) + + it('should be able to continue when scrolled to the bottom of terms of use', async () => { + const button = await driver.findElement(By.css('button')) + const buttonEnabled = await button.isEnabled() + await delay(500) + assert.equal(buttonEnabled, true, 'enabled continue button') + await button.click() + }) + + it('should accept password with length of eight', async () => { + await delay(300) + const passwordBox = await driver.findElement(By.id('password-box')) + const passwordBoxConfirm = driver.findElement(By.id('password-box-confirm')) + const button = driver.findElement(By.css('button')) + + passwordBox.sendKeys('12345678') + passwordBoxConfirm.sendKeys('12345678') + await delay(300) + await button.click() + }) + + it('should show value was created and seed phrase', async () => { + await delay(700) + this.seedPhase = await driver.findElement(By.className('twelve-word-phrase')).getText() + const continueAfterSeedPhrase = await driver.findElement(By.css('button')) + await continueAfterSeedPhrase.click() + }) + + it('should show lock account', async () => { + await delay(300) + await driver.findElement(By.className('sandwich-expando')).click() + await delay(500) + await driver.findElement(By.xpath('//*[@id="app-content"]/div/div[3]/span/div/li[2]')).click() + }) + + it('should accept account password after lock', async () => { + await delay(500) + await driver.findElement(By.id('password-box')).sendKeys('12345678') + await driver.findElement(By.css('button')).click() + await delay(500) + }) + + it('should show QR code', async () => { + await delay(300) + await driver.findElement(By.className('fa-ellipsis-h')).click() + await driver.findElement(By.xpath('//*[@id="app-content"]/div/div[4]/div/div/div[1]/flex-column/div[1]/div/span/i/div/div/li[2]')).click() + await delay(300) + }) + + it('should show the account address', async () => { + this.accountAddress = await driver.findElement(By.className('ellip-address')).getText() + await driver.findElement(By.className('fa-arrow-left')).click() + await delay(500) + }) + }) +}) From 0db4ba1086f56422752dd4b9e3754a273d23a866 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 18 Jan 2018 08:10:53 -0800 Subject: [PATCH 002/246] chromedriver, changed extension id(might need zip/crx file) --- package.json | 7 ++++--- test/e2e/func.js | 1 + test/e2e/metamask.spec.js | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 29fc4aa5a..c811c6bec 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "mascara": "METAMASK_DEBUG=true node ./mascara/example/server", "dist": "npm run dist:clear && npm install && gulp dist", "dist:clear": "rm -rf node_modules/eth-contract-metadata && rm -rf node_modules/eth-phishing-detect", - "test": "npm run lint && npm run test:coverage && npm run test:integration", + "test": "npm run lint && npm run test:coverage && npm run test:e2e", "test:unit": "METAMASK_ENV=test mocha --exit --compilers js:babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"", "test:single": "METAMASK_ENV=test mocha --require test/helper.js", "test:integration": "npm run test:flat && npm run test:mascara", @@ -169,6 +169,7 @@ "brfs": "^1.4.3", "browserify": "^14.4.0", "chai": "^4.1.0", + "chromedriver": "^2.34.1", "coveralls": "^3.0.0", "deep-freeze-strict": "^1.1.1", "del": "^3.0.0", @@ -179,6 +180,7 @@ "eth-json-rpc-middleware": "^1.2.7", "fs-promise": "^2.0.3", "gulp": "github:gulpjs/gulp#4.0", + "gulp-eslint": "^4.0.0", "gulp-if": "^2.0.1", "gulp-json-editor": "^2.2.1", "gulp-livereload": "^3.8.1", @@ -187,7 +189,6 @@ "gulp-util": "^3.0.7", "gulp-watch": "^4.3.5", "gulp-zip": "^4.0.0", - "gulp-eslint": "^4.0.0", "isomorphic-fetch": "^2.2.1", "jsdom": "^11.2.0", "jsdom-global": "^3.0.2", @@ -211,8 +212,8 @@ "react-addons-test-utils": "^15.5.1", "react-test-renderer": "^15.6.2", "react-testutils-additions": "^15.2.0", - "sinon": "^4.0.0", "selenium-webdriver": "^3.5.0", + "sinon": "^4.0.0", "tape": "^4.5.1", "testem": "^1.10.3", "uglifyify": "^4.0.2", diff --git a/test/e2e/func.js b/test/e2e/func.js index 50363ade3..733225565 100644 --- a/test/e2e/func.js +++ b/test/e2e/func.js @@ -1,3 +1,4 @@ +require('chromedriver') const webdriver = require('selenium-webdriver') exports.delay = function delay (time) { diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index fc748fe18..cf4cd0b52 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -15,7 +15,7 @@ describe('Metamask popup page', function () { driver = buildWebDriver(extPath) await driver.get('chrome://extensions-frame') const elems = await driver.findElements(By.xpath( - '//*[@id="jepnlelaaflcpibhckpebdcijgfdfleo"]' + '//*[@id="fmmjaglpijbgopejlfapbkhhbnaagbpj"]' )) const extensionId = await elems[0].getAttribute('id') await driver.get(`chrome-extension://${extensionId}/popup.html`) From c18f2a17fc86640ff3a91cb14b35a85888612a75 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 9 Mar 2018 23:57:03 -0800 Subject: [PATCH 003/246] Add selenium-webdriver and chromedriver --- package-lock.json | 175 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/package-lock.json b/package-lock.json index 55fa5c838..535a0f1eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2952,6 +2952,19 @@ "readdirp": "2.1.0" } }, + "chromedriver": { + "version": "2.36.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-2.36.0.tgz", + "integrity": "sha512-Lq2HrigCJ4RVdIdCmchenv1rVrejNSJ7EUCQojycQo12ww3FedQx4nb+GgTdqMhjbOMTqq5+ziaiZlrEN2z1gQ==", + "dev": true, + "requires": { + "del": "3.0.0", + "extract-zip": "1.6.6", + "kew": "0.7.0", + "mkdirp": "0.5.1", + "request": "2.83.0" + } + }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -4912,6 +4925,12 @@ "event-emitter": "0.3.5" } }, + "es6-promise": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", + "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", + "dev": true + }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", @@ -6305,6 +6324,35 @@ "is-extglob": "1.0.0" } }, + "extract-zip": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.6.tgz", + "integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=", + "dev": true, + "requires": { + "concat-stream": "1.6.0", + "debug": "2.6.9", + "mkdirp": "0.5.0", + "yauzl": "2.4.1" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + } + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -6413,6 +6461,15 @@ } } }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, + "requires": { + "pend": "1.2.0" + } + }, "fetch-ponyfill": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz", @@ -11082,6 +11139,47 @@ "array-includes": "3.0.3" } }, + "jszip": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.5.tgz", + "integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==", + "dev": true, + "requires": { + "core-js": "2.3.0", + "es6-promise": "3.0.2", + "lie": "3.1.1", + "pako": "1.0.6", + "readable-stream": "2.0.6" + }, + "dependencies": { + "core-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", + "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=", + "dev": true + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, "just-debounce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", @@ -11377,6 +11475,12 @@ "sha3": "1.2.0" } }, + "kew": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -11688,6 +11792,23 @@ "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=", "dev": true }, + "lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", + "dev": true, + "requires": { + "immediate": "3.0.6" + }, + "dependencies": { + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + } + } + }, "liftoff": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", @@ -16292,6 +16413,12 @@ "sha.js": "2.4.9" } }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, "percentile": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/percentile/-/percentile-1.2.0.tgz", @@ -18243,6 +18370,29 @@ "safe-buffer": "5.1.1" } }, + "selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "requires": { + "jszip": "3.1.5", + "rimraf": "2.6.2", + "tmp": "0.0.30", + "xml2js": "0.4.19" + }, + "dependencies": { + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + } + } + }, "semaphore": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/semaphore/-/semaphore-1.1.0.tgz", @@ -22155,6 +22305,22 @@ "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", "dev": true }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": "1.2.4", + "xmlbuilder": "9.0.7" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, "xmldom": { "version": "0.1.27", "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", @@ -22222,6 +22388,15 @@ "camelcase": "3.0.0" } }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, + "requires": { + "fd-slicer": "1.0.1" + } + }, "yazl": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.4.3.tgz", From a62fe4f7eae1c615c15c56109eb40874e811d25f Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 9 Mar 2018 23:57:44 -0800 Subject: [PATCH 004/246] Update selenium tests --- test/e2e/metamask.spec.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index cf4cd0b52..c73ba2b41 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -14,10 +14,8 @@ describe('Metamask popup page', function () { const extPath = path.resolve('dist/chrome') driver = buildWebDriver(extPath) await driver.get('chrome://extensions-frame') - const elems = await driver.findElements(By.xpath( - '//*[@id="fmmjaglpijbgopejlfapbkhhbnaagbpj"]' - )) - const extensionId = await elems[0].getAttribute('id') + const elems = await driver.findElements(By.className('extension-list-item-wrapper')) + const extensionId = await elems[1].getAttribute('id') await driver.get(`chrome-extension://${extensionId}/popup.html`) await delay(500) }) @@ -78,12 +76,12 @@ describe('Metamask popup page', function () { it('should accept password with length of eight', async () => { await delay(300) const passwordBox = await driver.findElement(By.id('password-box')) - const passwordBoxConfirm = driver.findElement(By.id('password-box-confirm')) + const passwordBoxConfirm = await driver.findElement(By.id('password-box-confirm')) const button = driver.findElement(By.css('button')) - passwordBox.sendKeys('12345678') - passwordBoxConfirm.sendKeys('12345678') - await delay(300) + passwordBox.sendKeys('123456789') + passwordBoxConfirm.sendKeys('123456789') + await delay(500) await button.click() }) @@ -103,7 +101,7 @@ describe('Metamask popup page', function () { it('should accept account password after lock', async () => { await delay(500) - await driver.findElement(By.id('password-box')).sendKeys('12345678') + await driver.findElement(By.id('password-box')).sendKeys('123456789') await driver.findElement(By.css('button')).click() await delay(500) }) From 34aeef50a0519576da64f23d65afdfbfa278273d Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 14 Mar 2018 16:31:45 -0700 Subject: [PATCH 005/246] i18n - load locales manually --- app/scripts/popup.js | 133 ++++++++++-------- package-lock.json | 10 ++ ui/app/accounts/import/index.js | 10 +- ui/app/accounts/import/json.js | 5 +- ui/app/accounts/import/private-key.js | 2 +- ui/app/accounts/import/seed.js | 2 +- ui/app/accounts/new-account/create-form.js | 4 +- ui/app/accounts/new-account/index.js | 2 +- ui/app/app.js | 2 +- ui/app/components/account-dropdowns.js | 1 - ui/app/components/account-export.js | 2 +- ui/app/components/account-menu/index.js | 2 +- ui/app/components/bn-as-decimal-input.js | 2 +- ui/app/components/coinbase-form.js | 2 +- ui/app/components/copyButton.js | 2 +- ui/app/components/copyable.js | 2 +- .../components/customize-gas-modal/index.js | 2 +- .../dropdowns/components/account-dropdowns.js | 3 +- .../components/dropdowns/network-dropdown.js | 3 +- .../dropdowns/token-menu-dropdown.js | 3 +- ui/app/components/ens-input.js | 2 +- .../modals/account-details-modal.js | 2 +- .../modals/account-modal-container.js | 2 +- ui/app/components/modals/buy-options-modal.js | 2 +- .../components/modals/deposit-ether-modal.js | 34 +++-- .../modals/edit-account-name-modal.js | 2 +- .../modals/export-private-key-modal.js | 2 +- .../modals/hide-token-confirmation-modal.js | 2 +- ui/app/components/modals/modal.js | 9 +- ui/app/components/modals/new-account-modal.js | 2 +- .../components/modals/notification-modal.js | 5 +- .../pending-tx/confirm-deploy-contract.js | 2 +- .../pending-tx/confirm-send-ether.js | 2 +- .../pending-tx/confirm-send-token.js | 2 +- ui/app/components/send-token/index.js | 2 +- ui/app/components/send/gas-fee-display-v2.js | 2 +- ui/app/components/send/gas-tooltip.js | 2 +- ui/app/components/send/to-autocomplete.js | 2 +- ui/create-i18n.js | 43 ++++++ 39 files changed, 197 insertions(+), 118 deletions(-) create mode 100644 ui/create-i18n.js diff --git a/app/scripts/popup.js b/app/scripts/popup.js index 11d50ee87..0677311da 100644 --- a/app/scripts/popup.js +++ b/app/scripts/popup.js @@ -1,3 +1,9 @@ +// setup i18n +const Translator = require('../../ui/create-i18n') +const translator = new Translator() +global.translator = translator +global.getMessage = translator.getMessage.bind(translator) + const injectCss = require('inject-css') const OldMetaMaskUiCss = require('../../old-ui/css') const NewMetaMaskUiCss = require('../../ui/css') @@ -10,68 +16,77 @@ const NotificationManager = require('./lib/notification-manager') const notificationManager = new NotificationManager() const setupRaven = require('./lib/setupRaven') -// create platform global -global.platform = new ExtensionPlatform() - -// setup sentry error reporting -const release = global.platform.getVersion() -setupRaven({ release }) - -// inject css -// const css = MetaMaskUiCss() -// injectCss(css) - -// identify window type (popup, notification) -const windowType = isPopupOrNotification() -global.METAMASK_UI_TYPE = windowType -closePopupIfOpen(windowType) - -// setup stream to background -const extensionPort = extension.runtime.connect({ name: windowType }) -const connectionStream = new PortStream(extensionPort) - -// start ui -const container = document.getElementById('app-content') -startPopup({ container, connectionStream }, (err, store) => { - if (err) return displayCriticalError(err) - - // Code commented out until we begin auto adding users to NewUI - // const { isMascara, identities = {}, featureFlags = {} } = store.getState().metamask - // const firstTime = Object.keys(identities).length === 0 - const { isMascara, featureFlags = {} } = store.getState().metamask - let betaUIState = featureFlags.betaUI - - // Code commented out until we begin auto adding users to NewUI - // const useBetaCss = isMascara || firstTime || betaUIState - const useBetaCss = isMascara || betaUIState - - let css = useBetaCss ? NewMetaMaskUiCss() : OldMetaMaskUiCss() - let deleteInjectedCss = injectCss(css) - let newBetaUIState - - store.subscribe(() => { - const state = store.getState() - newBetaUIState = state.metamask.featureFlags.betaUI - if (newBetaUIState !== betaUIState) { - deleteInjectedCss() - betaUIState = newBetaUIState - css = betaUIState ? NewMetaMaskUiCss() : OldMetaMaskUiCss() - deleteInjectedCss = injectCss(css) - } - if (state.appState.shouldClose) notificationManager.closePopup() +start().catch(log.error) + +async function start() { + + // create platform global + global.platform = new ExtensionPlatform() + + // setup sentry error reporting + const release = global.platform.getVersion() + setupRaven({ release }) + + // Load translator + await translator.setLocale('ja') + + // inject css + // const css = MetaMaskUiCss() + // injectCss(css) + + // identify window type (popup, notification) + const windowType = isPopupOrNotification() + global.METAMASK_UI_TYPE = windowType + closePopupIfOpen(windowType) + + // setup stream to background + const extensionPort = extension.runtime.connect({ name: windowType }) + const connectionStream = new PortStream(extensionPort) + + // start ui + const container = document.getElementById('app-content') + startPopup({ container, connectionStream }, (err, store) => { + if (err) return displayCriticalError(err) + + // Code commented out until we begin auto adding users to NewUI + // const { isMascara, identities = {}, featureFlags = {} } = store.getState().metamask + // const firstTime = Object.keys(identities).length === 0 + const { isMascara, featureFlags = {} } = store.getState().metamask + let betaUIState = featureFlags.betaUI + + // Code commented out until we begin auto adding users to NewUI + // const useBetaCss = isMascara || firstTime || betaUIState + const useBetaCss = isMascara || betaUIState + + let css = useBetaCss ? NewMetaMaskUiCss() : OldMetaMaskUiCss() + let deleteInjectedCss = injectCss(css) + let newBetaUIState + + store.subscribe(() => { + const state = store.getState() + newBetaUIState = state.metamask.featureFlags.betaUI + if (newBetaUIState !== betaUIState) { + deleteInjectedCss() + betaUIState = newBetaUIState + css = betaUIState ? NewMetaMaskUiCss() : OldMetaMaskUiCss() + deleteInjectedCss = injectCss(css) + } + if (state.appState.shouldClose) notificationManager.closePopup() + }) }) -}) -function closePopupIfOpen (windowType) { - if (windowType !== 'notification') { - notificationManager.closePopup() + function closePopupIfOpen (windowType) { + if (windowType !== 'notification') { + notificationManager.closePopup() + } + } + + function displayCriticalError (err) { + container.innerHTML = '
The MetaMask app failed to load: please open and close MetaMask again to restart.
' + container.style.height = '80px' + log.error(err.stack) + throw err } -} -function displayCriticalError (err) { - container.innerHTML = '
The MetaMask app failed to load: please open and close MetaMask again to restart.
' - container.style.height = '80px' - log.error(err.stack) - throw err } diff --git a/package-lock.json b/package-lock.json index bd3026816..d1c488b09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3929,6 +3929,16 @@ "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.1.0.tgz", "integrity": "sha512-ZQVKfRVlwRfD150ndzEK8M90ABT+Y/JQKs4Y7U4MXdpuoUkkrr4DwKbVux3YjylA5bUMUj0Nc3pMxPJX6N2QQQ==" }, + "debounce-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/debounce-stream/-/debounce-stream-2.0.0.tgz", + "integrity": "sha1-HjNADM/wFavY7DMGYaVitoQQsI8=", + "requires": { + "debounce": "1.1.0", + "duplexer": "0.1.1", + "through": "2.3.8" + } + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js index c1b190e3d..9c4a79bec 100644 --- a/ui/app/accounts/import/index.js +++ b/ui/app/accounts/import/index.js @@ -2,23 +2,21 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect -const t = require('../../../i18n') import Select from 'react-select' // Subviews const JsonImportView = require('./json.js') const PrivateKeyImportView = require('./private-key.js') -const menuItems = [ - t('privateKey'), - t('jsonFile'), -] module.exports = connect(mapStateToProps)(AccountImportSubview) function mapStateToProps (state) { return { - menuItems, + menuItems: [ + t('privateKey'), + t('jsonFile'), + ], } } diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index 1b5e485d7..187abcc6a 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -4,7 +4,8 @@ const h = require('react-hyperscript') const connect = require('react-redux').connect const actions = require('../../actions') const FileInput = require('react-simple-file-input').default -const t = require('../../../i18n') +const t = global.getMessage + const HELP_LINK = 'https://support.metamask.io/kb/article/7-importing-accounts' @@ -102,7 +103,7 @@ class JsonImportSubview extends Component { const message = t('needImportPassword') return this.props.displayWarning(message) } - + this.props.importNewJsonAccount([ fileContents, password ]) } } diff --git a/ui/app/accounts/import/private-key.js b/ui/app/accounts/import/private-key.js index bc9e9384e..01a43afba 100644 --- a/ui/app/accounts/import/private-key.js +++ b/ui/app/accounts/import/private-key.js @@ -3,7 +3,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect const actions = require('../../actions') -const t = require('../../../i18n') +const t = global.getMessage module.exports = connect(mapStateToProps, mapDispatchToProps)(PrivateKeyImportView) diff --git a/ui/app/accounts/import/seed.js b/ui/app/accounts/import/seed.js index 9ffc669a2..da70a9cb5 100644 --- a/ui/app/accounts/import/seed.js +++ b/ui/app/accounts/import/seed.js @@ -2,7 +2,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect -const t = require('../../../i18n') +const t = global.getMessage module.exports = connect(mapStateToProps)(SeedImportSubview) diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js index 8ef842a2a..78802d35a 100644 --- a/ui/app/accounts/new-account/create-form.js +++ b/ui/app/accounts/new-account/create-form.js @@ -3,7 +3,7 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const { connect } = require('react-redux') const actions = require('../../actions') -const t = require('../../../i18n') +const t = global.getMessage class NewAccountCreateForm extends Component { constructor (props) { @@ -20,7 +20,7 @@ class NewAccountCreateForm extends Component { render () { const { newAccountName, defaultAccountName } = this.state - + return h('div.new-account-create-form', [ diff --git a/ui/app/accounts/new-account/index.js b/ui/app/accounts/new-account/index.js index 854568c77..a4535ec83 100644 --- a/ui/app/accounts/new-account/index.js +++ b/ui/app/accounts/new-account/index.js @@ -3,7 +3,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') -const t = require('../../../i18n') +const t = global.getMessage const { getCurrentViewContext } = require('../../selectors') const classnames = require('classnames') diff --git a/ui/app/app.js b/ui/app/app.js index 9708a2485..f7fea0c22 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -4,7 +4,7 @@ const connect = require('react-redux').connect const h = require('react-hyperscript') const actions = require('./actions') const classnames = require('classnames') -const t = require('../i18n') +const t = global.getMessage // mascara const MascaraFirstTime = require('../../mascara/src/app/first-time').default diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index 1612d7b6a..500c794e3 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -9,7 +9,6 @@ const DropdownMenuItem = require('./dropdown').DropdownMenuItem const Identicon = require('./identicon') const ethUtil = require('ethereumjs-util') const copyToClipboard = require('copy-to-clipboard') -const t = require('../../i18n') class AccountDropdowns extends Component { constructor (props) { diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js index 5637bc8d0..41dc887a0 100644 --- a/ui/app/components/account-export.js +++ b/ui/app/components/account-export.js @@ -6,7 +6,7 @@ const copyToClipboard = require('copy-to-clipboard') const actions = require('../actions') const ethUtil = require('ethereumjs-util') const connect = require('react-redux').connect -const t = require('../../i18n') +const t = global.getMessage module.exports = connect(mapStateToProps)(ExportAccountView) diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js index e838e8916..09d002597 100644 --- a/ui/app/components/account-menu/index.js +++ b/ui/app/components/account-menu/index.js @@ -6,7 +6,7 @@ const actions = require('../../actions') const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu') const Identicon = require('../identicon') const { formatBalance } = require('../../util') -const t = require('../../../i18n') +const t = global.getMessage module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountMenu) diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js index 70701b039..2abdebeb9 100644 --- a/ui/app/components/bn-as-decimal-input.js +++ b/ui/app/components/bn-as-decimal-input.js @@ -4,7 +4,7 @@ const inherits = require('util').inherits const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const extend = require('xtend') -const t = require('../../i18n') +const t = global.getMessage module.exports = BnAsDecimalInput diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js index e442b43d5..b9ef143e6 100644 --- a/ui/app/components/coinbase-form.js +++ b/ui/app/components/coinbase-form.js @@ -3,7 +3,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../actions') -const t = require('../../i18n') +const t = global.getMessage module.exports = connect(mapStateToProps)(CoinbaseForm) diff --git a/ui/app/components/copyButton.js b/ui/app/components/copyButton.js index 355f78d45..610d5b6a8 100644 --- a/ui/app/components/copyButton.js +++ b/ui/app/components/copyButton.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const copyToClipboard = require('copy-to-clipboard') -const t = require('../../i18n') +const t = global.getMessage const Tooltip = require('./tooltip') diff --git a/ui/app/components/copyable.js b/ui/app/components/copyable.js index fca7d3863..e0bf66f7e 100644 --- a/ui/app/components/copyable.js +++ b/ui/app/components/copyable.js @@ -4,7 +4,7 @@ const inherits = require('util').inherits const Tooltip = require('./tooltip') const copyToClipboard = require('copy-to-clipboard') -const t = require('../../i18n') +const t = global.getMessage module.exports = Copyable diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index 920dfeab6..ac8f3b842 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -3,8 +3,8 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') -const t = require('../../../i18n') const GasModalCard = require('./gas-modal-card') +const t = global.getMessage const ethUtil = require('ethereumjs-util') diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index e5359c1d6..0cdc2c0ae 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -10,7 +10,8 @@ const Identicon = require('../../identicon') const ethUtil = require('ethereumjs-util') const copyToClipboard = require('copy-to-clipboard') const { formatBalance } = require('../../../util') -const t = require('../../../../i18n') +const t = global.getMessage + class AccountDropdowns extends Component { constructor (props) { diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index 5afe730c1..a7acc7bb9 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -6,8 +6,9 @@ const actions = require('../../actions') const Dropdown = require('./components/dropdown').Dropdown const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem const NetworkDropdownIcon = require('./components/network-dropdown-icon') -const t = require('../../../i18n') const R = require('ramda') +const t = global.getMessage + // classes from nodes of the toggle element. const notToggleElementClassnames = [ diff --git a/ui/app/components/dropdowns/token-menu-dropdown.js b/ui/app/components/dropdowns/token-menu-dropdown.js index a4f93b505..392f43c35 100644 --- a/ui/app/components/dropdowns/token-menu-dropdown.js +++ b/ui/app/components/dropdowns/token-menu-dropdown.js @@ -3,7 +3,8 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') -const t = require('../../../i18n') +const t = global.getMessage + module.exports = connect(null, mapDispatchToProps)(TokenMenuDropdown) diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index add67ea35..4f6b3afe4 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -8,7 +8,7 @@ const ENS = require('ethjs-ens') const networkMap = require('ethjs-ens/lib/network-map.json') const ensRE = /.+\..+$/ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' -const t = require('../../i18n') +const t = global.getMessage module.exports = EnsInput diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js index 75f989e86..c6a3111b1 100644 --- a/ui/app/components/modals/account-details-modal.js +++ b/ui/app/components/modals/account-details-modal.js @@ -8,7 +8,7 @@ const { getSelectedIdentity } = require('../../selectors') const genAccountLink = require('../../../lib/account-link.js') const QrView = require('../qr-code') const EditableLabel = require('../editable-label') -const t = require('../../../i18n') +const t = global.getMessage function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js index 08540aa76..964677244 100644 --- a/ui/app/components/modals/account-modal-container.js +++ b/ui/app/components/modals/account-modal-container.js @@ -5,7 +5,7 @@ const connect = require('react-redux').connect const actions = require('../../actions') const { getSelectedIdentity } = require('../../selectors') const Identicon = require('../identicon') -const t = require('../../../i18n') +const t = global.getMessage function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/buy-options-modal.js b/ui/app/components/modals/buy-options-modal.js index 7eb73c3a6..33f8f6682 100644 --- a/ui/app/components/modals/buy-options-modal.js +++ b/ui/app/components/modals/buy-options-modal.js @@ -4,7 +4,7 @@ const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames -const t = require('../../../i18n') +const t = global.getMessage function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index 26ff3ea03..03304207e 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -5,15 +5,16 @@ const connect = require('react-redux').connect const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames const ShapeshiftForm = require('../shapeshift-form') -const t = require('../../../i18n') - -const DIRECT_DEPOSIT_ROW_TITLE = t('directDepositEther') -const DIRECT_DEPOSIT_ROW_TEXT = t('directDepositEtherExplainer') -const COINBASE_ROW_TITLE = t('buyCoinbase') -const COINBASE_ROW_TEXT = t('buyCoinbaseExplainer') -const SHAPESHIFT_ROW_TITLE = t('depositShapeShift') -const SHAPESHIFT_ROW_TEXT = t('depositShapeShiftExplainer') -const FAUCET_ROW_TITLE = t('testFaucet') +const t = global.getMessage + +let DIRECT_DEPOSIT_ROW_TITLE +let DIRECT_DEPOSIT_ROW_TEXT +let COINBASE_ROW_TITLE +let COINBASE_ROW_TEXT +let SHAPESHIFT_ROW_TITLE +let SHAPESHIFT_ROW_TEXT +let FAUCET_ROW_TITLE + const facuetRowText = (networkName) => { return t('getEtherFromFaucet', [networkName]) } @@ -47,6 +48,15 @@ inherits(DepositEtherModal, Component) function DepositEtherModal () { Component.call(this) + // need to set after i18n locale has loaded + DIRECT_DEPOSIT_ROW_TITLE = t('directDepositEther') + DIRECT_DEPOSIT_ROW_TEXT = t('directDepositEtherExplainer') + COINBASE_ROW_TITLE = t('buyCoinbase') + COINBASE_ROW_TEXT = t('buyCoinbaseExplainer') + SHAPESHIFT_ROW_TITLE = t('depositShapeShift') + SHAPESHIFT_ROW_TEXT = t('depositShapeShiftExplainer') + FAUCET_ROW_TITLE = t('testFaucet') + this.state = { buyingWithShapeshift: false, } @@ -128,9 +138,9 @@ DepositEtherModal.prototype.render = function () { }), ]), - + h('.page-container__content', {}, [ - + h('div.deposit-ether-modal__buy-rows', [ this.renderRow({ @@ -164,7 +174,7 @@ DepositEtherModal.prototype.render = function () { onButtonClick: () => toCoinbase(address), hide: isTestNetwork || buyingWithShapeshift, }), - + this.renderRow({ logo: h('div.deposit-ether-modal__logo', { style: { diff --git a/ui/app/components/modals/edit-account-name-modal.js b/ui/app/components/modals/edit-account-name-modal.js index 6efa8d476..79d6109cc 100644 --- a/ui/app/components/modals/edit-account-name-modal.js +++ b/ui/app/components/modals/edit-account-name-modal.js @@ -4,7 +4,7 @@ const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const { getSelectedAccount } = require('../../selectors') -const t = require('../../../i18n') +const t = global.getMessage function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js index 017177cfd..3fc93b4f5 100644 --- a/ui/app/components/modals/export-private-key-modal.js +++ b/ui/app/components/modals/export-private-key-modal.js @@ -7,7 +7,7 @@ const actions = require('../../actions') const AccountModalContainer = require('./account-modal-container') const { getSelectedIdentity } = require('../../selectors') const ReadOnlyInput = require('../readonly-input') -const t = require('../../../i18n') +const t = global.getMessage const copyToClipboard = require('copy-to-clipboard') function mapStateToProps (state) { diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js index 33d8062c6..efd472cf3 100644 --- a/ui/app/components/modals/hide-token-confirmation-modal.js +++ b/ui/app/components/modals/hide-token-confirmation-modal.js @@ -4,7 +4,7 @@ const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const Identicon = require('../identicon') -const t = require('../../../i18n') +const t = global.getMessage function mapStateToProps (state) { return { diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index 501b83430..9250cc77e 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -6,7 +6,6 @@ const FadeModal = require('boron').FadeModal const actions = require('../../actions') const isMobileView = require('../../../lib/is-mobile-view') const isPopupOrNotification = require('../../../../app/scripts/lib/is-popup-or-notification') -const t = require('../../../i18n') // Modal Components const BuyOptions = require('./buy-options-modal') @@ -174,8 +173,8 @@ const MODALS = { BETA_UI_NOTIFICATION_MODAL: { contents: [ h(NotifcationModal, { - header: t('uiWelcome'), - message: t('uiWelcomeMessage'), + header: 'uiWelcome', + message: 'uiWelcomeMessage', }), ], mobileModalStyle: { @@ -191,8 +190,8 @@ const MODALS = { OLD_UI_NOTIFICATION_MODAL: { contents: [ h(NotifcationModal, { - header: t('oldUI'), - message: t('oldUIMessage'), + header: 'oldUI', + message: 'oldUIMessage', }), ], mobileModalStyle: { diff --git a/ui/app/components/modals/new-account-modal.js b/ui/app/components/modals/new-account-modal.js index 298b76af4..7fe367f3f 100644 --- a/ui/app/components/modals/new-account-modal.js +++ b/ui/app/components/modals/new-account-modal.js @@ -3,7 +3,7 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const { connect } = require('react-redux') const actions = require('../../actions') -const t = require('../../../i18n') +const t = global.getMessage class NewAccountModal extends Component { constructor (props) { diff --git a/ui/app/components/modals/notification-modal.js b/ui/app/components/modals/notification-modal.js index 621a974d0..071d7ffd5 100644 --- a/ui/app/components/modals/notification-modal.js +++ b/ui/app/components/modals/notification-modal.js @@ -3,6 +3,7 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const { connect } = require('react-redux') const actions = require('../../actions') +const t = global.getMessage class NotificationModal extends Component { render () { @@ -22,12 +23,12 @@ class NotificationModal extends Component { }, [ h('div.notification-modal__header', {}, [ - header, + t(header), ]), h('div.notification-modal__message-wrapper', {}, [ h('div.notification-modal__message', {}, [ - message, + t(message), ]), ]), diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index 49fbe6387..b6bfb9afe 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -9,7 +9,7 @@ const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const hexToBn = require('../../../../app/scripts/lib/hex-to-bn') const { conversionUtil } = require('../../conversion-util') -const t = require('../../../i18n') +const t = global.getMessage const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index 4d4732bdb..7e1b25bb7 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -9,7 +9,7 @@ const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const hexToBn = require('../../../../app/scripts/lib/hex-to-bn') const { conversionUtil, addCurrencies } = require('../../conversion-util') -const t = require('../../../i18n') +const t = global.getMessage const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index 69afa8094..3a7678aa3 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -6,7 +6,7 @@ const tokenAbi = require('human-standard-token-abi') const abiDecoder = require('abi-decoder') abiDecoder.addABI(tokenAbi) const actions = require('../../actions') -const t = require('../../../i18n') +const t = global.getMessage const clone = require('clone') const Identicon = require('../identicon') const ethUtil = require('ethereumjs-util') diff --git a/ui/app/components/send-token/index.js b/ui/app/components/send-token/index.js index 58743b641..4519f469b 100644 --- a/ui/app/components/send-token/index.js +++ b/ui/app/components/send-token/index.js @@ -7,7 +7,7 @@ const inherits = require('util').inherits const actions = require('../../actions') const selectors = require('../../selectors') const { isValidAddress, allNull } = require('../../util') -const t = require('../../../i18n') +const t = global.getMessage // const BalanceComponent = require('./balance-component') const Identicon = require('../identicon') diff --git a/ui/app/components/send/gas-fee-display-v2.js b/ui/app/components/send/gas-fee-display-v2.js index 0c6f76303..2aaa43350 100644 --- a/ui/app/components/send/gas-fee-display-v2.js +++ b/ui/app/components/send/gas-fee-display-v2.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const CurrencyDisplay = require('./currency-display') -const t = require('../../../i18n') +const t = global.getMessage module.exports = GasFeeDisplay diff --git a/ui/app/components/send/gas-tooltip.js b/ui/app/components/send/gas-tooltip.js index d925d3ed8..246c25152 100644 --- a/ui/app/components/send/gas-tooltip.js +++ b/ui/app/components/send/gas-tooltip.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const InputNumber = require('../input-number.js') -const t = require('../../../i18n') +const t = global.getMessage module.exports = GasTooltip diff --git a/ui/app/components/send/to-autocomplete.js b/ui/app/components/send/to-autocomplete.js index 72074229e..1b0a1064a 100644 --- a/ui/app/components/send/to-autocomplete.js +++ b/ui/app/components/send/to-autocomplete.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const AccountListItem = require('./account-list-item') -const t = require('../../../i18n') +const t = global.getMessage module.exports = ToAutoComplete diff --git a/ui/create-i18n.js b/ui/create-i18n.js new file mode 100644 index 000000000..c80f5351a --- /dev/null +++ b/ui/create-i18n.js @@ -0,0 +1,43 @@ +// cross-browser connection to extension i18n API +const extension = require('extensionizer') +const log = require('loglevel') + + +class Translator { + + async setLocale(localeName) { + this.localeName = localeName + this.locale = await fetchLocale(localeName) + } + + getMessage (key, substitutions) { + // check locale is loaded + if (!this.locale) { + throw new Error('Translator - has not loaded a locale yet') + } + // check entry is present + const entry = this.locale[key] + if (!entry) { + log.error(`Translator - Unable to find value for "${key}"`) + throw new Error(`Translator - Unable to find value for "${key}"`) + } + let phrase = entry.message + // perform substitutions + if (substitutions && substitutions.length) { + phrase = phrase.replace(/\$1/g, substitutions[0]) + if (substitutions.length > 1) { + phrase = phrase.replace(/\$2/g, substitutions[1]) + } + } + return phrase + } + +} + +async function fetchLocale (localeName) { + const response = await fetch(`/_locales/${localeName}/messages.json`) + const locale = await response.json() + return locale +} + +module.exports = Translator From e781ba2c55be14e7332c7a471560b203bf8e2125 Mon Sep 17 00:00:00 2001 From: Mami Mordovets Date: Wed, 14 Mar 2018 14:33:26 +0900 Subject: [PATCH 006/246] Translation to Japanese --- app/_locales/ja/messages.json | 605 +++++++++++++++++++++++++++++++++- 1 file changed, 602 insertions(+), 3 deletions(-) diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index f15d06ff4..bab8d3b95 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -1,10 +1,609 @@ { + "accept": { + "message": "承認" + }, + "account": { + "message": "アカウント" + }, + "accountDetails": { + "message": "アカウント詳細" + }, + "accountName": { + "message": "アカウント名" + }, + "address": { + "message": "アドレス" + }, + "addToken": { + "message": "トークンを追加" + }, + "amount": { + "message": "金額" + }, + "amountPlusGas": { + "message": "金額 + ガス" + }, + "appDescription": { + "message": "Ethereumのブラウザ・エクステンション", + "description": "The description of the application" + }, "appName": { "message": "MetaMask", "description": "The name of the application" }, - "appDescription": { - "message": "EthereumのID管理", - "description": "The description of the application" + "attemptingConnect": { + "message": "ブロックチェーンに接続中" + }, + "available": { + "message": "有効" + }, + "back": { + "message": "戻る" + }, + "balance": { + "message": "残高:" + }, + "balanceIsInsufficientGas": { + "message": "現在のガス総量に対して残高が不足しています" + }, + "beta": { + "message": "ベータ版" + }, + "betweenMinAndMax": { + "message": " $1以上 $2以下にして下さい。", + "description": "helper for inputting hex as decimal input" + }, + "borrowDharma": { + "message": "Dharmaで借りる(ベータ版)" + }, + "buy": { + "message": "購入" + }, + "buyCoinbase": { + "message": "Coinbaseで購入" + }, + "buyCoinbaseExplainer": { + "message": "Coinbaseは、世界で最もポピュラーなBitcoin、Ethereum、そしてLitecoinの取引所です。" + }, + "cancel": { + "message": "キャンセル" + }, + "clickCopy": { + "message": "クリックしてコピー" + }, + "confirm": { + "message": "確認" + }, + "confirmContract": { + "message": "コントラクトの確認" + }, + "confirmPassword": { + "message": "パスワードの確認" + }, + "confirmTransaction": { + "message": "トランザクションの確認" + }, + "continueToCoinbase": { + "message": "Coinbaseで続行" + }, + "contractDeployment": { + "message": "コントラクトのデプロイ" + }, + "conversionProgress": { + "message": "変換中" + }, + "copiedButton": { + "message": "コピー完了" + }, + "copiedClipboard": { + "message": "クリップボードへコピー済み" + }, + "copiedExclamation": { + "message": "コピー完了!" + }, + "copy": { + "message": "コピー" + }, + "copyToClipboard": { + "message": "クリップボードへコピー" + }, + "copyButton": { + "message": " コピー " + }, + "copyPrivateKey": { + "message": "これはあなたの秘密鍵です(クリックでコピー)" + }, + "create": { + "message": "作成" + }, + "createAccount": { + "message": "アカウント作成" + }, + "createDen": { + "message": "作成" + }, + "crypto": { + "message": "暗号通貨", + "description": "Exchange type (cryptocurrencies)" + }, + "customGas": { + "message": "ガスのカスタマイズ" + }, + "customize": { + "message": "カスタマイズ" + }, + "customRPC": { + "message": "カスタムRPC" + }, + "defaultNetwork": { + "message": "Etherトランザクションのデフォルトのネットワークはメインネットです。" + }, + "denExplainer": { + "message": "DENとは、あなたのパスワードが暗号化されたMetaMask内のストレージです。" + }, + "deposit": { + "message": "デポジット" + }, + "depositBTC": { + "message": "あなたのBTCを次のアドレスへデポジット:" + }, + "depositCoin": { + "message": "あなたの $1を次のアドレスへデポジット", + "description": "Tells the user what coin they have selected to deposit with shapeshift" + }, + "depositEth": { + "message": "ETHをデポジット" + }, + "depositEther": { + "message": "Etherをデポジット" + }, + "depositFiat": { + "message": "法定通貨でデポジット" + }, + "depositFromAccount": { + "message": "別のアカウントからデポジット" + }, + "depositShapeShift": { + "message": "ShapeShiftでデポジット" + }, + "depositShapeShiftExplainer": { + "message": "あなたが他の暗号通貨を持っているなら、Etherにトレードしてダイレクトにメタマスクウォレットへのデポジットが可能です。アカウント作成は不要。" + }, + "details": { + "message": "詳細" + }, + "directDeposit": { + "message": "ダイレクトデポジット" + }, + "directDepositEther": { + "message": "Etherをダイレクトデポジット" + }, + "directDepositEtherExplainer": { + "message": "あなたがEtherをすでにお持ちなら、ダイレクトデポジットは新しいウォレットにEtherを入手する最も迅速な方法です。" + }, + "done": { + "message": "完了" + }, + "edit": { + "message": "編集" + }, + "editAccountName": { + "message": "アカウント名を編集" + }, + "encryptNewDen": { + "message": "新しいDENを暗号化する" + }, + "enterPassword": { + "message": "パスワードを入力" + }, + "etherscanView": { + "message": "Etherscanでアカウントを見る" + }, + "exchangeRate": { + "message": "交換レート" + }, + "exportPrivateKey": { + "message": "秘密鍵のエクスポート" + }, + "exportPrivateKeyWarning": { + "message": "あなた自身の責任で秘密鍵をエクスポート" + }, + "failed": { + "message": "失敗" + }, + "fiat": { + "message": "法定通貨", + "description": "Exchange type" + }, + "fileImportFail": { + "message": "ファイルがインポートされなければ、ここをクリック!", + "description": "Helps user import their account from a JSON file" + }, + "from": { + "message": "送信元" + }, + "fromShapeShift": { + "message": "ShapeShiftから" + }, + "gas": { + "message": "ガス", + "description": "Short indication of gas cost" + }, + "gasFee": { + "message": "ガス料金" + }, + "gasLimit": { + "message": "ガスリミット" + }, + "gasLimitCalculation": { + "message": "ネットワークの成功率を基にして、ガスリミットを提案しています。" + }, + "gasLimitRequired": { + "message": "必要ガスリミット" + }, + "gasLimitTooLow": { + "message": "ガスリミットは最低21000です。" + }, + "gasPrice": { + "message": "ガスプライス (GWEI)" + }, + "gasPriceCalculation": { + "message": "ネットワークの成功率を基にして、ガスプライスを提案しています。" + }, + "gasPriceRequired": { + "message": "必要ガスプライス" + }, + "getEther": { + "message": "Etherをゲット" + }, + "getEtherFromFaucet": { + "message": "フォーセットで $1のEtherをゲット", + "description": "Displays network name for Ether faucet" + }, + "greaterThanMin": { + "message": " $1以上にして下さい。", + "description": "helper for inputting hex as decimal input" + }, + "here": { + "message": "ここ", + "description": "as in -click here- for more information (goes with troubleTokenBalances)" + }, + "hide": { + "message": "隠す" + }, + "hideToken": { + "message": "トークンを隠す" + }, + "hideTokenPrompt": { + "message": "トークンを隠しますか??" + }, + "howToDeposit": { + "message": "どのようにEtherをデポジットしますか?" + }, + "import": { + "message": "インポート", + "description": "Button to import an account from a selected file" + }, + "importAccount": { + "message": "アカウントのインポート" + }, + "importAnAccount": { + "message": "アカウントをインポート" + }, + "importDen": { + "message": "既存のDENをインポート" + }, + "imported": { + "message": "インポート完了", + "description": "status showing that an account has been fully loaded into the keyring" + }, + "infoHelp": { + "message": "インフォメーションとヘルプ" + }, + "invalidAddress": { + "message": "アドレスが無効です。" + }, + "invalidGasParams": { + "message": "ガスのパラメーターが無効です。" + }, + "invalidInput": { + "message": "インプットが無効です。" + }, + "invalidRequest": { + "message": "リクエストが無効です。" + }, + "jsonFile": { + "message": "JSONファイル", + "description": "format for importing an account" + }, + "kovan": { + "message": "Kovanテストネットワーク" + }, + "lessThanMax": { + "message": " $1以下にして下さい。", + "description": "helper for inputting hex as decimal input" + }, + "limit": { + "message": "リミット" + }, + "loading": { + "message": "ロード中..." + }, + "loadingTokens": { + "message": "トークンをロード中..." + }, + "localhost": { + "message": "Localhost 8545" + }, + "logout": { + "message": "ログアウト" + }, + "loose": { + "message": "外部秘密鍵" + }, + "mainnet": { + "message": "Ethereumメインネットワーク" + }, + "message": { + "message": "メッセージ" + }, + "min": { + "message": "ミニマム" + }, + "myAccounts": { + "message": "マイアカウント" + }, + "needEtherInWallet": { + "message": "MetaMaskを使って分散型アプリケーションと対話するためには、あなたのウォレットにEtherが必要になります。" + }, + "needImportFile": { + "message": "インポートするファイルを選択してください。", + "description": "User is important an account and needs to add a file to continue" + }, + "needImportPassword": { + "message": "選択したファイルのパスワードを入力してください。", + "description": "Password and file needed to import an account" + }, + "networks": { + "message": "ネットワーク" + }, + "newAccount": { + "message": "新規アカウント" + }, + "newAccountNumberName": { + "message": "アカウント $1", + "description": "Default name of next account to be created on create account screen" + }, + "newContract": { + "message": "新規コントラクト" + }, + "newPassword": { + "message": "新規パスワード(最低8文字)" + }, + "newRecipient": { + "message": "新規受取人" + }, + "next": { + "message": "次へ" + }, + "noAddressForName": { + "message": "この名前にはアドレスが設定されていません。" + }, + "noDeposits": { + "message": "デポジットがありません。" + }, + "noTransactionHistory": { + "message": "トランザクション履歴がありません。" + }, + "noTransactions": { + "message": "トランザクションがありません。" + }, + "notStarted": { + "message": "スタートしていません。" + }, + "oldUI": { + "message": "旧UI" + }, + "oldUIMessage": { + "message": "旧UIを表示しています。右上のドロップダウンメニューのオプションより、新UIへ切り替えが可能です。" + }, + "or": { + "message": "または", + "description": "choice between creating or importing a new account" + }, + "passwordMismatch": { + "message": "パスワードが一致しません。", + "description": "in password creation process, the two new password fields did not match" + }, + "passwordShort": { + "message": "パスワードが短すぎます。", + "description": "in password creation process, the password is not long enough to be secure" + }, + "pastePrivateKey": { + "message": "秘密鍵をここにペーストして下さい:", + "description": "For importing an account from a private key" + }, + "pasteSeed": { + "message": "シードをここにペーストして下さい!" + }, + "pleaseReviewTransaction": { + "message": "トランザクションをレビューして下さい。" + }, + "privateKey": { + "message": "秘密鍵", + "description": "select this type of file to use to import an account" + }, + "privateKeyWarning": { + "message": "警告: この鍵は絶対に公開しないで下さい。公開すると、誰でもあなたのアカウント内の資産を盗むことができてしまいます。" + }, + "privateNetwork": { + "message": "プライベート・ネットワーク" + }, + "qrCode": { + "message": "QRコードを表示" + }, + "readdToken": { + "message": "アカウントのオプションメニューから「トークンを追加」すれば、将来このトークンを追加し直すことができます。" + }, + "readMore": { + "message": "もっと読む" + }, + "receive": { + "message": "受け取る" + }, + "recipientAddress": { + "message": "受取人アドレス" + }, + "refundAddress": { + "message": "あなたの返金先アドレス" + }, + "rejected": { + "message": "拒否されました" + }, + "required": { + "message": "必要です。" + }, + "retryWithMoreGas": { + "message": "より高いガスプライスで再度試して下さい。" + }, + "revert": { + "message": "元に戻す" + }, + "rinkeby": { + "message": "Rinkebyテストネットワーク" + }, + "ropsten": { + "message": "Ropstenテストネットワーク" + }, + "sampleAccountName": { + "message": "例.新しいマイアカウント", + "description": "Help user understand concept of adding a human-readable name to their account" + }, + "save": { + "message": "保存" + }, + "saveAsFile": { + "message": "ファイルとして保存", + "description": "Account export process" + }, + "selectService": { + "message": "サービスを選択" + }, + "send": { + "message": "送信" + }, + "sendTokens": { + "message": "トークンを送る" + }, + "sendTokensAnywhere": { + "message": "イーサリアムのアカウントを持っている人にトークンを送る" + }, + "settings": { + "message": "設定" + }, + "shapeshiftBuy": { + "message": "Shapeshiftで買う" + }, + "showPrivateKeys": { + "message": "秘密鍵を表示" + }, + "showQRCode": { + "message": "QRコードを表示" + }, + "sign": { + "message": "署名" + }, + "signMessage": { + "message": "メッセージに署名" + }, + "signNotice": { + "message": "このメッセージへの署名は危険となる可能性があります。\n完全に信頼するサイトからのメッセージのみ、\nあなたのアカウントで署名して下さい。今後のバージョンでは、\nこの危険なメソッドは削除される予定です。" + }, + "sigRequest": { + "message": "署名リクエスト" + }, + "sigRequested": { + "message": "署名がリクエストされました" + }, + "status": { + "message": "ステータス" + }, + "submit": { + "message": "送信" + }, + "takesTooLong": { + "message": "長くかかりすぎていますか?" + }, + "testFaucet": { + "message": "Faucetをテスト" + }, + "to": { + "message": "宛先" + }, + "toETHviaShapeShift": { + "message": "ShapeShiftで $1をETHにする", + "description": "system will fill in deposit type in start of message" + }, + "tokenBalance": { + "message": "あなたのトークン残高:" + }, + "total": { + "message": "合計" + }, + "transactionMemo": { + "message": "トランザクションメモ (オプション)" + }, + "transactionNumber": { + "message": "トランザクション番号" + }, + "transfers": { + "message": "トランスファー" + }, + "troubleTokenBalances": { + "message": "トークン残高を取得できません。こちらでご確認ください。", + "description": "Followed by a link (here) to view token balances" + }, + "typePassword": { + "message": "パスワードタイプ" + }, + "uiWelcome": { + "message": "新UIへようこそ!(ベータ版)" + }, + "uiWelcomeMessage": { + "message": "現在Metamaskの新しいUIをお使いになっています。トークン送信など、新たな機能を試してみましょう!何か問題があればご報告ください。" + }, + "unavailable": { + "message": "有効ではありません。" + }, + "unknown": { + "message": "不明" + }, + "unknownNetwork": { + "message": "不明なプライベートネットワーク" + }, + "unknownNetworkId": { + "message": "不明なネットワークID" + }, + "usaOnly": { + "message": "米国居住者のみ", + "description": "Using this exchange is limited to people inside the USA" + }, + "usedByClients": { + "message": "様々なクライアントによって使用されています。" + }, + "viewAccount": { + "message": "アカウントを見る" + }, + "warning": { + "message": "警告" + }, + "whatsThis": { + "message": "これは何でしょう?" + }, + "yourSigRequested": { + "message": "あなたの署名がリクエストされています。" + }, + "youSign": { + "message": "署名しています。" } } From eb5a84975b490664aa6238be6ceab3d4749167ee Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 14 Mar 2018 17:11:41 -0700 Subject: [PATCH 007/246] ui - settings - add option to set current locale --- ui/app/settings.js | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/ui/app/settings.js b/ui/app/settings.js index 466f739d5..95b69e46e 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -25,6 +25,23 @@ const getInfuraCurrencyOptions = () => { }) } +const locales = [ + { name: 'English', code: 'en' }, + { name: 'Japanese', code: 'ja' }, + { name: 'French', code: 'fr' }, + { name: 'Spanish', code: 'es' }, +] + +const getLocaleOptions = () => { + return locales.map((locale) => { + return { + displayValue: `${locale.name}`, + key: locale.code, + value: locale.code, + } + }) +} + class Settings extends Component { constructor (props) { super(props) @@ -94,6 +111,33 @@ class Settings extends Component { ]) } + renderCurrentLocale () { + const { setCurrentLocale } = this.props + const currentLocaleName = global.translator.localeName + const currentLocale = locales.find(locale => locale.code === currentLocaleName) + + return h('div.settings__content-row', [ + h('div.settings__content-item', [ + h('span', 'Current Language'), + h('span.settings__content-description', `${currentLocale.name}`), + ]), + h('div.settings__content-item', [ + h('div.settings__content-item-col', [ + h(SimpleDropdown, { + placeholder: 'Select Locale', + options: getLocaleOptions(), + selectedOption: currentLocaleName, + onSelect: async (newLocale) => { + log('set new locale', newLocale) + await global.translator.setLocale(newLocale) + log('did set new locale', newLocale) + }, + }), + ]), + ]), + ]) + } + renderCurrentProvider () { const { metamask: { provider = {} } } = this.props let title, value, color @@ -281,6 +325,7 @@ class Settings extends Component { h('div.settings__content', [ warning && h('div.settings__error', warning), this.renderCurrentConversion(), + this.renderCurrentLocale(), // this.renderCurrentProvider(), this.renderNewRpcUrl(), this.renderStateLogs(), From 5fe0be722b6514692a68e920ee8058c5d572237d Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 15 Mar 2018 21:59:45 -0230 Subject: [PATCH 008/246] Handle i18n with redux. --- app/scripts/controllers/preferences.js | 5 +++ app/scripts/metamask-controller.js | 10 +++++ app/scripts/popup-core.js | 4 +- app/scripts/popup.js | 14 +++--- ui/app/account-detail.js | 2 +- ui/app/accounts/import/index.js | 10 ++--- ui/app/accounts/import/json.js | 18 ++++---- ui/app/accounts/import/private-key.js | 10 ++--- ui/app/accounts/import/seed.js | 8 ++-- ui/app/accounts/new-account/create-form.js | 12 +++--- ui/app/accounts/new-account/index.js | 10 ++--- ui/app/actions.js | 43 ++++++++++++++++++- ui/app/add-token.js | 2 +- ui/app/app.js | 8 ++-- ui/app/components/account-dropdowns.js | 16 +++---- ui/app/components/account-export.js | 18 ++++---- ui/app/components/account-menu/index.js | 18 ++++---- ui/app/components/balance-component.js | 2 +- ui/app/components/bn-as-decimal-input.js | 10 ++--- ui/app/components/buy-button-subview.js | 14 +++--- ui/app/components/coinbase-form.js | 8 ++-- ui/app/components/copyButton.js | 4 +- ui/app/components/copyable.js | 4 +- .../components/customize-gas-modal/index.js | 18 ++++---- .../dropdowns/components/account-dropdowns.js | 22 +++++----- .../components/dropdowns/network-dropdown.js | 30 ++++++------- .../dropdowns/token-menu-dropdown.js | 6 +-- ui/app/components/ens-input.js | 6 +-- ui/app/components/hex-as-decimal-input.js | 10 ++--- ui/app/components/identicon.js | 2 +- .../modals/account-details-modal.js | 8 ++-- .../modals/account-modal-container.js | 6 +-- ui/app/components/modals/buy-options-modal.js | 18 ++++---- .../components/modals/deposit-ether-modal.js | 30 ++++++------- .../modals/edit-account-name-modal.js | 6 +-- .../modals/export-private-key-modal.js | 16 +++---- .../modals/hide-token-confirmation-modal.js | 12 +++--- ui/app/components/modals/modal.js | 2 +- ui/app/components/modals/new-account-modal.js | 14 +++--- .../components/modals/notification-modal.js | 2 +- .../modals/shapeshift-deposit-tx-modal.js | 2 +- ui/app/components/network.js | 26 +++++------ ui/app/components/notice.js | 4 +- ui/app/components/pending-msg-details.js | 4 +- ui/app/components/pending-msg.js | 12 +++--- .../pending-personal-msg-details.js | 4 +- .../pending-tx/confirm-deploy-contract.js | 24 +++++------ .../pending-tx/confirm-send-ether.js | 18 ++++---- .../pending-tx/confirm-send-token.js | 30 ++++++------- .../components/pending-typed-msg-details.js | 4 +- ui/app/components/pending-typed-msg.js | 8 ++-- ui/app/components/qr-code.js | 2 +- ui/app/components/send-token/index.js | 18 ++++---- ui/app/components/send/account-list-item.js | 2 +- ui/app/components/send/gas-fee-display-v2.js | 4 +- ui/app/components/send/gas-tooltip.js | 2 +- ui/app/components/send/send-v2-container.js | 2 +- ui/app/components/send/to-autocomplete.js | 4 +- ui/app/components/shapeshift-form.js | 22 +++++----- ui/app/components/shift-list-item.js | 18 ++++---- ui/app/components/signature-request.js | 20 ++++----- ui/app/components/token-balance.js | 2 +- ui/app/components/token-cell.js | 2 +- ui/app/components/token-list.js | 10 ++--- ui/app/components/transaction-list-item.js | 20 ++++----- ui/app/components/transaction-list.js | 4 +- ui/app/components/tx-list-item.js | 6 +-- ui/app/components/tx-list.js | 8 ++-- ui/app/components/tx-view.js | 10 ++--- ui/app/components/wallet-view.js | 12 +++--- ui/app/conf-tx.js | 2 +- ui/app/first-time/init-menu.js | 22 +++++----- ui/app/info.js | 2 +- ui/app/keychains/hd/create-vault-complete.js | 2 +- .../keychains/hd/recover-seed/confirmation.js | 2 +- ui/app/keychains/hd/restore-vault.js | 2 +- ui/app/metamask-connect.js | 18 ++++++++ ui/app/new-keychain.js | 2 +- ui/app/reducers.js | 7 +++ ui/app/reducers/locale.js | 18 ++++++++ ui/app/reducers/metamask.js | 6 +++ ui/app/select-app.js | 2 +- ui/app/send.js | 2 +- ui/app/settings.js | 17 +++++--- ui/app/template.js | 2 +- ui/app/unlock.js | 6 +-- ui/i18n-helper.js | 37 ++++++++++++++++ ui/index.js | 12 ++++-- 88 files changed, 538 insertions(+), 385 deletions(-) create mode 100644 ui/app/metamask-connect.js create mode 100644 ui/app/reducers/locale.js create mode 100644 ui/i18n-helper.js diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 39d15fd83..dc7da90d0 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -11,6 +11,7 @@ class PreferencesController { tokens: [], useBlockie: false, featureFlags: {}, + currentLocale: 'ja', }, opts.initState) this.store = new ObservableStore(initState) } @@ -24,6 +25,10 @@ class PreferencesController { return this.store.getState().useBlockie } + setCurrentLocale (key) { + this.store.updateState({ currentLocale: key }) + } + setSelectedAddress (_address) { return new Promise((resolve, reject) => { const address = normalizeAddress(_address) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 0a5c1d36f..4ff08e029 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -333,6 +333,7 @@ module.exports = class MetamaskController extends EventEmitter { getState: (cb) => cb(null, this.getState()), setCurrentCurrency: this.setCurrentCurrency.bind(this), setUseBlockie: this.setUseBlockie.bind(this), + setCurrentLocale: this.setCurrentLocale.bind(this), markAccountsFound: this.markAccountsFound.bind(this), markPasswordForgotten: this.markPasswordForgotten.bind(this), unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this), @@ -920,6 +921,15 @@ module.exports = class MetamaskController extends EventEmitter { } } + setCurrentLocale (key, cb) { + try { + this.preferencesController.setCurrentLocale(key) + cb(null) + } catch (err) { + cb(err) + } + } + recordFirstTimeInfo (initState) { if (!('firstTimeInfo' in initState)) { initState.firstTimeInfo = { diff --git a/app/scripts/popup-core.js b/app/scripts/popup-core.js index 2e4334bb1..5af913e98 100644 --- a/app/scripts/popup-core.js +++ b/app/scripts/popup-core.js @@ -11,11 +11,11 @@ const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex module.exports = initializePopup -function initializePopup ({ container, connectionStream }, cb) { +function initializePopup ({ container, connectionStream, localeMessages }, cb) { // setup app async.waterfall([ (cb) => connectToAccountManager(connectionStream, cb), - (accountManager, cb) => launchMetamaskUi({ container, accountManager }, cb), + (accountManager, cb) => launchMetamaskUi({ container, accountManager, localeMessages }, cb), ], cb) } diff --git a/app/scripts/popup.js b/app/scripts/popup.js index 0677311da..fe6aae799 100644 --- a/app/scripts/popup.js +++ b/app/scripts/popup.js @@ -1,8 +1,8 @@ // setup i18n -const Translator = require('../../ui/create-i18n') -const translator = new Translator() -global.translator = translator -global.getMessage = translator.getMessage.bind(translator) +// const Translator = require('../../ui/create-i18n') +// const translator = new Translator() +// global.translator = translator +// global.getMessage = translator.getMessage.bind(translator) const injectCss = require('inject-css') const OldMetaMaskUiCss = require('../../old-ui/css') @@ -15,6 +15,7 @@ const ExtensionPlatform = require('./platforms/extension') const NotificationManager = require('./lib/notification-manager') const notificationManager = new NotificationManager() const setupRaven = require('./lib/setupRaven') +const { fetchLocale } = require('../../ui/i18n-helper.js') start().catch(log.error) @@ -28,7 +29,8 @@ async function start() { setupRaven({ release }) // Load translator - await translator.setLocale('ja') + // await translator.setLocale('ja') + const localeMessages = await fetchLocale('ja') // inject css // const css = MetaMaskUiCss() @@ -45,7 +47,7 @@ async function start() { // start ui const container = document.getElementById('app-content') - startPopup({ container, connectionStream }, (err, store) => { + startPopup({ container, connectionStream, localeMessages }, (err, store) => { if (err) return displayCriticalError(err) // Code commented out until we begin auto adding users to NewUI diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js index 0da435298..c67ccb647 100644 --- a/ui/app/account-detail.js +++ b/ui/app/account-detail.js @@ -2,7 +2,7 @@ const inherits = require('util').inherits const extend = require('xtend') const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('react-redux').connect +const connect = require('./metamask-connect') const actions = require('./actions') const valuesFor = require('./util').valuesFor const TransactionList = require('./components/transaction-list') diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js index 9c4a79bec..ab5344dc6 100644 --- a/ui/app/accounts/import/index.js +++ b/ui/app/accounts/import/index.js @@ -1,7 +1,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') import Select from 'react-select' // Subviews @@ -14,8 +14,8 @@ module.exports = connect(mapStateToProps)(AccountImportSubview) function mapStateToProps (state) { return { menuItems: [ - t('privateKey'), - t('jsonFile'), + t(this.props.localeMessages, 'privateKey'), + t(this.props.localeMessages, 'jsonFile'), ], } } @@ -84,9 +84,9 @@ AccountImportSubview.prototype.renderImportView = function () { const current = type || menuItems[0] switch (current) { - case t('privateKey'): + case t(this.props.localeMessages, 'privateKey'): return h(PrivateKeyImportView) - case t('jsonFile'): + case t(this.props.localeMessages, 'jsonFile'): return h(JsonImportView) default: return h(JsonImportView) diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index 187abcc6a..b3f412e98 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -1,10 +1,10 @@ const Component = require('react').Component const PropTypes = require('prop-types') const h = require('react-hyperscript') -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') const FileInput = require('react-simple-file-input').default -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage const HELP_LINK = 'https://support.metamask.io/kb/article/7-importing-accounts' @@ -25,11 +25,11 @@ class JsonImportSubview extends Component { return ( h('div.new-account-import-form__json', [ - h('p', t('usedByClients')), + h('p', t(this.props.localeMessages, 'usedByClients')), h('a.warning', { href: HELP_LINK, target: '_blank', - }, t('fileImportFail')), + }, t(this.props.localeMessages, 'fileImportFail')), h(FileInput, { readAs: 'text', @@ -44,7 +44,7 @@ class JsonImportSubview extends Component { h('input.new-account-import-form__input-password', { type: 'password', - placeholder: t('enterPassword'), + placeholder: t(this.props.localeMessages, 'enterPassword'), id: 'json-password-box', onKeyPress: this.createKeyringOnEnter.bind(this), }), @@ -54,13 +54,13 @@ class JsonImportSubview extends Component { h('button.new-account-create-form__button-cancel', { onClick: () => this.props.goHome(), }, [ - t('cancel'), + t(this.props.localeMessages, 'cancel'), ]), h('button.new-account-create-form__button-create', { onClick: () => this.createNewKeychain(), }, [ - t('import'), + t(this.props.localeMessages, 'import'), ]), ]), @@ -92,7 +92,7 @@ class JsonImportSubview extends Component { const { fileContents } = state if (!fileContents) { - const message = t('needImportFile') + const message = t(this.props.localeMessages, 'needImportFile') return this.props.displayWarning(message) } @@ -100,7 +100,7 @@ class JsonImportSubview extends Component { const password = passwordInput.value if (!password) { - const message = t('needImportPassword') + const message = t(this.props.localeMessages, 'needImportPassword') return this.props.displayWarning(message) } diff --git a/ui/app/accounts/import/private-key.js b/ui/app/accounts/import/private-key.js index 01a43afba..9a23b791a 100644 --- a/ui/app/accounts/import/private-key.js +++ b/ui/app/accounts/import/private-key.js @@ -1,9 +1,9 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage module.exports = connect(mapStateToProps, mapDispatchToProps)(PrivateKeyImportView) @@ -34,7 +34,7 @@ PrivateKeyImportView.prototype.render = function () { return ( h('div.new-account-import-form__private-key', [ - h('span.new-account-create-form__instruction', t('pastePrivateKey')), + h('span.new-account-create-form__instruction', t(this.props.localeMessages, 'pastePrivateKey')), h('div.new-account-import-form__private-key-password-container', [ @@ -51,13 +51,13 @@ PrivateKeyImportView.prototype.render = function () { h('button.new-account-create-form__button-cancel.allcaps', { onClick: () => goHome(), }, [ - t('cancel'), + t(this.props.localeMessages, 'cancel'), ]), h('button.new-account-create-form__button-create.allcaps', { onClick: () => this.createNewKeychain(), }, [ - t('import'), + t(this.props.localeMessages, 'import'), ]), ]), diff --git a/ui/app/accounts/import/seed.js b/ui/app/accounts/import/seed.js index da70a9cb5..d701feedc 100644 --- a/ui/app/accounts/import/seed.js +++ b/ui/app/accounts/import/seed.js @@ -1,8 +1,8 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('react-redux').connect -const t = global.getMessage +const connect = require('../../metamask-connect') +const t = require('../../../i18n-helper').getMessage module.exports = connect(mapStateToProps)(SeedImportSubview) @@ -21,10 +21,10 @@ SeedImportSubview.prototype.render = function () { style: { }, }, [ - t('pasteSeed'), + t(this.props.localeMessages, 'pasteSeed'), h('textarea'), h('br'), - h('button', t('submit')), + h('button', t(this.props.localeMessages, 'submit')), ]) ) } diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js index 78802d35a..38cffec64 100644 --- a/ui/app/accounts/new-account/create-form.js +++ b/ui/app/accounts/new-account/create-form.js @@ -1,9 +1,9 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const { connect } = require('react-redux') +const connect = require('../../metamask-connect') const actions = require('../../actions') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage class NewAccountCreateForm extends Component { constructor (props) { @@ -14,7 +14,7 @@ class NewAccountCreateForm extends Component { this.state = { newAccountName: '', - defaultAccountName: t('newAccountNumberName', [newAccountNumber]), + defaultAccountName: t(this.props.localeMessages, 'newAccountNumberName', [newAccountNumber]), } } @@ -25,7 +25,7 @@ class NewAccountCreateForm extends Component { return h('div.new-account-create-form', [ h('div.new-account-create-form__input-label', {}, [ - t('accountName'), + t(this.props.localeMessages, 'accountName'), ]), h('div.new-account-create-form__input-wrapper', {}, [ @@ -41,13 +41,13 @@ class NewAccountCreateForm extends Component { h('button.new-account-create-form__button-cancel.allcaps', { onClick: () => this.props.goHome(), }, [ - t('cancel'), + t(this.props.localeMessages, 'cancel'), ]), h('button.new-account-create-form__button-create.allcaps', { onClick: () => this.props.createAccount(newAccountName || defaultAccountName), }, [ - t('create'), + t(this.props.localeMessages, 'create'), ]), ]), diff --git a/ui/app/accounts/new-account/index.js b/ui/app/accounts/new-account/index.js index a4535ec83..8c305bfae 100644 --- a/ui/app/accounts/new-account/index.js +++ b/ui/app/accounts/new-account/index.js @@ -1,9 +1,9 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage const { getCurrentViewContext } = require('../../selectors') const classnames = require('classnames') @@ -46,7 +46,7 @@ AccountDetailsModal.prototype.render = function () { h('div.new-account__header', [ - h('div.new-account__title', t('newAccount')), + h('div.new-account__title', t(this.props.localeMessages, 'newAccount')), h('div.new-account__tabs', [ @@ -56,7 +56,7 @@ AccountDetailsModal.prototype.render = function () { 'new-account__tabs__unselected cursor-pointer': displayedForm !== 'CREATE', }), onClick: () => displayForm('CREATE'), - }, t('createDen')), + }, t(this.props.localeMessages, 'createDen')), h('div.new-account__tabs__tab', { className: classnames('new-account__tabs__tab', { @@ -64,7 +64,7 @@ AccountDetailsModal.prototype.render = function () { 'new-account__tabs__unselected cursor-pointer': displayedForm !== 'IMPORT', }), onClick: () => displayForm('IMPORT'), - }, t('import')), + }, t(this.props.localeMessages, 'import')), ]), diff --git a/ui/app/actions.js b/ui/app/actions.js index 092af080b..4749d0735 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -2,6 +2,7 @@ const abi = require('human-standard-token-abi') const getBuyEthUrl = require('../../app/scripts/lib/buy-eth-url') const { getTokenAddressFromTokenObject } = require('./util') const ethUtil = require('ethereumjs-util') +const { fetchLocale } = require('../i18n-helper') var actions = { _setBackgroundConnection: _setBackgroundConnection, @@ -23,7 +24,7 @@ var actions = { NETWORK_DROPDOWN_CLOSE: 'UI_NETWORK_DROPDOWN_CLOSE', showNetworkDropdown: showNetworkDropdown, hideNetworkDropdown: hideNetworkDropdown, - // menu state + // menu state/ getNetworkStatus: 'getNetworkStatus', // transition state TRANSITION_FORWARD: 'TRANSITION_FORWARD', @@ -254,6 +255,13 @@ var actions = { SET_USE_BLOCKIE: 'SET_USE_BLOCKIE', setUseBlockie, + // locale + SET_CURRENT_LOCALE: 'SET_CURRENT_LOCALE', + SET_LOCALE_MESSAGES: 'SET_LOCALE_MESSAGES', + setCurrentLocale, + updateCurrentLocale, + setLocaleMessages, + // // Feature Flags setFeatureFlag, updateFeatureFlags, @@ -1790,6 +1798,39 @@ function setUseBlockie (val) { } } +function updateCurrentLocale (key) { + return (dispatch) => { + dispatch(actions.showLoadingIndication()) + log.debug(`background.updateCurrentLocale`) + console.log(`fetchLocale`, fetchLocale); + fetchLocale(key) + .then((localeMessages) => { + background.setCurrentLocale(key, (err) => { + dispatch(actions.hideLoadingIndication()) + if (err) { + return dispatch(actions.displayWarning(err.message)) + } + dispatch(actions.setCurrentLocale(key)) + dispatch(actions.setLocaleMessages(localeMessages)) + }) + }) + } +} + +function setCurrentLocale (key) { + return { + type: actions.SET_CURRENT_LOCALE, + value: key, + } +} + +function setLocaleMessages (localeMessages) { + return { + type: actions.SET_LOCALE_MESSAGES, + value: localeMessages, + } +} + function setNetworkEndpoints (networkEndpointType) { return dispatch => { log.debug('background.setNetworkEndpoints') diff --git a/ui/app/add-token.js b/ui/app/add-token.js index b8878b772..917a7c9fb 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -2,7 +2,7 @@ const inherits = require('util').inherits const Component = require('react').Component const classnames = require('classnames') const h = require('react-hyperscript') -const connect = require('react-redux').connect +const connect = require('./metamask-connect') const R = require('ramda') const Fuse = require('fuse.js') const contractMap = require('eth-contract-metadata') diff --git a/ui/app/app.js b/ui/app/app.js index f7fea0c22..34dd3d868 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -1,10 +1,10 @@ const inherits = require('util').inherits const Component = require('react').Component -const connect = require('react-redux').connect +const connect = require('./metamask-connect') const h = require('react-hyperscript') const actions = require('./actions') const classnames = require('classnames') -const t = global.getMessage +const t = require('../i18n-helper').getMessage // mascara const MascaraFirstTime = require('../../mascara/src/app/first-time').default @@ -294,8 +294,8 @@ App.prototype.renderAppBar = function () { // metamask name h('.flex-row', [ - h('h1', t('appName')), - h('div.beta-label', t('beta')), + h('h1', t(this.props.localeMessages, 'appName')), + h('div.beta-label', t(this.props.localeMessages, 'beta')), ]), ]), diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index 500c794e3..1f870a27c 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -3,7 +3,7 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const actions = require('../actions') const genAccountLink = require('etherscan-link').createAccountLink -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const Dropdown = require('./dropdown').Dropdown const DropdownMenuItem = require('./dropdown').DropdownMenuItem const Identicon = require('./identicon') @@ -79,7 +79,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label.allcaps', t('loose')) : null + return isLoose ? h('.keyring-label.allcaps', t(this.props.localeMessages, 'loose')) : null } catch (e) { return } } @@ -129,7 +129,7 @@ class AccountDropdowns extends Component { diameter: 32, }, ), - h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, t('createAccount')), + h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, t(this.props.localeMessages, 'createAccount')), ], ), h( @@ -154,7 +154,7 @@ class AccountDropdowns extends Component { fontSize: '24px', marginBottom: '5px', }, - }, t('importAccount')), + }, t(this.props.localeMessages, 'importAccount')), ] ), ] @@ -192,7 +192,7 @@ class AccountDropdowns extends Component { global.platform.openWindow({ url }) }, }, - t('etherscanView'), + t(this.props.localeMessages, 'etherscanView'), ), h( DropdownMenuItem, @@ -204,7 +204,7 @@ class AccountDropdowns extends Component { actions.showQrView(selected, identity ? identity.name : '') }, }, - t('showQRCode'), + t(this.props.localeMessages, 'showQRCode'), ), h( DropdownMenuItem, @@ -216,7 +216,7 @@ class AccountDropdowns extends Component { copyToClipboard(checkSumAddress) }, }, - t('copyAddress'), + t(this.props.localeMessages, 'copyAddress'), ), h( DropdownMenuItem, @@ -226,7 +226,7 @@ class AccountDropdowns extends Component { actions.requestAccountExport() }, }, - t('exportPrivateKey'), + t(this.props.localeMessages, 'exportPrivateKey'), ), ] ) diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js index 41dc887a0..3bb7ec337 100644 --- a/ui/app/components/account-export.js +++ b/ui/app/components/account-export.js @@ -5,8 +5,8 @@ const exportAsFile = require('../util').exportAsFile const copyToClipboard = require('copy-to-clipboard') const actions = require('../actions') const ethUtil = require('ethereumjs-util') -const connect = require('react-redux').connect -const t = global.getMessage +const connect = require('../metamask-connect') +const t = require('../../i18n-helper').getMessage module.exports = connect(mapStateToProps)(ExportAccountView) @@ -36,7 +36,7 @@ ExportAccountView.prototype.render = function () { if (notExporting) return h('div') if (exportRequested) { - const warning = t('exportPrivateKeyWarning') + const warning = t(this.props.localeMessages, 'exportPrivateKeyWarning') return ( h('div', { style: { @@ -54,7 +54,7 @@ ExportAccountView.prototype.render = function () { h('p.error', warning), h('input#exportAccount.sizing-input', { type: 'password', - placeholder: t('confirmPassword').toLowerCase(), + placeholder: t(this.props.localeMessages, 'confirmPassword').toLowerCase(), onKeyPress: this.onExportKeyPress.bind(this), style: { position: 'relative', @@ -75,10 +75,10 @@ ExportAccountView.prototype.render = function () { style: { marginRight: '10px', }, - }, t('submit')), + }, t(this.props.localeMessages, 'submit')), h('button', { onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)), - }, t('cancel')), + }, t(this.props.localeMessages, 'cancel')), ]), (this.props.warning) && ( h('span.error', { @@ -99,7 +99,7 @@ ExportAccountView.prototype.render = function () { margin: '0 20px', }, }, [ - h('label', t('copyPrivateKey') + ':'), + h('label', t(this.props.localeMessages, 'copyPrivateKey') + ':'), h('p.error.cursor-pointer', { style: { textOverflow: 'ellipsis', @@ -113,13 +113,13 @@ ExportAccountView.prototype.render = function () { }, plainKey), h('button', { onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)), - }, t('done')), + }, t(this.props.localeMessages, 'done')), h('button', { style: { marginLeft: '10px', }, onClick: () => exportAsFile(`MetaMask ${nickname} Private Key`, plainKey), - }, t('saveAsFile')), + }, t(this.props.localeMessages, 'saveAsFile')), ]) } } diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js index 09d002597..dc9c36c40 100644 --- a/ui/app/components/account-menu/index.js +++ b/ui/app/components/account-menu/index.js @@ -1,12 +1,12 @@ const inherits = require('util').inherits const Component = require('react').Component -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const h = require('react-hyperscript') const actions = require('../../actions') const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu') const Identicon = require('../identicon') const { formatBalance } = require('../../util') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountMenu) @@ -71,10 +71,10 @@ AccountMenu.prototype.render = function () { h(Item, { className: 'account-menu__header', }, [ - t('myAccounts'), + t(this.props.localeMessages, 'myAccounts'), h('button.account-menu__logout-button', { onClick: lockMetamask, - }, t('logout')), + }, t(this.props.localeMessages, 'logout')), ]), h(Divider), h('div.account-menu__accounts', this.renderAccounts()), @@ -82,23 +82,23 @@ AccountMenu.prototype.render = function () { h(Item, { onClick: () => showNewAccountPage('CREATE'), icon: h('img.account-menu__item-icon', { src: 'images/plus-btn-white.svg' }), - text: t('createAccount'), + text: t(this.props.localeMessages, 'createAccount'), }), h(Item, { onClick: () => showNewAccountPage('IMPORT'), icon: h('img.account-menu__item-icon', { src: 'images/import-account.svg' }), - text: t('importAccount'), + text: t(this.props.localeMessages, 'importAccount'), }), h(Divider), h(Item, { onClick: showInfoPage, icon: h('img', { src: 'images/mm-info-icon.svg' }), - text: t('infoHelp'), + text: t(this.props.localeMessages, 'infoHelp'), }), h(Item, { onClick: showConfigPage, icon: h('img.account-menu__item-icon', { src: 'images/settings.svg' }), - text: t('settings'), + text: t(this.props.localeMessages, 'settings'), }), ]) } @@ -156,6 +156,6 @@ AccountMenu.prototype.indicateIfLoose = function (keyring) { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label.allcaps', t('imported')) : null + return isLoose ? h('.keyring-label.allcaps', t(this.props.localeMessages, 'imported')) : null } catch (e) { return } } diff --git a/ui/app/components/balance-component.js b/ui/app/components/balance-component.js index d591ab455..f6292e358 100644 --- a/ui/app/components/balance-component.js +++ b/ui/app/components/balance-component.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const h = require('react-hyperscript') const inherits = require('util').inherits const TokenBalance = require('./token-balance') diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js index 2abdebeb9..5b83b4332 100644 --- a/ui/app/components/bn-as-decimal-input.js +++ b/ui/app/components/bn-as-decimal-input.js @@ -4,7 +4,7 @@ const inherits = require('util').inherits const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const extend = require('xtend') -const t = global.getMessage +const t = require('../../i18n-helper').getMessage module.exports = BnAsDecimalInput @@ -137,13 +137,13 @@ BnAsDecimalInput.prototype.constructWarning = function () { let message = name ? name + ' ' : '' if (min && max) { - message += t('betweenMinAndMax', [`${newMin} ${suffix}`, `${newMax} ${suffix}`]) + message += t(this.props.localeMessages, 'betweenMinAndMax', [`${newMin} ${suffix}`, `${newMax} ${suffix}`]) } else if (min) { - message += t('greaterThanMin', [`${newMin} ${suffix}`]) + message += t(this.props.localeMessages, 'greaterThanMin', [`${newMin} ${suffix}`]) } else if (max) { - message += t('lessThanMax', [`${newMax} ${suffix}`]) + message += t(this.props.localeMessages, 'lessThanMax', [`${newMax} ${suffix}`]) } else { - message += t('invalidInput') + message += t(this.props.localeMessages, 'invalidInput') } return message diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js index 1e277a94b..b2b8cbbd5 100644 --- a/ui/app/components/buy-button-subview.js +++ b/ui/app/components/buy-button-subview.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const actions = require('../actions') const CoinbaseForm = require('./coinbase-form') const ShapeshiftForm = require('./shapeshift-form') @@ -9,7 +9,7 @@ const Loading = require('./loading') const AccountPanel = require('./account-panel') const RadioList = require('./custom-radio-list') const networkNames = require('../../../app/scripts/config.js').networkNames -const t = require('../../i18n') +const t = require('../../i18n-helper.js').getMessage module.exports = connect(mapStateToProps)(BuyButtonSubview) @@ -77,7 +77,7 @@ BuyButtonSubview.prototype.headerSubview = function () { paddingTop: '4px', paddingBottom: '4px', }, - }, t('depositEth')), + }, t(this.props.localeMessages, 'depositEth')), ]), // loading indication @@ -119,7 +119,7 @@ BuyButtonSubview.prototype.headerSubview = function () { paddingTop: '4px', paddingBottom: '4px', }, - }, t('selectService')), + }, t(this.props.localeMessages, 'selectService')), ]), ]) @@ -165,14 +165,14 @@ BuyButtonSubview.prototype.primarySubview = function () { style: { marginTop: '15px', }, - }, t('borrowDharma')) + }, t(this.props.localeMessages, 'borrowDharma')) ) : null, ]) ) default: return ( - h('h2.error', t('unknownNetworkId')) + h('h2.error', t(this.props.localeMessages, 'unknownNetworkId')) ) } @@ -205,7 +205,7 @@ BuyButtonSubview.prototype.mainnetSubview = function () { ], subtext: { 'Coinbase': `${t('crypto')}/${t('fiat')} (${t('usaOnly')})`, - 'ShapeShift': t('crypto'), + 'ShapeShift': t(this.props.localeMessages, 'crypto'), }, onClick: this.radioHandler.bind(this), }), diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js index b9ef143e6..be413905e 100644 --- a/ui/app/components/coinbase-form.js +++ b/ui/app/components/coinbase-form.js @@ -1,9 +1,9 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const actions = require('../actions') -const t = global.getMessage +const t = require('../../i18n-helper').getMessage module.exports = connect(mapStateToProps)(CoinbaseForm) @@ -38,11 +38,11 @@ CoinbaseForm.prototype.render = function () { }, [ h('button.btn-green', { onClick: this.toCoinbase.bind(this), - }, t('continueToCoinbase')), + }, t(this.props.localeMessages, 'continueToCoinbase')), h('button.btn-red', { onClick: () => props.dispatch(actions.goHome()), - }, t('cancel')), + }, t(this.props.localeMessages, 'cancel')), ]), ]) } diff --git a/ui/app/components/copyButton.js b/ui/app/components/copyButton.js index 610d5b6a8..db43668cb 100644 --- a/ui/app/components/copyButton.js +++ b/ui/app/components/copyButton.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const copyToClipboard = require('copy-to-clipboard') -const t = global.getMessage +const t = require('../../i18n-helper').getMessage const Tooltip = require('./tooltip') @@ -23,7 +23,7 @@ CopyButton.prototype.render = function () { const value = props.value const copied = state.copied - const message = copied ? t('copiedButton') : props.title || t('copyButton') + const message = copied ? t(this.props.localeMessages, 'copiedButton') : props.title || t(this.props.localeMessages, 'copyButton') return h('.copy-button', { style: { diff --git a/ui/app/components/copyable.js b/ui/app/components/copyable.js index e0bf66f7e..92a337a37 100644 --- a/ui/app/components/copyable.js +++ b/ui/app/components/copyable.js @@ -4,7 +4,7 @@ const inherits = require('util').inherits const Tooltip = require('./tooltip') const copyToClipboard = require('copy-to-clipboard') -const t = global.getMessage +const t = require('../../i18n-helper').getMessage module.exports = Copyable @@ -23,7 +23,7 @@ Copyable.prototype.render = function () { const { copied } = state return h(Tooltip, { - title: copied ? t('copiedExclamation') : t('copy'), + title: copied ? t(this.props.localeMessages, 'copiedExclamation') : t(this.props.localeMessages, 'copy'), position: 'bottom', }, h('span', { style: { diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index ac8f3b842..8e3960ce4 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -1,10 +1,10 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') const GasModalCard = require('./gas-modal-card') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage const ethUtil = require('ethereumjs-util') @@ -147,7 +147,7 @@ CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) { }) if (!balanceIsSufficient) { - error = t('balanceIsInsufficientGas') + error = t(this.props.localeMessages, 'balanceIsInsufficientGas') } const gasLimitTooLow = gasLimit && conversionGreaterThan( @@ -163,7 +163,7 @@ CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) { ) if (gasLimitTooLow) { - error = t('gasLimitTooLow') + error = t(this.props.localeMessages, 'gasLimitTooLow') } this.setState({ error }) @@ -240,7 +240,7 @@ CustomizeGasModal.prototype.render = function () { }, [ h('div.send-v2__customize-gas__header', {}, [ - h('div.send-v2__customize-gas__title', t('customGas')), + h('div.send-v2__customize-gas__title', t(this.props.localeMessages, 'customGas')), h('div.send-v2__customize-gas__close', { onClick: hideModal, @@ -256,8 +256,8 @@ CustomizeGasModal.prototype.render = function () { // max: 1000, step: multiplyCurrencies(MIN_GAS_PRICE_GWEI, 10), onChange: value => this.convertAndSetGasPrice(value), - title: t('gasPrice'), - copy: t('gasPriceCalculation'), + title: t(this.props.localeMessages, 'gasPrice'), + copy: t(this.props.localeMessages, 'gasPriceCalculation'), }), h(GasModalCard, { @@ -266,8 +266,8 @@ CustomizeGasModal.prototype.render = function () { // max: 100000, step: 1, onChange: value => this.convertAndSetGasLimit(value), - title: t('gasLimit'), - copy: t('gasLimitCalculation'), + title: t(this.props.localeMessages, 'gasLimit'), + copy: t(this.props.localeMessages, 'gasLimitCalculation'), }), ]), diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index 0cdc2c0ae..73afb7009 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -3,14 +3,14 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const actions = require('../../../actions') const genAccountLink = require('../../../../lib/account-link.js') -const connect = require('react-redux').connect +const connect = require('../../../metamask-connect') const Dropdown = require('./dropdown').Dropdown const DropdownMenuItem = require('./dropdown').DropdownMenuItem const Identicon = require('../../identicon') const ethUtil = require('ethereumjs-util') const copyToClipboard = require('copy-to-clipboard') const { formatBalance } = require('../../../util') -const t = global.getMessage +const t = require('../../../../i18n-helper').getMessage class AccountDropdowns extends Component { @@ -131,7 +131,7 @@ class AccountDropdowns extends Component { actions.showEditAccountModal(identity) }, }, [ - t('edit'), + t(this.props.localeMessages, 'edit'), ]), ]), @@ -145,7 +145,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label.allcaps', t('loose')) : null + return isLoose ? h('.keyring-label.allcaps', t(this.props.localeMessages, 'loose')) : null } catch (e) { return } } @@ -203,7 +203,7 @@ class AccountDropdowns extends Component { fontSize: '16px', lineHeight: '23px', }, - }, t('createAccount')), + }, t(this.props.localeMessages, 'createAccount')), ], ), h( @@ -237,7 +237,7 @@ class AccountDropdowns extends Component { fontSize: '16px', lineHeight: '23px', }, - }, t('importAccount')), + }, t(this.props.localeMessages, 'importAccount')), ] ), ] @@ -288,7 +288,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t('accountDetails'), + t(this.props.localeMessages, 'accountDetails'), ), h( DropdownMenuItem, @@ -304,7 +304,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t('etherscanView'), + t(this.props.localeMessages, 'etherscanView'), ), h( DropdownMenuItem, @@ -320,7 +320,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t('copyAddress'), + t(this.props.localeMessages, 'copyAddress'), ), h( DropdownMenuItem, @@ -332,7 +332,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t('exportPrivateKey'), + t(this.props.localeMessages, 'exportPrivateKey'), ), h( DropdownMenuItem, @@ -347,7 +347,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t('addToken'), + t(this.props.localeMessages, 'addToken'), ), ] diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index a7acc7bb9..61c574aed 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -1,13 +1,13 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') const Dropdown = require('./components/dropdown').Dropdown const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem const NetworkDropdownIcon = require('./components/network-dropdown-icon') const R = require('ramda') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage // classes from nodes of the toggle element. @@ -95,13 +95,13 @@ NetworkDropdown.prototype.render = function () { }, [ h('div.network-dropdown-header', {}, [ - h('div.network-dropdown-title', {}, t('networks')), + h('div.network-dropdown-title', {}, t(this.props.localeMessages, 'networks')), h('div.network-dropdown-divider'), h('div.network-dropdown-content', {}, - t('defaultNetwork') + t(this.props.localeMessages, 'defaultNetwork') ), ]), @@ -123,7 +123,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'mainnet' ? '#ffffff' : '#9b9b9b', }, - }, t('mainnet')), + }, t(this.props.localeMessages, 'mainnet')), ] ), @@ -145,7 +145,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'ropsten' ? '#ffffff' : '#9b9b9b', }, - }, t('ropsten')), + }, t(this.props.localeMessages, 'ropsten')), ] ), @@ -167,7 +167,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'kovan' ? '#ffffff' : '#9b9b9b', }, - }, t('kovan')), + }, t(this.props.localeMessages, 'kovan')), ] ), @@ -189,7 +189,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'rinkeby' ? '#ffffff' : '#9b9b9b', }, - }, t('rinkeby')), + }, t(this.props.localeMessages, 'rinkeby')), ] ), @@ -211,7 +211,7 @@ NetworkDropdown.prototype.render = function () { style: { color: activeNetwork === 'http://localhost:8545' ? '#ffffff' : '#9b9b9b', }, - }, t('localhost')), + }, t(this.props.localeMessages, 'localhost')), ] ), @@ -235,7 +235,7 @@ NetworkDropdown.prototype.render = function () { style: { color: activeNetwork === 'custom' ? '#ffffff' : '#9b9b9b', }, - }, t('customRPC')), + }, t(this.props.localeMessages, 'customRPC')), ] ), @@ -250,15 +250,15 @@ NetworkDropdown.prototype.getNetworkName = function () { let name if (providerName === 'mainnet') { - name = t('mainnet') + name = t(this.props.localeMessages, 'mainnet') } else if (providerName === 'ropsten') { - name = t('ropsten') + name = t(this.props.localeMessages, 'ropsten') } else if (providerName === 'kovan') { - name = t('kovan') + name = t(this.props.localeMessages, 'kovan') } else if (providerName === 'rinkeby') { - name = t('rinkeby') + name = t(this.props.localeMessages, 'rinkeby') } else { - name = t('unknownNetwork') + name = t(this.props.localeMessages, 'unknownNetwork') } return name diff --git a/ui/app/components/dropdowns/token-menu-dropdown.js b/ui/app/components/dropdowns/token-menu-dropdown.js index 392f43c35..403d17591 100644 --- a/ui/app/components/dropdowns/token-menu-dropdown.js +++ b/ui/app/components/dropdowns/token-menu-dropdown.js @@ -1,9 +1,9 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage module.exports = connect(null, mapDispatchToProps)(TokenMenuDropdown) @@ -45,7 +45,7 @@ TokenMenuDropdown.prototype.render = function () { showHideTokenConfirmationModal(this.props.token) this.props.onClose() }, - }, t('hideToken')), + }, t(this.props.localeMessages, 'hideToken')), ]), ]), diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index 4f6b3afe4..ea26acbca 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -8,7 +8,7 @@ const ENS = require('ethjs-ens') const networkMap = require('ethjs-ens/lib/network-map.json') const ensRE = /.+\..+$/ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' -const t = global.getMessage +const t = require('../../i18n-helper').getMessage module.exports = EnsInput @@ -90,13 +90,13 @@ EnsInput.prototype.lookupEnsName = function () { log.info(`ENS attempting to resolve name: ${recipient}`) this.ens.lookup(recipient.trim()) .then((address) => { - if (address === ZERO_ADDRESS) throw new Error(t('noAddressForName')) + if (address === ZERO_ADDRESS) throw new Error(t(this.props.localeMessages, 'noAddressForName')) if (address !== ensResolution) { this.setState({ loadingEns: false, ensResolution: address, nickname: recipient.trim(), - hoverText: address + '\n' + t('clickCopy'), + hoverText: address + '\n' + t(this.props.localeMessages, 'clickCopy'), ensFailure: false, }) } diff --git a/ui/app/components/hex-as-decimal-input.js b/ui/app/components/hex-as-decimal-input.js index a43d44f89..7e53ba2f0 100644 --- a/ui/app/components/hex-as-decimal-input.js +++ b/ui/app/components/hex-as-decimal-input.js @@ -4,7 +4,7 @@ const inherits = require('util').inherits const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const extend = require('xtend') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage module.exports = HexAsDecimalInput @@ -127,13 +127,13 @@ HexAsDecimalInput.prototype.constructWarning = function () { let message = name ? name + ' ' : '' if (min && max) { - message += t('betweenMinAndMax', [min, max]) + message += t(this.props.localeMessages, 'betweenMinAndMax', [min, max]) } else if (min) { - message += t('greaterThanMin', [min]) + message += t(this.props.localeMessages, 'greaterThanMin', [min]) } else if (max) { - message += t('lessThanMax', [max]) + message += t(this.props.localeMessages, 'lessThanMax', [max]) } else { - message += t('invalidInput') + message += t(this.props.localeMessages, 'invalidInput') } return message diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index b803b7ceb..6b2a1b428 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const isNode = require('detect-node') const findDOMNode = require('react-dom').findDOMNode const jazzicon = require('jazzicon') diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js index c6a3111b1..e4f2009aa 100644 --- a/ui/app/components/modals/account-details-modal.js +++ b/ui/app/components/modals/account-details-modal.js @@ -1,14 +1,14 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') const AccountModalContainer = require('./account-modal-container') const { getSelectedIdentity } = require('../../selectors') const genAccountLink = require('../../../lib/account-link.js') const QrView = require('../qr-code') const EditableLabel = require('../editable-label') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage function mapStateToProps (state) { return { @@ -65,12 +65,12 @@ AccountDetailsModal.prototype.render = function () { h('button.btn-clear.account-modal__button', { onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }), - }, t('etherscanView')), + }, t(this.props.localeMessages, 'etherscanView')), // Holding on redesign for Export Private Key functionality h('button.btn-clear.account-modal__button', { onClick: () => showExportPrivateKeyModal(), - }, t('exportPrivateKey')), + }, t(this.props.localeMessages, 'exportPrivateKey')), ]) } diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js index 964677244..ac6457b37 100644 --- a/ui/app/components/modals/account-modal-container.js +++ b/ui/app/components/modals/account-modal-container.js @@ -1,11 +1,11 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') const { getSelectedIdentity } = require('../../selectors') const Identicon = require('../identicon') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage function mapStateToProps (state) { return { @@ -60,7 +60,7 @@ AccountModalContainer.prototype.render = function () { h('i.fa.fa-angle-left.fa-lg'), - h('span.account-modal-back__text', ' ' + t('back')), + h('span.account-modal-back__text', ' ' + t(this.props.localeMessages, 'back')), ]), diff --git a/ui/app/components/modals/buy-options-modal.js b/ui/app/components/modals/buy-options-modal.js index 33f8f6682..0e93e9a2d 100644 --- a/ui/app/components/modals/buy-options-modal.js +++ b/ui/app/components/modals/buy-options-modal.js @@ -1,10 +1,10 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage function mapStateToProps (state) { return { @@ -57,15 +57,15 @@ BuyOptions.prototype.render = function () { }, [ h('div.buy-modal-content-title', { style: {}, - }, t('transfers')), - h('div', {}, t('howToDeposit')), + }, t(this.props.localeMessages, 'transfers')), + h('div', {}, t(this.props.localeMessages, 'howToDeposit')), ]), h('div.buy-modal-content-options.flex-column.flex-center', {}, [ isTestNetwork - ? this.renderModalContentOption(networkName, t('testFaucet'), () => toFaucet(network)) - : this.renderModalContentOption('Coinbase', t('depositFiat'), () => toCoinbase(address)), + ? this.renderModalContentOption(networkName, t(this.props.localeMessages, 'testFaucet'), () => toFaucet(network)) + : this.renderModalContentOption('Coinbase', t(this.props.localeMessages, 'depositFiat'), () => toCoinbase(address)), // h('div.buy-modal-content-option', {}, [ // h('div.buy-modal-content-option-title', {}, 'Shapeshift'), @@ -73,8 +73,8 @@ BuyOptions.prototype.render = function () { // ]),, this.renderModalContentOption( - t('directDeposit'), - t('depositFromAccount'), + t(this.props.localeMessages, 'directDeposit'), + t(this.props.localeMessages, 'depositFromAccount'), () => this.goToAccountDetailsModal() ), @@ -85,7 +85,7 @@ BuyOptions.prototype.render = function () { background: 'white', }, onClick: () => { this.props.hideModal() }, - }, h('div.buy-modal-content-footer#buy-modal-content-footer-text', {}, t('cancel'))), + }, h('div.buy-modal-content-footer#buy-modal-content-footer-text', {}, t(this.props.localeMessages, 'cancel'))), ]), ]) } diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index 03304207e..3984e2c7b 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -1,11 +1,11 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames const ShapeshiftForm = require('../shapeshift-form') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage let DIRECT_DEPOSIT_ROW_TITLE let DIRECT_DEPOSIT_ROW_TEXT @@ -16,7 +16,7 @@ let SHAPESHIFT_ROW_TEXT let FAUCET_ROW_TITLE const facuetRowText = (networkName) => { - return t('getEtherFromFaucet', [networkName]) + return t(this.props.localeMessages, 'getEtherFromFaucet', [networkName]) } function mapStateToProps (state) { @@ -49,13 +49,13 @@ function DepositEtherModal () { Component.call(this) // need to set after i18n locale has loaded - DIRECT_DEPOSIT_ROW_TITLE = t('directDepositEther') - DIRECT_DEPOSIT_ROW_TEXT = t('directDepositEtherExplainer') - COINBASE_ROW_TITLE = t('buyCoinbase') - COINBASE_ROW_TEXT = t('buyCoinbaseExplainer') - SHAPESHIFT_ROW_TITLE = t('depositShapeShift') - SHAPESHIFT_ROW_TEXT = t('depositShapeShiftExplainer') - FAUCET_ROW_TITLE = t('testFaucet') + DIRECT_DEPOSIT_ROW_TITLE = t(this.props.localeMessages, 'directDepositEther') + DIRECT_DEPOSIT_ROW_TEXT = t(this.props.localeMessages, 'directDepositEtherExplainer') + COINBASE_ROW_TITLE = t(this.props.localeMessages, 'buyCoinbase') + COINBASE_ROW_TEXT = t(this.props.localeMessages, 'buyCoinbaseExplainer') + SHAPESHIFT_ROW_TITLE = t(this.props.localeMessages, 'depositShapeShift') + SHAPESHIFT_ROW_TEXT = t(this.props.localeMessages, 'depositShapeShiftExplainer') + FAUCET_ROW_TITLE = t(this.props.localeMessages, 'testFaucet') this.state = { buyingWithShapeshift: false, @@ -126,7 +126,7 @@ DepositEtherModal.prototype.render = function () { h('div.page-container__title', [t('depositEther')]), h('div.page-container__subtitle', [ - t('needEtherInWallet'), + t(this.props.localeMessages, 'needEtherInWallet'), ]), h('div.page-container__header-close', { @@ -147,7 +147,7 @@ DepositEtherModal.prototype.render = function () { logo: h('img.deposit-ether-modal__buy-row__eth-logo', { src: '../../../images/eth_logo.svg' }), title: DIRECT_DEPOSIT_ROW_TITLE, text: DIRECT_DEPOSIT_ROW_TEXT, - buttonLabel: t('viewAccount'), + buttonLabel: t(this.props.localeMessages, 'viewAccount'), onButtonClick: () => this.goToAccountDetailsModal(), hide: buyingWithShapeshift, }), @@ -156,7 +156,7 @@ DepositEtherModal.prototype.render = function () { logo: h('i.fa.fa-tint.fa-2x'), title: FAUCET_ROW_TITLE, text: facuetRowText(networkName), - buttonLabel: t('getEther'), + buttonLabel: t(this.props.localeMessages, 'getEther'), onButtonClick: () => toFaucet(network), hide: !isTestNetwork || buyingWithShapeshift, }), @@ -170,7 +170,7 @@ DepositEtherModal.prototype.render = function () { }), title: COINBASE_ROW_TITLE, text: COINBASE_ROW_TEXT, - buttonLabel: t('continueToCoinbase'), + buttonLabel: t(this.props.localeMessages, 'continueToCoinbase'), onButtonClick: () => toCoinbase(address), hide: isTestNetwork || buyingWithShapeshift, }), @@ -183,7 +183,7 @@ DepositEtherModal.prototype.render = function () { }), title: SHAPESHIFT_ROW_TITLE, text: SHAPESHIFT_ROW_TEXT, - buttonLabel: t('shapeshiftBuy'), + buttonLabel: t(this.props.localeMessages, 'shapeshiftBuy'), onButtonClick: () => this.setState({ buyingWithShapeshift: true }), hide: isTestNetwork, hideButton: buyingWithShapeshift, diff --git a/ui/app/components/modals/edit-account-name-modal.js b/ui/app/components/modals/edit-account-name-modal.js index 79d6109cc..02de5b99c 100644 --- a/ui/app/components/modals/edit-account-name-modal.js +++ b/ui/app/components/modals/edit-account-name-modal.js @@ -1,10 +1,10 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') const { getSelectedAccount } = require('../../selectors') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage function mapStateToProps (state) { return { @@ -70,7 +70,7 @@ EditAccountNameModal.prototype.render = function () { }, disabled: this.state.inputText.length === 0, }, [ - t('save'), + t(this.props.localeMessages, 'save'), ]), ]), diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js index 3fc93b4f5..fac5366a4 100644 --- a/ui/app/components/modals/export-private-key-modal.js +++ b/ui/app/components/modals/export-private-key-modal.js @@ -1,13 +1,13 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const ethUtil = require('ethereumjs-util') const actions = require('../../actions') const AccountModalContainer = require('./account-modal-container') const { getSelectedIdentity } = require('../../selectors') const ReadOnlyInput = require('../readonly-input') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage const copyToClipboard = require('copy-to-clipboard') function mapStateToProps (state) { @@ -49,8 +49,8 @@ ExportPrivateKeyModal.prototype.exportAccountAndGetPrivateKey = function (passwo ExportPrivateKeyModal.prototype.renderPasswordLabel = function (privateKey) { return h('span.private-key-password-label', privateKey - ? t('copyPrivateKey') - : t('typePassword') + ? t(this.props.localeMessages, 'copyPrivateKey') + : t(this.props.localeMessages, 'typePassword') ) } @@ -87,8 +87,8 @@ ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, password, ), (privateKey - ? this.renderButton('btn-clear export-private-key__button', () => hideModal(), t('done')) - : this.renderButton('btn-clear export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), t('confirm')) + ? this.renderButton('btn-clear export-private-key__button', () => hideModal(), t(this.props.localeMessages, 'done')) + : this.renderButton('btn-clear export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), t(this.props.localeMessages, 'confirm')) ), ]) @@ -121,7 +121,7 @@ ExportPrivateKeyModal.prototype.render = function () { h('div.account-modal-divider'), - h('span.modal-body-title', t('showPrivateKeys')), + h('span.modal-body-title', t(this.props.localeMessages, 'showPrivateKeys')), h('div.private-key-password', {}, [ this.renderPasswordLabel(privateKey), @@ -131,7 +131,7 @@ ExportPrivateKeyModal.prototype.render = function () { !warning ? null : h('span.private-key-password-error', warning), ]), - h('div.private-key-password-warning', t('privateKeyWarning')), + h('div.private-key-password-warning', t(this.props.localeMessages, 'privateKeyWarning')), this.renderButtons(privateKey, this.state.password, address, hideModal), diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js index efd472cf3..a6cf2889f 100644 --- a/ui/app/components/modals/hide-token-confirmation-modal.js +++ b/ui/app/components/modals/hide-token-confirmation-modal.js @@ -1,10 +1,10 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') const Identicon = require('../identicon') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage function mapStateToProps (state) { return { @@ -42,7 +42,7 @@ HideTokenConfirmationModal.prototype.render = function () { h('div.hide-token-confirmation__container', { }, [ h('div.hide-token-confirmation__title', {}, [ - t('hideTokenPrompt'), + t(this.props.localeMessages, 'hideTokenPrompt'), ]), h(Identicon, { @@ -55,19 +55,19 @@ HideTokenConfirmationModal.prototype.render = function () { h('div.hide-token-confirmation__symbol', {}, symbol), h('div.hide-token-confirmation__copy', {}, [ - t('readdToken'), + t(this.props.localeMessages, 'readdToken'), ]), h('div.hide-token-confirmation__buttons', {}, [ h('button.btn-cancel.hide-token-confirmation__button.allcaps', { onClick: () => hideModal(), }, [ - t('cancel'), + t(this.props.localeMessages, 'cancel'), ]), h('button.btn-clear.hide-token-confirmation__button.allcaps', { onClick: () => hideToken(address), }, [ - t('hide'), + t(this.props.localeMessages, 'hide'), ]), ]), ]), diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index 9250cc77e..d0f4b486c 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const FadeModal = require('boron').FadeModal const actions = require('../../actions') const isMobileView = require('../../../lib/is-mobile-view') diff --git a/ui/app/components/modals/new-account-modal.js b/ui/app/components/modals/new-account-modal.js index 7fe367f3f..7f9b7a154 100644 --- a/ui/app/components/modals/new-account-modal.js +++ b/ui/app/components/modals/new-account-modal.js @@ -3,7 +3,7 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const { connect } = require('react-redux') const actions = require('../../actions') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage class NewAccountModal extends Component { constructor (props) { @@ -23,7 +23,7 @@ class NewAccountModal extends Component { h('div.new-account-modal-wrapper', { }, [ h('div.new-account-modal-header', {}, [ - t('newAccount'), + t(this.props.localeMessages, 'newAccount'), ]), h('div.modal-close-x', { @@ -31,19 +31,19 @@ class NewAccountModal extends Component { }), h('div.new-account-modal-content', {}, [ - t('accountName'), + t(this.props.localeMessages, 'accountName'), ]), h('div.new-account-input-wrapper', {}, [ h('input.new-account-input', { value: this.state.newAccountName, - placeholder: t('sampleAccountName'), + placeholder: t(this.props.localeMessages, 'sampleAccountName'), onChange: event => this.setState({ newAccountName: event.target.value }), }, []), ]), h('div.new-account-modal-content.after-input', {}, [ - t('or'), + t(this.props.localeMessages, 'or'), ]), h('div.new-account-modal-content.after-input.pointer', { @@ -51,13 +51,13 @@ class NewAccountModal extends Component { this.props.hideModal() this.props.showImportPage() }, - }, t('importAnAccount')), + }, t(this.props.localeMessages, 'importAnAccount')), h('div.new-account-modal-content.button.allcaps', {}, [ h('button.btn-clear', { onClick: () => this.props.createAccount(newAccountName), }, [ - t('save'), + t(this.props.localeMessages, 'save'), ]), ]), ]), diff --git a/ui/app/components/modals/notification-modal.js b/ui/app/components/modals/notification-modal.js index 071d7ffd5..c05d80251 100644 --- a/ui/app/components/modals/notification-modal.js +++ b/ui/app/components/modals/notification-modal.js @@ -3,7 +3,7 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const { connect } = require('react-redux') const actions = require('../../actions') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage class NotificationModal extends Component { render () { diff --git a/ui/app/components/modals/shapeshift-deposit-tx-modal.js b/ui/app/components/modals/shapeshift-deposit-tx-modal.js index 24af5a0de..28dcb1902 100644 --- a/ui/app/components/modals/shapeshift-deposit-tx-modal.js +++ b/ui/app/components/modals/shapeshift-deposit-tx-modal.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') const QrView = require('../qr-code') const AccountModalContainer = require('./account-modal-container') diff --git a/ui/app/components/network.js b/ui/app/components/network.js index f3df2242a..d3a36b012 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -3,7 +3,7 @@ const h = require('react-hyperscript') const classnames = require('classnames') const inherits = require('util').inherits const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage module.exports = Network @@ -34,7 +34,7 @@ Network.prototype.render = function () { onClick: (event) => this.props.onClick(event), }, [ h('img', { - title: t('attemptingConnect'), + title: t(props.localeMessages, 'attemptingConnect'), style: { width: '27px', }, @@ -42,22 +42,22 @@ Network.prototype.render = function () { }), ]) } else if (providerName === 'mainnet') { - hoverText = t('mainnet') + hoverText = t(props.localeMessages, 'mainnet') iconName = 'ethereum-network' } else if (providerName === 'ropsten') { - hoverText = t('ropsten') + hoverText = t(props.localeMessages, 'ropsten') iconName = 'ropsten-test-network' } else if (parseInt(networkNumber) === 3) { - hoverText = t('ropsten') + hoverText = t(props.localeMessages, 'ropsten') iconName = 'ropsten-test-network' } else if (providerName === 'kovan') { - hoverText = t('kovan') + hoverText = t(props.localeMessages, 'kovan') iconName = 'kovan-test-network' } else if (providerName === 'rinkeby') { - hoverText = t('rinkeby') + hoverText = t(props.localeMessages, 'rinkeby') iconName = 'rinkeby-test-network' } else { - hoverText = t('unknownNetwork') + hoverText = t(props.localeMessages, 'unknownNetwork') iconName = 'unknown-private-network' } @@ -85,7 +85,7 @@ Network.prototype.render = function () { backgroundColor: '#038789', // $blue-lagoon nonSelectBackgroundColor: '#15afb2', }), - h('.network-name', t('mainnet')), + h('.network-name', t(props.localeMessages, 'mainnet')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'ropsten-test-network': @@ -94,7 +94,7 @@ Network.prototype.render = function () { backgroundColor: '#e91550', // $crimson nonSelectBackgroundColor: '#ec2c50', }), - h('.network-name', t('ropsten')), + h('.network-name', t(props.localeMessages, 'ropsten')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'kovan-test-network': @@ -103,7 +103,7 @@ Network.prototype.render = function () { backgroundColor: '#690496', // $purple nonSelectBackgroundColor: '#b039f3', }), - h('.network-name', t('kovan')), + h('.network-name', t(props.localeMessages, 'kovan')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'rinkeby-test-network': @@ -112,7 +112,7 @@ Network.prototype.render = function () { backgroundColor: '#ebb33f', // $tulip-tree nonSelectBackgroundColor: '#ecb23e', }), - h('.network-name', t('rinkeby')), + h('.network-name', t(props.localeMessages, 'rinkeby')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) default: @@ -124,7 +124,7 @@ Network.prototype.render = function () { }, }), - h('.network-name', t('privateNetwork')), + h('.network-name', t(props.localeMessages, 'privateNetwork')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) } diff --git a/ui/app/components/notice.js b/ui/app/components/notice.js index 8b0ce1e8b..ffc5ec6f1 100644 --- a/ui/app/components/notice.js +++ b/ui/app/components/notice.js @@ -4,7 +4,7 @@ const h = require('react-hyperscript') const ReactMarkdown = require('react-markdown') const linker = require('extension-link-enabler') const findDOMNode = require('react-dom').findDOMNode -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage module.exports = Notice @@ -111,7 +111,7 @@ Notice.prototype.render = function () { style: { marginTop: '18px', }, - }, t('accept')), + }, t(this.props.localeMessages, 'accept')), ]) ) } diff --git a/ui/app/components/pending-msg-details.js b/ui/app/components/pending-msg-details.js index 87e66855d..8edf21b48 100644 --- a/ui/app/components/pending-msg-details.js +++ b/ui/app/components/pending-msg-details.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage const AccountPanel = require('./account-panel') @@ -40,7 +40,7 @@ PendingMsgDetails.prototype.render = function () { // message data h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [ h('.flex-column.flex-space-between', [ - h('label.font-small.allcaps', t('message')), + h('label.font-small.allcaps', t(this.props.localeMessages, 'message')), h('span.font-small', msgParams.data), ]), ]), diff --git a/ui/app/components/pending-msg.js b/ui/app/components/pending-msg.js index dc406b955..2364353be 100644 --- a/ui/app/components/pending-msg.js +++ b/ui/app/components/pending-msg.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const PendingTxDetails = require('./pending-msg-details') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage module.exports = PendingMsg @@ -30,14 +30,14 @@ PendingMsg.prototype.render = function () { fontWeight: 'bold', textAlign: 'center', }, - }, t('signMessage')), + }, t(this.props.localeMessages, 'signMessage')), h('.error', { style: { margin: '10px', }, }, [ - t('signNotice'), + t(this.props.localeMessages, 'signNotice'), h('a', { href: 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527', style: { color: 'rgb(247, 134, 28)' }, @@ -46,7 +46,7 @@ PendingMsg.prototype.render = function () { const url = 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527' global.platform.openWindow({ url }) }, - }, t('readMore')), + }, t(this.props.localeMessages, 'readMore')), ]), // message details @@ -56,10 +56,10 @@ PendingMsg.prototype.render = function () { h('.flex-row.flex-space-around', [ h('button', { onClick: state.cancelMessage, - }, t('cancel')), + }, t(this.props.localeMessages, 'cancel')), h('button', { onClick: state.signMessage, - }, t('sign')), + }, t(this.props.localeMessages, 'sign')), ]), ]) diff --git a/ui/app/components/pending-personal-msg-details.js b/ui/app/components/pending-personal-msg-details.js index b896e9a7e..74f7b2ba0 100644 --- a/ui/app/components/pending-personal-msg-details.js +++ b/ui/app/components/pending-personal-msg-details.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage const AccountPanel = require('./account-panel') const BinaryRenderer = require('./binary-renderer') @@ -46,7 +46,7 @@ PendingMsgDetails.prototype.render = function () { height: '260px', }, }, [ - h('label.font-small.allcaps', { style: { display: 'block' } }, t('message')), + h('label.font-small.allcaps', { style: { display: 'block' } }, t(this.props.localeMessages, 'message')), h(BinaryRenderer, { value: data, style: { diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index b6bfb9afe..483574094 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -9,7 +9,7 @@ const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const hexToBn = require('../../../../app/scripts/lib/hex-to-bn') const { conversionUtil } = require('../../conversion-util') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') @@ -56,7 +56,7 @@ ConfirmDeployContract.prototype.onSubmit = function (event) { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.dispatch(actions.displayWarning(t('invalidGasParams'))) + this.props.dispatch(actions.displayWarning(t(this.props.localeMessages, 'invalidGasParams'))) this.setState({ submitting: false }) } } @@ -201,7 +201,7 @@ ConfirmDeployContract.prototype.renderGasFee = function () { return ( h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'gasFee') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${fiatGas} ${currentCurrency.toUpperCase()}`), @@ -240,8 +240,8 @@ ConfirmDeployContract.prototype.renderTotalPlusGas = function () { return ( h('section.flex-row.flex-center.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ t('total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), + h('span.confirm-screen-label', [ t(this.props.localeMessages, 'total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ t(this.props.localeMessages, 'amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -274,8 +274,8 @@ ConfirmDeployContract.prototype.render = function () { h('h3.flex-center.confirm-screen-header', [ h('button.confirm-screen-back-button.allcaps', { onClick: () => backToAccountDetail(selectedAddress), - }, t('back')), - h('div.confirm-screen-title', t('confirmContract')), + }, t(this.props.localeMessages, 'back')), + h('div.confirm-screen-title', t(this.props.localeMessages, 'confirmContract')), h('div.confirm-screen-header-tip'), ]), h('div.flex-row.flex-center.confirm-screen-identicons', [ @@ -293,7 +293,7 @@ ConfirmDeployContract.prototype.render = function () { h('i.fa.fa-arrow-right.fa-lg'), h('div.confirm-screen-account-wrapper', [ h('i.fa.fa-file-text-o'), - h('span.confirm-screen-account-name', t('newContract')), + h('span.confirm-screen-account-name', t(this.props.localeMessages, 'newContract')), h('span.confirm-screen-account-number', ' '), ]), ]), @@ -311,7 +311,7 @@ ConfirmDeployContract.prototype.render = function () { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -319,9 +319,9 @@ ConfirmDeployContract.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'to') ]), h('div.confirm-screen-section-column', [ - h('div.confirm-screen-row-info', t('newContract')), + h('div.confirm-screen-row-info', t(this.props.localeMessages, 'newContract')), ]), ]), @@ -338,7 +338,7 @@ ConfirmDeployContract.prototype.render = function () { // Cancel Button h('div.cancel.btn-light.confirm-screen-cancel-button.allcaps', { onClick: (event) => this.cancel(event, txMeta), - }, t('cancel')), + }, t(this.props.localeMessages, 'cancel')), // Accept Button h('button.confirm-screen-confirm-button.allcaps', [t('confirm')]), diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index 7e1b25bb7..7fd498d83 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -9,7 +9,7 @@ const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const hexToBn = require('../../../../app/scripts/lib/hex-to-bn') const { conversionUtil, addCurrencies } = require('../../conversion-util') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') @@ -166,7 +166,7 @@ ConfirmSendEther.prototype.getData = function () { }, to: { address: txParams.to, - name: identities[txParams.to] ? identities[txParams.to].name : t('newRecipient'), + name: identities[txParams.to] ? identities[txParams.to].name : t(this.props.localeMessages, 'newRecipient'), }, memo: txParams.memo || '', gasFeeInFIAT, @@ -267,7 +267,7 @@ ConfirmSendEther.prototype.render = function () { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -275,7 +275,7 @@ ConfirmSendEther.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'to') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', toName), h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`), @@ -283,7 +283,7 @@ ConfirmSendEther.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'gasFee') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${gasFeeInFIAT} ${currentCurrency.toUpperCase()}`), @@ -294,8 +294,8 @@ ConfirmSendEther.prototype.render = function () { h('section.flex-row.flex-center.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ t('total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), + h('span.confirm-screen-label', [ t(this.props.localeMessages, 'total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ t(this.props.localeMessages, 'amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -395,7 +395,7 @@ ConfirmSendEther.prototype.render = function () { clearSend() this.cancel(event, txMeta) }, - }, t('cancel')), + }, t(this.props.localeMessages, 'cancel')), // Accept Button h('button.confirm-screen-confirm-button.allcaps', [t('confirm')]), @@ -413,7 +413,7 @@ ConfirmSendEther.prototype.onSubmit = function (event) { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.dispatch(actions.displayWarning(t('invalidGasParams'))) + this.props.dispatch(actions.displayWarning(t(this.props.localeMessages, 'invalidGasParams'))) this.setState({ submitting: false }) } } diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index 3a7678aa3..bd1ad82ef 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -6,7 +6,7 @@ const tokenAbi = require('human-standard-token-abi') const abiDecoder = require('abi-decoder') abiDecoder.addABI(tokenAbi) const actions = require('../../actions') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage const clone = require('clone') const Identicon = require('../identicon') const ethUtil = require('ethereumjs-util') @@ -134,7 +134,7 @@ ConfirmSendToken.prototype.getAmount = function () { ? +(sendTokenAmount * tokenExchangeRate * conversionRate).toFixed(2) : null, token: typeof value === 'undefined' - ? t('unknown') + ? t(this.props.localeMessages, 'unknown') : +sendTokenAmount.toFixed(decimals), } @@ -205,7 +205,7 @@ ConfirmSendToken.prototype.getData = function () { }, to: { address: value, - name: identities[value] ? identities[value].name : t('newRecipient'), + name: identities[value] ? identities[value].name : t(this.props.localeMessages, 'newRecipient'), }, memo: txParams.memo || '', } @@ -245,7 +245,7 @@ ConfirmSendToken.prototype.renderGasFee = function () { return ( h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'gasFee') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${fiatGas} ${currentCurrency}`), @@ -267,8 +267,8 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { ? ( h('section.flex-row.flex-center.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ t('total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), + h('span.confirm-screen-label', [ t(this.props.localeMessages, 'total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ t(this.props.localeMessages, 'amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -280,8 +280,8 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { : ( h('section.flex-row.flex-center.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ t('total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), + h('span.confirm-screen-label', [ t(this.props.localeMessages, 'total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ t(this.props.localeMessages, 'amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -315,9 +315,9 @@ ConfirmSendToken.prototype.render = function () { h('div.page-container__header', [ h('button.confirm-screen-back-button', { onClick: () => editTransaction(txMeta), - }, t('edit')), - h('div.page-container__title', t('confirm')), - h('div.page-container__subtitle', t('pleaseReviewTransaction')), + }, t(this.props.localeMessages, 'edit')), + h('div.page-container__title', t(this.props.localeMessages, 'confirm')), + h('div.page-container__subtitle', t(this.props.localeMessages, 'pleaseReviewTransaction')), ]), h('div.flex-row.flex-center.confirm-screen-identicons', [ h('div.confirm-screen-account-wrapper', [ @@ -358,7 +358,7 @@ ConfirmSendToken.prototype.render = function () { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -366,7 +366,7 @@ ConfirmSendToken.prototype.render = function () { ]), toAddress && h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'to') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', toName), h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`), @@ -386,7 +386,7 @@ ConfirmSendToken.prototype.render = function () { // Cancel Button h('div.cancel.btn-light.confirm-screen-cancel-button.allcaps', { onClick: (event) => this.cancel(event, txMeta), - }, t('cancel')), + }, t(this.props.localeMessages, 'cancel')), // Accept Button h('button.confirm-screen-confirm-button.allcaps', [t('confirm')]), @@ -406,7 +406,7 @@ ConfirmSendToken.prototype.onSubmit = function (event) { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.dispatch(actions.displayWarning(t('invalidGasParams'))) + this.props.dispatch(actions.displayWarning(t(this.props.localeMessages, 'invalidGasParams'))) this.setState({ submitting: false }) } } diff --git a/ui/app/components/pending-typed-msg-details.js b/ui/app/components/pending-typed-msg-details.js index ae0a1171e..21eec3ce5 100644 --- a/ui/app/components/pending-typed-msg-details.js +++ b/ui/app/components/pending-typed-msg-details.js @@ -4,7 +4,7 @@ const inherits = require('util').inherits const AccountPanel = require('./account-panel') const TypedMessageRenderer = require('./typed-message-renderer') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage module.exports = PendingMsgDetails @@ -46,7 +46,7 @@ PendingMsgDetails.prototype.render = function () { height: '260px', }, }, [ - h('label.font-small.allcaps', { style: { display: 'block' } }, t('youSign')), + h('label.font-small.allcaps', { style: { display: 'block' } }, t(this.props.localeMessages, 'youSign')), h(TypedMessageRenderer, { value: data, style: { diff --git a/ui/app/components/pending-typed-msg.js b/ui/app/components/pending-typed-msg.js index ccde5e8af..91fa5f052 100644 --- a/ui/app/components/pending-typed-msg.js +++ b/ui/app/components/pending-typed-msg.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const PendingTxDetails = require('./pending-typed-msg-details') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage module.exports = PendingMsg @@ -27,7 +27,7 @@ PendingMsg.prototype.render = function () { fontWeight: 'bold', textAlign: 'center', }, - }, t('signMessage')), + }, t(this.props.localeMessages, 'signMessage')), // message details h(PendingTxDetails, state), @@ -36,10 +36,10 @@ PendingMsg.prototype.render = function () { h('.flex-row.flex-space-around', [ h('button.allcaps', { onClick: state.cancelTypedMessage, - }, t('cancel')), + }, t(this.props.localeMessages, 'cancel')), h('button.allcaps', { onClick: state.signTypedMessage, - }, t('sign')), + }, t(this.props.localeMessages, 'sign')), ]), ]) diff --git a/ui/app/components/qr-code.js b/ui/app/components/qr-code.js index 83885539c..89504eca3 100644 --- a/ui/app/components/qr-code.js +++ b/ui/app/components/qr-code.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const qrCode = require('qrcode-npm').qrcode const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const isHexPrefixed = require('ethereumjs-util').isHexPrefixed const ReadOnlyInput = require('./readonly-input') diff --git a/ui/app/components/send-token/index.js b/ui/app/components/send-token/index.js index 4519f469b..96ccde214 100644 --- a/ui/app/components/send-token/index.js +++ b/ui/app/components/send-token/index.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const h = require('react-hyperscript') const classnames = require('classnames') const abi = require('ethereumjs-abi') @@ -7,7 +7,7 @@ const inherits = require('util').inherits const actions = require('../../actions') const selectors = require('../../selectors') const { isValidAddress, allNull } = require('../../util') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage // const BalanceComponent = require('./balance-component') const Identicon = require('../identicon') @@ -127,14 +127,14 @@ SendTokenScreen.prototype.validate = function () { const amount = Number(stringAmount) const errors = { - to: !to ? t('required') : null, - amount: !amount ? t('required') : null, - gasPrice: !gasPrice ? t('gasPriceRequired') : null, - gasLimit: !gasLimit ? t('gasLimitRequired') : null, + to: !to ? t(this.props.localeMessages, 'required') : null, + amount: !amount ? t(this.props.localeMessages, 'required') : null, + gasPrice: !gasPrice ? t(this.props.localeMessages, 'gasPriceRequired') : null, + gasLimit: !gasLimit ? t(this.props.localeMessages, 'gasLimitRequired') : null, } if (to && !isValidAddress(to)) { - errors.to = t('invalidAddress') + errors.to = t(this.props.localeMessages, 'invalidAddress') } const isValid = Object.entries(errors).every(([key, value]) => value === null) @@ -238,7 +238,7 @@ SendTokenScreen.prototype.renderToAddressInput = function () { h('input.large-input.send-screen-input', { name: 'address', list: 'addresses', - placeholder: t('address'), + placeholder: t(this.props.localeMessages, 'address'), value: to, onChange: e => this.setState({ to: e.target.value, @@ -356,7 +356,7 @@ SendTokenScreen.prototype.renderGasInput = function () { }), h('div.send-screen-gas-labels', {}, [ - h('span', [ h('i.fa.fa-bolt'), t('gasFee') + ':']), + h('span', [ h('i.fa.fa-bolt'), t(this.props.localeMessages, 'gasFee') + ':']), h('span', [t('whatsThis')]), ]), h('div.large-input.send-screen-gas-input', [ diff --git a/ui/app/components/send/account-list-item.js b/ui/app/components/send/account-list-item.js index 1ad3f69c1..749339694 100644 --- a/ui/app/components/send/account-list-item.js +++ b/ui/app/components/send/account-list-item.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const Identicon = require('../identicon') const CurrencyDisplay = require('./currency-display') const { conversionRateSelector, getCurrentCurrency } = require('../../selectors') diff --git a/ui/app/components/send/gas-fee-display-v2.js b/ui/app/components/send/gas-fee-display-v2.js index 2aaa43350..c156e4482 100644 --- a/ui/app/components/send/gas-fee-display-v2.js +++ b/ui/app/components/send/gas-fee-display-v2.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const CurrencyDisplay = require('./currency-display') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage module.exports = GasFeeDisplay @@ -31,7 +31,7 @@ GasFeeDisplay.prototype.render = function () { convertedPrefix: '$', readOnly: true, }) - : h('div.currency-display', t('loading')), + : h('div.currency-display', t(this.props.localeMessages, 'loading')), h('button.send-v2__sliders-icon-container', { onClick, diff --git a/ui/app/components/send/gas-tooltip.js b/ui/app/components/send/gas-tooltip.js index 246c25152..8411fd61b 100644 --- a/ui/app/components/send/gas-tooltip.js +++ b/ui/app/components/send/gas-tooltip.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const InputNumber = require('../input-number.js') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage module.exports = GasTooltip diff --git a/ui/app/components/send/send-v2-container.js b/ui/app/components/send/send-v2-container.js index 1106902b7..a2a3ed389 100644 --- a/ui/app/components/send/send-v2-container.js +++ b/ui/app/components/send/send-v2-container.js @@ -1,4 +1,4 @@ -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const actions = require('../../actions') const abi = require('ethereumjs-abi') const SendEther = require('../../send-v2') diff --git a/ui/app/components/send/to-autocomplete.js b/ui/app/components/send/to-autocomplete.js index 1b0a1064a..ca034d855 100644 --- a/ui/app/components/send/to-autocomplete.js +++ b/ui/app/components/send/to-autocomplete.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const AccountListItem = require('./account-list-item') -const t = global.getMessage +const t = require('../../../i18n-helper').getMessage module.exports = ToAutoComplete @@ -93,7 +93,7 @@ ToAutoComplete.prototype.render = function () { return h('div.send-v2__to-autocomplete', {}, [ h('input.send-v2__to-autocomplete__input', { - placeholder: t('recipientAddress'), + placeholder: t(this.props.localeMessages, 'recipientAddress'), className: inError ? `send-v2__error-border` : '', value: to, onChange: event => onChange(event.target.value), diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js index 3f8c17932..46b16975a 100644 --- a/ui/app/components/shapeshift-form.js +++ b/ui/app/components/shapeshift-form.js @@ -1,13 +1,13 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const Component = require('react').Component -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const classnames = require('classnames') const { qrcode } = require('qrcode-npm') const { shapeShiftSubview, pairUpdate, buyWithShapeShift } = require('../actions') const { isValidAddress } = require('../util') const SimpleDropdown = require('./dropdowns/simple-dropdown') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage function mapStateToProps (state) { const { @@ -94,7 +94,7 @@ ShapeshiftForm.prototype.onBuyWithShapeShift = function () { })) .catch(() => this.setState({ showQrCode: false, - errorMessage: t('invalidRequest'), + errorMessage: t(this.props.localeMessages, 'invalidRequest'), isLoading: false, })) } @@ -126,10 +126,10 @@ ShapeshiftForm.prototype.renderMarketInfo = function () { return h('div.shapeshift-form__metadata', {}, [ - this.renderMetadata(t('status'), limit ? t('available') : t('unavailable')), - this.renderMetadata(t('limit'), limit), - this.renderMetadata(t('exchangeRate'), rate), - this.renderMetadata(t('min'), minimum), + this.renderMetadata(t(this.props.localeMessages, 'status'), limit ? t(this.props.localeMessages, 'available') : t(this.props.localeMessages, 'unavailable')), + this.renderMetadata(t(this.props.localeMessages, 'limit'), limit), + this.renderMetadata(t(this.props.localeMessages, 'exchangeRate'), rate), + this.renderMetadata(t(this.props.localeMessages, 'min'), minimum), ]) } @@ -143,7 +143,7 @@ ShapeshiftForm.prototype.renderQrCode = function () { return h('div.shapeshift-form', {}, [ h('div.shapeshift-form__deposit-instruction', [ - t('depositCoin', [depositCoin.toUpperCase()]), + t(this.props.localeMessages, 'depositCoin', [depositCoin.toUpperCase()]), ]), h('div', depositAddress), @@ -180,7 +180,7 @@ ShapeshiftForm.prototype.render = function () { h('div.shapeshift-form__selector', [ - h('div.shapeshift-form__selector-label', t('deposit')), + h('div.shapeshift-form__selector-label', t(this.props.localeMessages, 'deposit')), h(SimpleDropdown, { selectedOption: this.state.depositCoin, @@ -200,7 +200,7 @@ ShapeshiftForm.prototype.render = function () { h('div.shapeshift-form__selector', [ h('div.shapeshift-form__selector-label', [ - t('receive'), + t(this.props.localeMessages, 'receive'), ]), h('div.shapeshift-form__selector-input', ['ETH']), @@ -218,7 +218,7 @@ ShapeshiftForm.prototype.render = function () { }, [ h('div.shapeshift-form__address-input-label', [ - t('refundAddress'), + t(this.props.localeMessages, 'refundAddress'), ]), h('input.shapeshift-form__address-input', { diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index fddbc6821..cc401bc34 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -1,12 +1,12 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const vreme = new (require('vreme'))() const explorerLink = require('etherscan-link').createExplorerLink const actions = require('../actions') const addressSummary = require('../util').addressSummary -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage const CopyButton = require('./copyButton') const EthBalance = require('./eth-balance') @@ -76,7 +76,7 @@ ShiftListItem.prototype.renderUtilComponents = function () { value: this.props.depositAddress, }), h(Tooltip, { - title: t('qrCode'), + title: t(this.props.localeMessages, 'qrCode'), }, [ h('i.fa.fa-qrcode.pointer.pop-hover', { onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType)), @@ -136,8 +136,8 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, t('toETHviaShapeShift', [props.depositType])), - h('div', t('noDeposits')), + }, t(this.props.localeMessages, 'toETHviaShapeShift', [props.depositType])), + h('div', t(this.props.localeMessages, 'noDeposits')), h('div', { style: { fontSize: 'x-small', @@ -159,8 +159,8 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, t('toETHviaShapeShift', [props.depositType])), - h('div', t('conversionProgress')), + }, t(this.props.localeMessages, 'toETHviaShapeShift', [props.depositType])), + h('div', t(this.props.localeMessages, 'conversionProgress')), h('div', { style: { fontSize: 'x-small', @@ -185,7 +185,7 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, t('fromShapeShift')), + }, t(this.props.localeMessages, 'fromShapeShift')), h('div', formatDate(props.time)), h('div', { style: { @@ -197,7 +197,7 @@ ShiftListItem.prototype.renderInfo = function () { ]) case 'failed': - return h('span.error', '(' + t('failed') + ')') + return h('span.error', '(' + t(this.props.localeMessages, 'failed') + ')') default: return '' } diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index 7bf34e7b6..d6dd424ec 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -2,14 +2,14 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const Identicon = require('./identicon') -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const ethUtil = require('ethereumjs-util') const classnames = require('classnames') const AccountDropdownMini = require('./dropdowns/account-dropdown-mini') const actions = require('../actions') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage const { conversionUtil } = require('../conversion-util') const { @@ -55,7 +55,7 @@ SignatureRequest.prototype.renderHeader = function () { h('div.request-signature__header-background'), - h('div.request-signature__header__text', t('sigRequest')), + h('div.request-signature__header__text', t(this.props.localeMessages, 'sigRequest')), h('div.request-signature__header__tip-container', [ h('div.request-signature__header__tip'), @@ -137,7 +137,7 @@ SignatureRequest.prototype.renderRequestInfo = function () { return h('div.request-signature__request-info', [ h('div.request-signature__headline', [ - t('yourSigRequested'), + t(this.props.localeMessages, 'yourSigRequested'), ]), ]) @@ -155,18 +155,18 @@ SignatureRequest.prototype.msgHexToText = function (hex) { SignatureRequest.prototype.renderBody = function () { let rows - let notice = t('youSign') + ':' + let notice = t(this.props.localeMessages, 'youSign') + ':' const { txData } = this.props const { type, msgParams: { data } } = txData if (type === 'personal_sign') { - rows = [{ name: t('message'), value: this.msgHexToText(data) }] + rows = [{ name: t(this.props.localeMessages, 'message'), value: this.msgHexToText(data) }] } else if (type === 'eth_signTypedData') { rows = data } else if (type === 'eth_sign') { - rows = [{ name: t('message'), value: data }] - notice = t('signNotice') + rows = [{ name: t(this.props.localeMessages, 'message'), value: data }] + notice = t(this.props.localeMessages, 'signNotice') } return h('div.request-signature__body', {}, [ @@ -225,10 +225,10 @@ SignatureRequest.prototype.renderFooter = function () { return h('div.request-signature__footer', [ h('button.request-signature__footer__cancel-button', { onClick: cancel, - }, t('cancel')), + }, t(this.props.localeMessages, 'cancel')), h('button.request-signature__footer__sign-button', { onClick: sign, - }, t('sign')), + }, t(this.props.localeMessages, 'sign')), ]) } diff --git a/ui/app/components/token-balance.js b/ui/app/components/token-balance.js index 2f71c0687..7d7744fe6 100644 --- a/ui/app/components/token-balance.js +++ b/ui/app/components/token-balance.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const TokenTracker = require('eth-token-tracker') -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const selectors = require('../selectors') function mapStateToProps (state) { diff --git a/ui/app/components/token-cell.js b/ui/app/components/token-cell.js index 0332fde88..a24781af1 100644 --- a/ui/app/components/token-cell.js +++ b/ui/app/components/token-cell.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const Identicon = require('./identicon') const prefixForNetwork = require('../../lib/etherscan-prefix-for-network') const selectors = require('../selectors') diff --git a/ui/app/components/token-list.js b/ui/app/components/token-list.js index 01529aeda..439619158 100644 --- a/ui/app/components/token-list.js +++ b/ui/app/components/token-list.js @@ -3,9 +3,9 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const TokenTracker = require('eth-token-tracker') const TokenCell = require('./token-cell.js') -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const selectors = require('../selectors') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage function mapStateToProps (state) { return { @@ -43,7 +43,7 @@ TokenList.prototype.render = function () { const { tokens, isLoading, error } = state if (isLoading) { - return this.message(t('loadingTokens')) + return this.message(t(this.props.localeMessages, 'loadingTokens')) } if (error) { @@ -53,7 +53,7 @@ TokenList.prototype.render = function () { padding: '80px', }, }, [ - t('troubleTokenBalances'), + t(this.props.localeMessages, 'troubleTokenBalances'), h('span.hotFix', { style: { color: 'rgba(247, 134, 28, 1)', @@ -64,7 +64,7 @@ TokenList.prototype.render = function () { url: `https://ethplorer.io/address/${userAddress}`, }) }, - }, t('here')), + }, t(this.props.localeMessages, 'here')), ]) } diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js index 6d6e79bd5..50555f2f3 100644 --- a/ui/app/components/transaction-list-item.js +++ b/ui/app/components/transaction-list-item.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const EthBalance = require('./eth-balance') const addressSummary = require('../util').addressSummary @@ -11,7 +11,7 @@ const vreme = new (require('vreme'))() const Tooltip = require('./tooltip') const numberToBN = require('number-to-bn') const actions = require('../actions') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage const TransactionIcon = require('./transaction-list-item-icon') const ShiftListItem = require('./shift-list-item') @@ -86,7 +86,7 @@ TransactionListItem.prototype.render = function () { ]), h(Tooltip, { - title: t('transactionNumber'), + title: t(this.props.localeMessages, 'transactionNumber'), position: 'right', }, [ h('span', { @@ -143,12 +143,12 @@ TransactionListItem.prototype.render = function () { style: { paddingRight: '2px', }, - }, t('takesTooLong')), + }, t(this.props.localeMessages, 'takesTooLong')), h('div', { style: { textDecoration: 'underline', }, - }, t('retryWithMoreGas')), + }, t(this.props.localeMessages, 'retryWithMoreGas')), ]), ]) ) @@ -177,11 +177,11 @@ function recipientField (txParams, transaction, isTx, isMsg) { let message if (isMsg) { - message = t('sigRequested') + message = t(this.props.localeMessages, 'sigRequested') } else if (txParams.to) { message = addressSummary(txParams.to) } else { - message = t('contractDeployment') + message = t(this.props.localeMessages, 'contractDeployment') } return h('div', { @@ -204,7 +204,7 @@ function renderErrorOrWarning (transaction) { // show rejected if (status === 'rejected') { - return h('span.error', ' (' + t('rejected') + ')') + return h('span.error', ' (' + t(this.props.localeMessages, 'rejected') + ')') } if (transaction.err || transaction.warning) { const { err, warning = {} } = transaction @@ -220,7 +220,7 @@ function renderErrorOrWarning (transaction) { title: message, position: 'bottom', }, [ - h(`span.error`, ` (` + t('failed') + `)`), + h(`span.error`, ` (` + t(this.props.localeMessages, 'failed') + `)`), ]) ) } @@ -232,7 +232,7 @@ function renderErrorOrWarning (transaction) { title: message, position: 'bottom', }, [ - h(`span.warning`, ` (` + t('warning') + `)`), + h(`span.warning`, ` (` + t(this.props.localeMessages, 'warning') + `)`), ]) } } diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js index 07f7a06ae..66da7054e 100644 --- a/ui/app/components/transaction-list.js +++ b/ui/app/components/transaction-list.js @@ -3,7 +3,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const TransactionListItem = require('./transaction-list-item') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage module.exports = TransactionList @@ -79,7 +79,7 @@ TransactionList.prototype.render = function () { style: { marginTop: '50px', }, - }, t('noTransactionHistory')), + }, t(this.props.localeMessages, 'noTransactionHistory')), ]), ]), ]) diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index 849d70489..db8621434 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -1,6 +1,6 @@ const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const inherits = require('util').inherits const classnames = require('classnames') const abi = require('human-standard-token-abi') @@ -13,7 +13,7 @@ const { conversionUtil, multiplyCurrencies } = require('../conversion-util') const { calcTokenAmount } = require('../token-util') const { getCurrentCurrency } = require('../selectors') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage module.exports = connect(mapStateToProps)(TxListItem) @@ -64,7 +64,7 @@ TxListItem.prototype.getAddressText = function () { default: return address ? `${address.slice(0, 10)}...${address.slice(-4)}` - : t('contractDeployment') + : t(this.props.localeMessages, 'contractDeployment') } } diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js index 34dc837ae..d536b2806 100644 --- a/ui/app/components/tx-list.js +++ b/ui/app/components/tx-list.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const h = require('react-hyperscript') const inherits = require('util').inherits const prefixForNetwork = require('../../lib/etherscan-prefix-for-network') @@ -10,7 +10,7 @@ const { formatDate } = require('../util') const { showConfTxPage } = require('../actions') const classnames = require('classnames') const { tokenInfoGetter } = require('../token-util') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage module.exports = connect(mapStateToProps, mapDispatchToProps)(TxList) @@ -57,7 +57,7 @@ TxList.prototype.renderTransaction = function () { : [h( 'div.tx-list-item.tx-list-item--empty', { key: 'tx-list-none' }, - [ t('noTransactions') ], + [ t(this.props.localeMessages, 'noTransactions') ], )] } @@ -108,7 +108,7 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa if (isUnapproved) { opts.onClick = () => showConfTxPage({id: transActionId}) - opts.transactionStatus = t('Not Started') + opts.transactionStatus = t(this.props.localeMessages, 'Not Started') } else if (transactionHash) { opts.onClick = () => this.view(transactionHash, transactionNetworkId) } diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js index 96d776270..f7ca9cc97 100644 --- a/ui/app/components/tx-view.js +++ b/ui/app/components/tx-view.js @@ -1,11 +1,11 @@ const Component = require('react').Component -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const h = require('react-hyperscript') const ethUtil = require('ethereumjs-util') const inherits = require('util').inherits const actions = require('../actions') const selectors = require('../selectors') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage const BalanceComponent = require('./balance-component') const TxList = require('./tx-list') @@ -73,21 +73,21 @@ TxView.prototype.renderButtons = function () { onClick: () => showModal({ name: 'DEPOSIT_ETHER', }), - }, t('deposit')), + }, t(this.props.localeMessages, 'deposit')), h('button.btn-clear.hero-balance-button.allcaps', { style: { marginLeft: '0.8em', }, onClick: showSendPage, - }, t('send')), + }, t(this.props.localeMessages, 'send')), ]) ) : ( h('div.flex-row.flex-center.hero-balance-buttons', [ h('button.btn-clear.hero-balance-button', { onClick: showSendTokenPage, - }, t('send')), + }, t(this.props.localeMessages, 'send')), ]) ) } diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index 18452205c..54770e436 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const h = require('react-hyperscript') const inherits = require('util').inherits const classnames = require('classnames') @@ -11,7 +11,7 @@ const actions = require('../actions') const BalanceComponent = require('./balance-component') const TokenList = require('./token-list') const selectors = require('../selectors') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage module.exports = connect(mapStateToProps, mapDispatchToProps)(WalletView) @@ -117,7 +117,7 @@ WalletView.prototype.render = function () { onClick: hideSidebar, }), - h('div.wallet-view__keyring-label.allcaps', isLoose ? t('imported') : ''), + h('div.wallet-view__keyring-label.allcaps', isLoose ? t(this.props.localeMessages, 'imported') : ''), h('div.flex-column.flex-center.wallet-view__name-container', { style: { margin: '0 auto' }, @@ -134,13 +134,13 @@ WalletView.prototype.render = function () { selectedIdentity.name, ]), - h('button.btn-clear.wallet-view__details-button.allcaps', t('details')), + h('button.btn-clear.wallet-view__details-button.allcaps', t(this.props.localeMessages, 'details')), ]), ]), h(Tooltip, { position: 'bottom', - title: this.state.hasCopied ? t('copiedExclamation') : t('copyToClipboard'), + title: this.state.hasCopied ? t(this.props.localeMessages, 'copiedExclamation') : t(this.props.localeMessages, 'copyToClipboard'), wrapperClassName: 'wallet-view__tooltip', }, [ h('button.wallet-view__address', { @@ -173,7 +173,7 @@ WalletView.prototype.render = function () { showAddTokenPage() hideSidebar() }, - }, t('addToken')), + }, t(this.props.localeMessages, 'addToken')), ]) } diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js index b4ffc48b7..cbf5cd1d2 100644 --- a/ui/app/conf-tx.js +++ b/ui/app/conf-tx.js @@ -1,7 +1,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('react-redux').connect +const connect = require('./metamask-connect') const actions = require('./actions') const txHelper = require('../lib/tx-helper') diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js index 370fdd5b7..797718498 100644 --- a/ui/app/first-time/init-menu.js +++ b/ui/app/first-time/init-menu.js @@ -1,12 +1,12 @@ const inherits = require('util').inherits const EventEmitter = require('events').EventEmitter const Component = require('react').Component -const connect = require('react-redux').connect +const connect = require('../metamask-connect') const h = require('react-hyperscript') const Mascot = require('../components/mascot') const actions = require('../actions') const Tooltip = require('../components/tooltip') -const t = require('../../i18n') +const t = require('../../i18n-helper').getMessage const getCaretCoordinates = require('textarea-caret') const environmentType = require('../../../app/scripts/lib/environment-type') const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums @@ -60,7 +60,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: '#7F8082', marginBottom: 10, }, - }, t('appName')), + }, t(this.props.localeMessages, 'appName')), h('div', [ @@ -70,10 +70,10 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: '#7F8082', display: 'inline', }, - }, t('encryptNewDen')), + }, t(this.props.localeMessages, 'encryptNewDen')), h(Tooltip, { - title: t('denExplainer'), + title: t(this.props.localeMessages, 'denExplainer'), }, [ h('i.fa.fa-question-circle.pointer', { style: { @@ -93,7 +93,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: t('newPassword'), + placeholder: t(this.props.localeMessages, 'newPassword'), onInput: this.inputChanged.bind(this), style: { width: 260, @@ -105,7 +105,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box-confirm', - placeholder: t('confirmPassword'), + placeholder: t(this.props.localeMessages, 'confirmPassword'), onKeyPress: this.createVaultOnEnter.bind(this), onInput: this.inputChanged.bind(this), style: { @@ -120,7 +120,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { style: { margin: 12, }, - }, t('createDen')), + }, t(this.props.localeMessages, 'createDen')), h('.flex-row.flex-center.flex-grow', [ h('p.pointer', { @@ -130,7 +130,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: 'rgb(247, 134, 28)', textDecoration: 'underline', }, - }, t('importDen')), + }, t(this.props.localeMessages, 'importDen')), ]), h('.flex-row.flex-center.flex-grow', [ @@ -179,12 +179,12 @@ InitializeMenuScreen.prototype.createNewVaultAndKeychain = function () { var passwordConfirm = passwordConfirmBox.value if (password.length < 8) { - this.warning = t('passwordShort') + this.warning = t(this.props.localeMessages, 'passwordShort') this.props.dispatch(actions.displayWarning(this.warning)) return } if (password !== passwordConfirm) { - this.warning = t('passwordMismatch') + this.warning = t(this.props.localeMessages, 'passwordMismatch') this.props.dispatch(actions.displayWarning(this.warning)) return } diff --git a/ui/app/info.js b/ui/app/info.js index 49ff9f24a..3375478dd 100644 --- a/ui/app/info.js +++ b/ui/app/info.js @@ -1,7 +1,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('react-redux').connect +const connect = require('./metamask-connect') const actions = require('./actions') module.exports = connect(mapStateToProps)(InfoScreen) diff --git a/ui/app/keychains/hd/create-vault-complete.js b/ui/app/keychains/hd/create-vault-complete.js index 5ab5d4c33..9d99eeb0d 100644 --- a/ui/app/keychains/hd/create-vault-complete.js +++ b/ui/app/keychains/hd/create-vault-complete.js @@ -1,6 +1,6 @@ const inherits = require('util').inherits const Component = require('react').Component -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const h = require('react-hyperscript') const actions = require('../../actions') const exportAsFile = require('../../util').exportAsFile diff --git a/ui/app/keychains/hd/recover-seed/confirmation.js b/ui/app/keychains/hd/recover-seed/confirmation.js index 4335186a5..5f323f7a1 100644 --- a/ui/app/keychains/hd/recover-seed/confirmation.js +++ b/ui/app/keychains/hd/recover-seed/confirmation.js @@ -1,7 +1,7 @@ const inherits = require('util').inherits const Component = require('react').Component -const connect = require('react-redux').connect +const connect = require('../../../metamask-connect') const h = require('react-hyperscript') const actions = require('../../../actions') diff --git a/ui/app/keychains/hd/restore-vault.js b/ui/app/keychains/hd/restore-vault.js index cb4088f61..0a604f505 100644 --- a/ui/app/keychains/hd/restore-vault.js +++ b/ui/app/keychains/hd/restore-vault.js @@ -1,6 +1,6 @@ const inherits = require('util').inherits const PersistentForm = require('../../../lib/persistent-form') -const connect = require('react-redux').connect +const connect = require('../../metamask-connect') const h = require('react-hyperscript') const actions = require('../../actions') diff --git a/ui/app/metamask-connect.js b/ui/app/metamask-connect.js new file mode 100644 index 000000000..eef90529b --- /dev/null +++ b/ui/app/metamask-connect.js @@ -0,0 +1,18 @@ +const connect = require('react-redux').connect + +const metamaskConnect = (mapStateToProps, mapDispatchToProps) => { + return connect( + _higherOrderMapStateToProps(mapStateToProps), + mapDispatchToProps + ) +} + +const _higherOrderMapStateToProps = (mapStateToProps) => { + return (state, ownProps) => { + const stateProps = mapStateToProps(state, ownProps) + stateProps.localeMessages = state.localeMessages || {} + return stateProps + } +} + +module.exports = metamaskConnect \ No newline at end of file diff --git a/ui/app/new-keychain.js b/ui/app/new-keychain.js index cc9633166..6337faa08 100644 --- a/ui/app/new-keychain.js +++ b/ui/app/new-keychain.js @@ -1,7 +1,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('react-redux').connect +const connect = require('./metamask-connect') module.exports = connect(mapStateToProps)(NewKeychain) diff --git a/ui/app/reducers.js b/ui/app/reducers.js index 70b7e71dc..f155b2bf3 100644 --- a/ui/app/reducers.js +++ b/ui/app/reducers.js @@ -7,6 +7,7 @@ const copyToClipboard = require('copy-to-clipboard') const reduceIdentities = require('./reducers/identities') const reduceMetamask = require('./reducers/metamask') const reduceApp = require('./reducers/app') +const reduceLocale = require('./reducers/locale') window.METAMASK_CACHED_LOG_STATE = null @@ -38,6 +39,12 @@ function rootReducer (state, action) { state.appState = reduceApp(state, action) + // + // LocaleMessages + // + + state.localeMessages = reduceLocale(state, action) + window.METAMASK_CACHED_LOG_STATE = state return state } diff --git a/ui/app/reducers/locale.js b/ui/app/reducers/locale.js new file mode 100644 index 000000000..d8b78e1dd --- /dev/null +++ b/ui/app/reducers/locale.js @@ -0,0 +1,18 @@ +const extend = require('xtend') +const actions = require('../actions') +const MetamascaraPlatform = require('../../../app/scripts/platforms/window') +const environmentType = require('../../../app/scripts/lib/environment-type') +const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums + +module.exports = reduceMetamask + +function reduceMetamask (state, action) { + const localeMessagesState = extend({}, state.localeMessages) + + switch (action.type) { + case actions.SET_LOCALE_MESSAGES: + return action.value + default: + return localeMessagesState + } +} diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 4ca7d221e..611c55391 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -45,6 +45,7 @@ function reduceMetamask (state, action) { networkEndpointType: OLD_UI_NETWORK_TYPE, isRevealingSeedWords: false, welcomeScreenSeen: false, + currentLocale: 'ja', }, state.metamask) switch (action.type) { @@ -353,6 +354,11 @@ function reduceMetamask (state, action) { welcomeScreenSeen: true, }) + case action.SET_CURRENT_LOCALE: + return extend(metamaskState, { + currentLocale: action.value, + }) + default: return metamaskState diff --git a/ui/app/select-app.js b/ui/app/select-app.js index 193c98353..fca3decce 100644 --- a/ui/app/select-app.js +++ b/ui/app/select-app.js @@ -1,6 +1,6 @@ const inherits = require('util').inherits const Component = require('react').Component -const connect = require('react-redux').connect +const connect = require('./metamask-connect') const h = require('react-hyperscript') const App = require('./app') const OldApp = require('../../old-ui/app/app') diff --git a/ui/app/send.js b/ui/app/send.js index 517b7690d..b6fa0c0da 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -1,7 +1,7 @@ // const { inherits } = require('util') // const PersistentForm = require('../lib/persistent-form') // const h = require('react-hyperscript') -// const connect = require('react-redux').connect +// const connect = require('./metamask-connect') // const Identicon = require('./components/identicon') // const EnsInput = require('./components/ens-input') // const GasTooltip = require('./components/send/gas-tooltip') diff --git a/ui/app/settings.js b/ui/app/settings.js index 95b69e46e..708d11082 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -112,9 +112,9 @@ class Settings extends Component { } renderCurrentLocale () { - const { setCurrentLocale } = this.props - const currentLocaleName = global.translator.localeName - const currentLocale = locales.find(locale => locale.code === currentLocaleName) + const { updateCurrentLocale, currentLocale } = this.props + // const currentLocaleName = global.translator.localeName + // const currentLocale = locales.find(locale => locale.code === currentLocaleName) return h('div.settings__content-row', [ h('div.settings__content-item', [ @@ -126,11 +126,12 @@ class Settings extends Component { h(SimpleDropdown, { placeholder: 'Select Locale', options: getLocaleOptions(), - selectedOption: currentLocaleName, + selectedOption: currentLocale, onSelect: async (newLocale) => { - log('set new locale', newLocale) - await global.translator.setLocale(newLocale) - log('did set new locale', newLocale) + // log('set new locale', newLocale) + // await global.translator.setLocale(newLocale) + updateCurrentLocale(newLocale) + // log('did set new locale', newLocale) }, }), ]), @@ -468,6 +469,7 @@ const mapStateToProps = state => { metamask: state.metamask, warning: state.appState.warning, isMascara: state.metamask.isMascara, + currentLocale: state.metamask.currentLocale, } } @@ -479,6 +481,7 @@ const mapDispatchToProps = dispatch => { displayWarning: warning => dispatch(actions.displayWarning(warning)), revealSeedConfirmation: () => dispatch(actions.revealSeedConfirmation()), setUseBlockie: value => dispatch(actions.setUseBlockie(value)), + updateCurrentLocale: key => dispatch(actions.updateCurrentLocale(key)), setFeatureFlagToBeta: () => { return dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) .then(() => dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE))) diff --git a/ui/app/template.js b/ui/app/template.js index d15b30fd2..83228ca77 100644 --- a/ui/app/template.js +++ b/ui/app/template.js @@ -1,7 +1,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('react-redux').connect +const connect = require('./metamask-connect') module.exports = connect(mapStateToProps)(COMPONENTNAME) diff --git a/ui/app/unlock.js b/ui/app/unlock.js index ac97d04d0..8b58ba1a8 100644 --- a/ui/app/unlock.js +++ b/ui/app/unlock.js @@ -1,11 +1,11 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('react-redux').connect +const connect = require('./metamask-connect') const actions = require('./actions') const getCaretCoordinates = require('textarea-caret') const EventEmitter = require('events').EventEmitter -const t = require('../i18n') +const t = require('../i18n-helper').getMessage const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums const environmentType = require('../../app/scripts/lib/environment-type') @@ -41,7 +41,7 @@ UnlockScreen.prototype.render = function () { textTransform: 'uppercase', color: '#7F8082', }, - }, t('appName')), + }, t(this.props.localeMessages, 'appName')), h('input.large-input', { type: 'password', diff --git a/ui/i18n-helper.js b/ui/i18n-helper.js new file mode 100644 index 000000000..7ad8cd040 --- /dev/null +++ b/ui/i18n-helper.js @@ -0,0 +1,37 @@ +// cross-browser connection to extension i18n API +const extension = require('extensionizer') +const log = require('loglevel') + +const getMessage = (locale, key, substitutions) => { + // check locale is loaded + if (!locale) { + // throw new Error('Translator - has not loaded a locale yet.') + return '' + } + // check entry is present + const entry = locale[key] + if (!entry) { + log.error(`Translator - Unable to find value for "${key}"`) + throw new Error(`Translator - Unable to find value for "${key}"`) + } + let phrase = entry.message + // perform substitutions + if (substitutions && substitutions.length) { + phrase = phrase.replace(/\$1/g, substitutions[0]) + if (substitutions.length > 1) { + phrase = phrase.replace(/\$2/g, substitutions[1]) + } + } + return phrase +} + +async function fetchLocale (localeName) { + const response = await fetch(`/_locales/${localeName}/messages.json`) + const locale = await response.json() + return locale +} + +module.exports = { + getMessage, + fetchLocale, +} diff --git a/ui/index.js b/ui/index.js index fdb2f23e0..c680accfe 100644 --- a/ui/index.js +++ b/ui/index.js @@ -4,6 +4,7 @@ const Root = require('./app/root') const actions = require('./app/actions') const configureStore = require('./app/store') const txHelper = require('./lib/tx-helper') +const { fetchLocale } = require('./i18n-helper').getMessage const { OLD_UI_NETWORK_TYPE, BETA_UI_NETWORK_TYPE } = require('../app/scripts/config').enums global.log = require('loglevel') @@ -18,14 +19,17 @@ function launchMetamaskUi (opts, cb) { // check if we are unlocked first accountManager.getState(function (err, metamaskState) { if (err) return cb(err) - const store = startApp(metamaskState, accountManager, opts) - cb(null, store) + startApp(metamaskState, accountManager, opts.localeMessages, opts) + .then((store) => { + cb(null, store) + }) }) } -function startApp (metamaskState, accountManager, opts) { +async function startApp (metamaskState, accountManager, currentLocaleMessages, opts) { // parse opts if (!metamaskState.featureFlags) metamaskState.featureFlags = {} + const store = configureStore({ // metamaskState represents the cross-tab state @@ -34,6 +38,8 @@ function startApp (metamaskState, accountManager, opts) { // appState represents the current tab's popup state appState: {}, + localeMessages: currentLocaleMessages, + // Which blockchain we are using: networkVersion: opts.networkVersion, }) From a51e8f6a165163b9cc37a4eb5b315cd37af17f77 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 19 Mar 2018 13:36:16 -0230 Subject: [PATCH 009/246] Fetch localeMessages in front end only. --- app/scripts/popup-core.js | 4 ++-- app/scripts/popup.js | 12 +----------- ui/index.js | 8 +++++--- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/app/scripts/popup-core.js b/app/scripts/popup-core.js index 5af913e98..2e4334bb1 100644 --- a/app/scripts/popup-core.js +++ b/app/scripts/popup-core.js @@ -11,11 +11,11 @@ const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex module.exports = initializePopup -function initializePopup ({ container, connectionStream, localeMessages }, cb) { +function initializePopup ({ container, connectionStream }, cb) { // setup app async.waterfall([ (cb) => connectToAccountManager(connectionStream, cb), - (accountManager, cb) => launchMetamaskUi({ container, accountManager, localeMessages }, cb), + (accountManager, cb) => launchMetamaskUi({ container, accountManager }, cb), ], cb) } diff --git a/app/scripts/popup.js b/app/scripts/popup.js index fe6aae799..5f526759a 100644 --- a/app/scripts/popup.js +++ b/app/scripts/popup.js @@ -1,9 +1,3 @@ -// setup i18n -// const Translator = require('../../ui/create-i18n') -// const translator = new Translator() -// global.translator = translator -// global.getMessage = translator.getMessage.bind(translator) - const injectCss = require('inject-css') const OldMetaMaskUiCss = require('../../old-ui/css') const NewMetaMaskUiCss = require('../../ui/css') @@ -28,10 +22,6 @@ async function start() { const release = global.platform.getVersion() setupRaven({ release }) - // Load translator - // await translator.setLocale('ja') - const localeMessages = await fetchLocale('ja') - // inject css // const css = MetaMaskUiCss() // injectCss(css) @@ -47,7 +37,7 @@ async function start() { // start ui const container = document.getElementById('app-content') - startPopup({ container, connectionStream, localeMessages }, (err, store) => { + startPopup({ container, connectionStream }, (err, store) => { if (err) return displayCriticalError(err) // Code commented out until we begin auto adding users to NewUI diff --git a/ui/index.js b/ui/index.js index c680accfe..598d2876b 100644 --- a/ui/index.js +++ b/ui/index.js @@ -4,7 +4,7 @@ const Root = require('./app/root') const actions = require('./app/actions') const configureStore = require('./app/store') const txHelper = require('./lib/tx-helper') -const { fetchLocale } = require('./i18n-helper').getMessage +const { fetchLocale } = require('./i18n-helper') const { OLD_UI_NETWORK_TYPE, BETA_UI_NETWORK_TYPE } = require('../app/scripts/config').enums global.log = require('loglevel') @@ -19,17 +19,19 @@ function launchMetamaskUi (opts, cb) { // check if we are unlocked first accountManager.getState(function (err, metamaskState) { if (err) return cb(err) - startApp(metamaskState, accountManager, opts.localeMessages, opts) + startApp(metamaskState, accountManager, opts) .then((store) => { cb(null, store) }) }) } -async function startApp (metamaskState, accountManager, currentLocaleMessages, opts) { +async function startApp (metamaskState, accountManager, opts) { // parse opts if (!metamaskState.featureFlags) metamaskState.featureFlags = {} + const currentLocaleMessages = await fetchLocale(metamaskState.currentLocale) + const store = configureStore({ // metamaskState represents the cross-tab state From 3191f2aa5ec4530df6dad6a750d60b797a84bda0 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 19 Mar 2018 13:37:07 -0230 Subject: [PATCH 010/246] Delete old i18n helper files. --- ui/create-i18n.js | 43 ------------------------------------------- ui/i18n.js | 33 --------------------------------- 2 files changed, 76 deletions(-) delete mode 100644 ui/create-i18n.js delete mode 100644 ui/i18n.js diff --git a/ui/create-i18n.js b/ui/create-i18n.js deleted file mode 100644 index c80f5351a..000000000 --- a/ui/create-i18n.js +++ /dev/null @@ -1,43 +0,0 @@ -// cross-browser connection to extension i18n API -const extension = require('extensionizer') -const log = require('loglevel') - - -class Translator { - - async setLocale(localeName) { - this.localeName = localeName - this.locale = await fetchLocale(localeName) - } - - getMessage (key, substitutions) { - // check locale is loaded - if (!this.locale) { - throw new Error('Translator - has not loaded a locale yet') - } - // check entry is present - const entry = this.locale[key] - if (!entry) { - log.error(`Translator - Unable to find value for "${key}"`) - throw new Error(`Translator - Unable to find value for "${key}"`) - } - let phrase = entry.message - // perform substitutions - if (substitutions && substitutions.length) { - phrase = phrase.replace(/\$1/g, substitutions[0]) - if (substitutions.length > 1) { - phrase = phrase.replace(/\$2/g, substitutions[1]) - } - } - return phrase - } - -} - -async function fetchLocale (localeName) { - const response = await fetch(`/_locales/${localeName}/messages.json`) - const locale = await response.json() - return locale -} - -module.exports = Translator diff --git a/ui/i18n.js b/ui/i18n.js deleted file mode 100644 index abfece426..000000000 --- a/ui/i18n.js +++ /dev/null @@ -1,33 +0,0 @@ - -// cross-browser connection to extension i18n API - -const chrome = chrome || null -const browser = browser || null -const extension = require('extensionizer') -var log = require('loglevel') -window.log = log -let getMessage - -if (extension.i18n && extension.i18n.getMessage) { - getMessage = extension.i18n.getMessage -} else { - // fallback function - log.warn('browser.i18n API not available, calling back to english.') - const msg = require('../app/_locales/en/messages.json') - getMessage = function (key, substitutions) { - if (!msg[key]) { - log.error(key) - throw new Error(key) - } - let phrase = msg[key].message - if (substitutions && substitutions.length) { - phrase = phrase.replace(/\$1/g, substitutions[0]) - if (substitutions.length > 1) { - phrase = phrase.replace(/\$2/g, substitutions[1]) - } - } - return phrase - } -} - -module.exports = getMessage From 98f934fb53b0ff66c3de3d11e1ea22b54f956fe6 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 19 Mar 2018 13:38:22 -0230 Subject: [PATCH 011/246] Delete commented out code from i18n implementation that used globals. --- ui/app/settings.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ui/app/settings.js b/ui/app/settings.js index 708d11082..809792f79 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -113,8 +113,6 @@ class Settings extends Component { renderCurrentLocale () { const { updateCurrentLocale, currentLocale } = this.props - // const currentLocaleName = global.translator.localeName - // const currentLocale = locales.find(locale => locale.code === currentLocaleName) return h('div.settings__content-row', [ h('div.settings__content-item', [ @@ -128,10 +126,7 @@ class Settings extends Component { options: getLocaleOptions(), selectedOption: currentLocale, onSelect: async (newLocale) => { - // log('set new locale', newLocale) - // await global.translator.setLocale(newLocale) updateCurrentLocale(newLocale) - // log('did set new locale', newLocale) }, }), ]), From 09260f9c5e0b2c460a214f00b87c8fafe0470419 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 19 Mar 2018 16:23:54 -0230 Subject: [PATCH 012/246] Fixed t() calls where localeMessages is missing; and fix incorrect connect reference. --- ui/app/components/customize-gas-modal/index.js | 6 +++--- ui/app/components/modals/deposit-ether-modal.js | 2 +- ui/app/components/modals/edit-account-name-modal.js | 2 +- ui/app/components/modals/new-account-modal.js | 2 +- ui/app/components/modals/notification-modal.js | 6 +++--- .../modals/notification-modals/confirm-reset-account.js | 2 +- ui/app/components/network.js | 5 ++++- ui/app/components/pending-tx/confirm-deploy-contract.js | 2 +- ui/app/components/pending-tx/confirm-send-ether.js | 2 +- ui/app/components/pending-tx/confirm-send-token.js | 2 +- ui/app/components/pending-tx/index.js | 2 +- ui/app/components/send/gas-tooltip.js | 2 +- ui/app/components/sender-to-recipient.js | 2 +- ui/app/components/shapeshift-form.js | 2 +- ui/app/components/signature-request.js | 4 ++-- ui/app/metamask-connect.js | 6 ++++-- ui/app/settings.js | 2 +- ui/i18n-helper.js | 2 +- 18 files changed, 29 insertions(+), 24 deletions(-) diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index 8e3960ce4..ed0a3b45e 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -280,16 +280,16 @@ CustomizeGasModal.prototype.render = function () { h('div.send-v2__customize-gas__revert', { onClick: () => this.revert(), - }, [t('revert')]), + }, [t(this.props.localeMessages, 'revert')]), h('div.send-v2__customize-gas__buttons', [ h('div.send-v2__customize-gas__cancel.allcaps', { onClick: this.props.hideModal, - }, [t('cancel')]), + }, [t(this.props.localeMessages, 'cancel')]), h(`div.send-v2__customize-gas__save${error ? '__error' : ''}.allcaps`, { onClick: () => !error && this.save(gasPrice, gasLimit, gasTotal), - }, [t('save')]), + }, [t(this.props.localeMessages, 'save')]), ]), ]), diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index 500a225c7..307e89a47 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -123,7 +123,7 @@ DepositEtherModal.prototype.render = function () { h('div.page-container__header', [ - h('div.page-container__title', [t('depositEther')]), + h('div.page-container__title', [t(this.props.localeMessages, 'depositEther')]), h('div.page-container__subtitle', [ t(this.props.localeMessages, 'needEtherInWallet'), diff --git a/ui/app/components/modals/edit-account-name-modal.js b/ui/app/components/modals/edit-account-name-modal.js index 02de5b99c..a64a41b27 100644 --- a/ui/app/components/modals/edit-account-name-modal.js +++ b/ui/app/components/modals/edit-account-name-modal.js @@ -51,7 +51,7 @@ EditAccountNameModal.prototype.render = function () { ]), h('div.edit-account-name-modal-title', { - }, [t('editAccountName')]), + }, [t(this.props.localeMessages, 'editAccountName')]), h('input.edit-account-name-modal-input', { placeholder: identity.name, diff --git a/ui/app/components/modals/new-account-modal.js b/ui/app/components/modals/new-account-modal.js index 7f9b7a154..2744af0b3 100644 --- a/ui/app/components/modals/new-account-modal.js +++ b/ui/app/components/modals/new-account-modal.js @@ -1,7 +1,7 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const { connect } = require('react-redux') +const connect = require('../../metamask-connect') const actions = require('../../actions') const t = require('../../../i18n-helper').getMessage diff --git a/ui/app/components/modals/notification-modal.js b/ui/app/components/modals/notification-modal.js index c05d80251..ba2c92c92 100644 --- a/ui/app/components/modals/notification-modal.js +++ b/ui/app/components/modals/notification-modal.js @@ -1,7 +1,7 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const { connect } = require('react-redux') +const connect = require('../../metamask-connect') const actions = require('../../actions') const t = require('../../../i18n-helper').getMessage @@ -23,12 +23,12 @@ class NotificationModal extends Component { }, [ h('div.notification-modal__header', {}, [ - t(header), + t(this.props.localeMessages, header), ]), h('div.notification-modal__message-wrapper', {}, [ h('div.notification-modal__message', {}, [ - t(message), + t(this.props.localeMessages, message), ]), ]), diff --git a/ui/app/components/modals/notification-modals/confirm-reset-account.js b/ui/app/components/modals/notification-modals/confirm-reset-account.js index e1bc91b24..94ee997ab 100644 --- a/ui/app/components/modals/notification-modals/confirm-reset-account.js +++ b/ui/app/components/modals/notification-modals/confirm-reset-account.js @@ -1,7 +1,7 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const { connect } = require('react-redux') +const connect = require('../../../metamask-connect') const actions = require('../../../actions') const NotifcationModal = require('../notification-modal') diff --git a/ui/app/components/network.js b/ui/app/components/network.js index d3a36b012..25003fd16 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -1,11 +1,12 @@ const Component = require('react').Component const h = require('react-hyperscript') +const connect = require('../metamask-connect') const classnames = require('classnames') const inherits = require('util').inherits const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') const t = require('../../i18n-helper').getMessage -module.exports = Network +module.exports = connect()(Network) inherits(Network, Component) @@ -78,6 +79,8 @@ Network.prototype.render = function () { }, }, [ (function () { + console.log(`12312312312312312 props.localeMessages`, props.localeMessages); + console.log(`12312312312312312 t(props.localeMessages, 'mainnet')`, t(props.localeMessages, 'mainnet')); switch (iconName) { case 'ethereum-network': return h('.network-indicator', [ diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index 340653422..bc93ad2f7 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -1,5 +1,5 @@ const { Component } = require('react') -const { connect } = require('react-redux') +const connect = require('../../metamask-connect') const h = require('react-hyperscript') const PropTypes = require('prop-types') const actions = require('../../actions') diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index be3a9d993..3a72f575f 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const { connect } = require('react-redux') +const connect = require('../../metamask-connect') const h = require('react-hyperscript') const inherits = require('util').inherits const actions = require('../../actions') diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index fe5c80711..238223321 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const { connect } = require('react-redux') +const connect = require('../../metamask-connect') const h = require('react-hyperscript') const inherits = require('util').inherits const tokenAbi = require('human-standard-token-abi') diff --git a/ui/app/components/pending-tx/index.js b/ui/app/components/pending-tx/index.js index f4f6afb8f..e490a45f4 100644 --- a/ui/app/components/pending-tx/index.js +++ b/ui/app/components/pending-tx/index.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const { connect } = require('react-redux') +const connect = require('../../metamask-connect') const h = require('react-hyperscript') const clone = require('clone') const abi = require('human-standard-token-abi') diff --git a/ui/app/components/send/gas-tooltip.js b/ui/app/components/send/gas-tooltip.js index 8411fd61b..7bdb164c7 100644 --- a/ui/app/components/send/gas-tooltip.js +++ b/ui/app/components/send/gas-tooltip.js @@ -82,7 +82,7 @@ GasTooltip.prototype.render = function () { 'marginTop': '81px', }, }, [ - h('span.gas-tooltip-label', {}, [t('gasLimit')]), + h('span.gas-tooltip-label', {}, [t(this.props.localeMessages, 'gasLimit')]), h('i.fa.fa-info-circle'), ]), h(InputNumber, { diff --git a/ui/app/components/sender-to-recipient.js b/ui/app/components/sender-to-recipient.js index a0e90a37f..530c4abae 100644 --- a/ui/app/components/sender-to-recipient.js +++ b/ui/app/components/sender-to-recipient.js @@ -30,7 +30,7 @@ class SenderToRecipient extends Component { ]), h('.sender-to-recipient__recipient', [ h('i.fa.fa-file-text-o'), - h('.sender-to-recipient__name.sender-to-recipient__recipient-name', t('newContract')), + h('.sender-to-recipient__name.sender-to-recipient__recipient-name', t(this.props.localeMessages, 'newContract')), ]), ]) ) diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js index 46b16975a..f915135f6 100644 --- a/ui/app/components/shapeshift-form.js +++ b/ui/app/components/shapeshift-form.js @@ -240,7 +240,7 @@ ShapeshiftForm.prototype.render = function () { className: btnClass, disabled: !token, onClick: () => this.onBuyWithShapeShift(), - }, [t('buy')]), + }, [t(this.props.localeMessages, 'buy')]), ]) } diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index d6dd424ec..7f4493b66 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -76,7 +76,7 @@ SignatureRequest.prototype.renderAccountDropdown = function () { return h('div.request-signature__account', [ - h('div.request-signature__account-text', [t('account') + ':']), + h('div.request-signature__account-text', [t(this.props.localeMessages, 'account') + ':']), h(AccountDropdownMini, { selectedAccount, @@ -103,7 +103,7 @@ SignatureRequest.prototype.renderBalance = function () { return h('div.request-signature__balance', [ - h('div.request-signature__balance-text', [t('balance')]), + h('div.request-signature__balance-text', [t(this.props.localeMessages, 'balance')]), h('div.request-signature__balance-value', `${balanceInEther} ETH`), diff --git a/ui/app/metamask-connect.js b/ui/app/metamask-connect.js index eef90529b..d13f8e87e 100644 --- a/ui/app/metamask-connect.js +++ b/ui/app/metamask-connect.js @@ -8,8 +8,10 @@ const metamaskConnect = (mapStateToProps, mapDispatchToProps) => { } const _higherOrderMapStateToProps = (mapStateToProps) => { - return (state, ownProps) => { - const stateProps = mapStateToProps(state, ownProps) + return (state, ownProps = {}) => { + const stateProps = mapStateToProps + ? mapStateToProps(state, ownProps) + : ownProps stateProps.localeMessages = state.localeMessages || {} return stateProps } diff --git a/ui/app/settings.js b/ui/app/settings.js index 809792f79..2280b189b 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -1,7 +1,7 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const { connect } = require('react-redux') +const connect = require('./metamask-connect') const actions = require('./actions') const infuraCurrencies = require('./infura-conversion.json') const validUrl = require('valid-url') diff --git a/ui/i18n-helper.js b/ui/i18n-helper.js index 7ad8cd040..345e83f00 100644 --- a/ui/i18n-helper.js +++ b/ui/i18n-helper.js @@ -12,7 +12,7 @@ const getMessage = (locale, key, substitutions) => { const entry = locale[key] if (!entry) { log.error(`Translator - Unable to find value for "${key}"`) - throw new Error(`Translator - Unable to find value for "${key}"`) + // throw new Error(`Translator - Unable to find value for "${key}"`) } let phrase = entry.message // perform substitutions From 2ddc2cc1fbe5249f70d80e2a74146cb87dcc8421 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 19 Mar 2018 16:53:06 -0230 Subject: [PATCH 013/246] Lint fixes. --- app/scripts/popup.js | 1 - ui/app/accounts/import/index.js | 1 + ui/app/accounts/import/json.js | 1 + ui/app/accounts/new-account/create-form.js | 1 + ui/app/actions.js | 1 - ui/app/components/account-dropdowns.js | 2 ++ ui/app/components/dropdowns/components/account-dropdowns.js | 1 + ui/app/components/modals/new-account-modal.js | 1 + ui/app/components/modals/notification-modal.js | 1 + ui/app/components/network.js | 2 -- ui/app/components/pending-tx/confirm-deploy-contract.js | 3 ++- ui/app/components/pending-tx/confirm-send-token.js | 3 ++- ui/app/components/sender-to-recipient.js | 6 +++++- ui/app/reducers/locale.js | 3 --- ui/app/settings.js | 2 ++ ui/i18n-helper.js | 1 - 16 files changed, 19 insertions(+), 11 deletions(-) diff --git a/app/scripts/popup.js b/app/scripts/popup.js index 5f526759a..6ef0be1ff 100644 --- a/app/scripts/popup.js +++ b/app/scripts/popup.js @@ -9,7 +9,6 @@ const ExtensionPlatform = require('./platforms/extension') const NotificationManager = require('./lib/notification-manager') const notificationManager = new NotificationManager() const setupRaven = require('./lib/setupRaven') -const { fetchLocale } = require('../../ui/i18n-helper.js') start().catch(log.error) diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js index ab5344dc6..98924b6d9 100644 --- a/ui/app/accounts/import/index.js +++ b/ui/app/accounts/import/index.js @@ -2,6 +2,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') const connect = require('../../metamask-connect') +const t = require('../../../i18n-helper').getMessage import Select from 'react-select' // Subviews diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index b3f412e98..f638e07c5 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -113,6 +113,7 @@ JsonImportSubview.propTypes = { goHome: PropTypes.func, displayWarning: PropTypes.func, importNewJsonAccount: PropTypes.func, + localeMessages: PropTypes.object, } const mapStateToProps = state => { diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js index 38cffec64..6eed0215c 100644 --- a/ui/app/accounts/new-account/create-form.js +++ b/ui/app/accounts/new-account/create-form.js @@ -62,6 +62,7 @@ NewAccountCreateForm.propTypes = { createAccount: PropTypes.func, goHome: PropTypes.func, numberOfExistingAccounts: PropTypes.number, + localeMessages: PropTypes.object, } const mapStateToProps = state => { diff --git a/ui/app/actions.js b/ui/app/actions.js index 4749d0735..12cf10411 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -1802,7 +1802,6 @@ function updateCurrentLocale (key) { return (dispatch) => { dispatch(actions.showLoadingIndication()) log.debug(`background.updateCurrentLocale`) - console.log(`fetchLocale`, fetchLocale); fetchLocale(key) .then((localeMessages) => { background.setCurrentLocale(key, (err) => { diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index 1f870a27c..f725e7d86 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -9,6 +9,7 @@ const DropdownMenuItem = require('./dropdown').DropdownMenuItem const Identicon = require('./identicon') const ethUtil = require('ethereumjs-util') const copyToClipboard = require('copy-to-clipboard') +const t = require('../../i18n-helper').getMessage class AccountDropdowns extends Component { constructor (props) { @@ -300,6 +301,7 @@ AccountDropdowns.propTypes = { style: PropTypes.object, enableAccountOptions: PropTypes.bool, enableAccountsSelector: PropTypes.bool, + localeMessages: PropTypes.object, } const mapDispatchToProps = (dispatch) => { diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index 73afb7009..6de4d8280 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -426,6 +426,7 @@ AccountDropdowns.propTypes = { enableAccountsSelector: PropTypes.bool, enableAccountOption: PropTypes.bool, enableAccountOptions: PropTypes.bool, + localeMessages: PropTypes.object, } const mapDispatchToProps = (dispatch) => { diff --git a/ui/app/components/modals/new-account-modal.js b/ui/app/components/modals/new-account-modal.js index 2744af0b3..23613ec9c 100644 --- a/ui/app/components/modals/new-account-modal.js +++ b/ui/app/components/modals/new-account-modal.js @@ -70,6 +70,7 @@ NewAccountModal.propTypes = { showImportPage: PropTypes.func, createAccount: PropTypes.func, numberOfExistingAccounts: PropTypes.number, + localeMessages: PropTypes.object, } const mapStateToProps = state => { diff --git a/ui/app/components/modals/notification-modal.js b/ui/app/components/modals/notification-modal.js index ba2c92c92..3898f1c44 100644 --- a/ui/app/components/modals/notification-modal.js +++ b/ui/app/components/modals/notification-modal.js @@ -63,6 +63,7 @@ NotificationModal.propTypes = { showCancelButton: PropTypes.bool, showConfirmButton: PropTypes.bool, onConfirm: PropTypes.func, + localeMessages: PropTypes.object, } const mapDispatchToProps = dispatch => { diff --git a/ui/app/components/network.js b/ui/app/components/network.js index 25003fd16..55bc14c3c 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -79,8 +79,6 @@ Network.prototype.render = function () { }, }, [ (function () { - console.log(`12312312312312312 props.localeMessages`, props.localeMessages); - console.log(`12312312312312312 t(props.localeMessages, 'mainnet')`, t(props.localeMessages, 'mainnet')); switch (iconName) { case 'ethereum-network': return h('.network-indicator', [ diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index bc93ad2f7..8e04fb84d 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -321,6 +321,7 @@ ConfirmDeployContract.propTypes = { conversionRate: PropTypes.number, currentCurrency: PropTypes.string, selectedAddress: PropTypes.string, + localeMessages: PropTypes.object, } const mapStateToProps = state => { @@ -347,4 +348,4 @@ const mapDispatchToProps = dispatch => { } } -module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmDeployContract) \ No newline at end of file +module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmDeployContract) diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index 238223321..4cd6f020b 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -378,7 +378,8 @@ ConfirmSendToken.prototype.render = function () { this.renderTotalPlusGas(), - ]) + ]), + ]), h('form#pending-tx-form', { diff --git a/ui/app/components/sender-to-recipient.js b/ui/app/components/sender-to-recipient.js index 530c4abae..02b6d96ea 100644 --- a/ui/app/components/sender-to-recipient.js +++ b/ui/app/components/sender-to-recipient.js @@ -1,5 +1,6 @@ const { Component } = require('react') const h = require('react-hyperscript') +const connect = require('../metamask-connect') const PropTypes = require('prop-types') const t = require('../../i18n-helper').getMessage const Identicon = require('./identicon') @@ -40,6 +41,9 @@ class SenderToRecipient extends Component { SenderToRecipient.propTypes = { senderName: PropTypes.string, senderAddress: PropTypes.string, + localeMessages: PropTypes.object, } -module.exports = SenderToRecipient +module.exports = { + AccountDropdowns: connect()(SenderToRecipient), +} \ No newline at end of file diff --git a/ui/app/reducers/locale.js b/ui/app/reducers/locale.js index d8b78e1dd..edfe9e865 100644 --- a/ui/app/reducers/locale.js +++ b/ui/app/reducers/locale.js @@ -1,8 +1,5 @@ const extend = require('xtend') const actions = require('../actions') -const MetamascaraPlatform = require('../../../app/scripts/platforms/window') -const environmentType = require('../../../app/scripts/lib/environment-type') -const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums module.exports = reduceMetamask diff --git a/ui/app/settings.js b/ui/app/settings.js index 2280b189b..1412606e5 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -457,6 +457,8 @@ Settings.propTypes = { warning: PropTypes.string, goHome: PropTypes.func, isMascara: PropTypes.bool, + updateCurrentLocale: PropTypes.func, + currentLocale: PropTypes.object, } const mapStateToProps = state => { diff --git a/ui/i18n-helper.js b/ui/i18n-helper.js index 345e83f00..10147b0f6 100644 --- a/ui/i18n-helper.js +++ b/ui/i18n-helper.js @@ -1,5 +1,4 @@ // cross-browser connection to extension i18n API -const extension = require('extensionizer') const log = require('loglevel') const getMessage = (locale, key, substitutions) => { From 9094af8319086f075c71814bec00c144aca0d67c Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 21 Mar 2018 17:39:53 +0000 Subject: [PATCH 014/246] chore(package): update sinon to version 5.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8f05bc7f1..25bc27c19 100644 --- a/package.json +++ b/package.json @@ -247,7 +247,7 @@ "react-test-renderer": "^15.6.2", "react-testutils-additions": "^15.2.0", "redux-test-utils": "^0.2.2", - "sinon": "^4.0.0", + "sinon": "^5.0.0", "stylelint-config-standard": "^18.2.0", "tape": "^4.5.1", "testem": "^2.0.0", From d24a0590d363dbe88d383c8faec8eb28809242f0 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 21 Mar 2018 22:11:47 -0230 Subject: [PATCH 015/246] i18n redux solution doesn't require importing t() and passing state to each t() call; t is just available on props. --- app/_locales/en/messages.json | 2 +- app/_locales/es/messages.json | 2 +- app/_locales/it/messages.json | 2 +- app/_locales/pt/messages.json | 2 +- ui/app/accounts/import/index.js | 15 +- ui/app/accounts/import/json.js | 17 +- ui/app/accounts/import/private-key.js | 7 +- ui/app/accounts/import/seed.js | 5 +- ui/app/accounts/new-account/create-form.js | 9 +- ui/app/accounts/new-account/index.js | 7 +- ui/app/add-token.js | 43 ++-- ui/app/app.js | 25 +- ui/app/components/account-dropdowns.js | 15 +- ui/app/components/account-export.js | 15 +- ui/app/components/account-menu/index.js | 15 +- ui/app/components/bn-as-decimal-input.js | 12 +- ui/app/components/buy-button-subview.js | 11 +- ui/app/components/coinbase-form.js | 5 +- ui/app/components/copyButton.js | 6 +- ui/app/components/copyable.js | 6 +- .../components/customize-gas-modal/index.js | 21 +- .../dropdowns/components/account-dropdowns.js | 19 +- .../components/dropdowns/network-dropdown.js | 27 +-- .../dropdowns/token-menu-dropdown.js | 3 +- ui/app/components/ens-input.js | 8 +- ui/app/components/hex-as-decimal-input.js | 12 +- .../modals/account-details-modal.js | 5 +- .../modals/account-modal-container.js | 3 +- ui/app/components/modals/buy-options-modal.js | 15 +- .../components/modals/deposit-ether-modal.js | 29 ++- .../modals/edit-account-name-modal.js | 5 +- .../modals/export-private-key-modal.js | 13 +- .../modals/hide-token-confirmation-modal.js | 9 +- ui/app/components/modals/modal.js | 2 +- ui/app/components/modals/new-account-modal.js | 13 +- .../components/modals/notification-modal.js | 5 +- ui/app/components/network.js | 25 +- ui/app/components/notice.js | 6 +- ui/app/components/pending-msg-details.js | 6 +- ui/app/components/pending-msg.js | 14 +- .../pending-tx/confirm-deploy-contract.js | 25 +- .../pending-tx/confirm-send-ether.js | 19 +- .../pending-tx/confirm-send-token.js | 35 ++- ui/app/components/send/currency-display.js | 2 +- ui/app/components/send/gas-fee-display-v2.js | 8 +- ui/app/components/send/gas-tooltip.js | 6 +- ui/app/components/send/send-v2-container.js | 1 + ui/app/components/send/to-autocomplete.js | 6 +- ui/app/components/sender-to-recipient.js | 3 +- ui/app/components/shapeshift-form.js | 21 +- ui/app/components/shift-list-item.js | 15 +- ui/app/components/signature-request.js | 21 +- ui/app/components/token-list.js | 7 +- ui/app/components/tx-list-item.js | 19 +- ui/app/components/tx-list.js | 7 +- ui/app/components/tx-view.js | 7 +- ui/app/components/wallet-view.js | 9 +- ui/app/first-time/init-menu.js | 19 +- .../keychains/hd/recover-seed/confirmation.js | 7 +- ui/app/keychains/hd/restore-vault.js | 25 +- ui/app/metamask-connect.js | 4 +- ui/app/reducers/locale.js | 4 +- ui/app/send-v2.js | 27 +-- ui/app/settings.js | 75 +++--- ui/app/unlock.js | 9 +- ui/i18n-helper.js | 4 +- ui/index.js | 6 +- yarn.lock | 229 +++++++++++++++++- 68 files changed, 636 insertions(+), 445 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index b309b119d..7f6b9e72d 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -232,7 +232,7 @@ "done": { "message": "Done" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Download State Logs" }, "dropped": { diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index f519c194c..0bef6bebf 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -759,7 +759,7 @@ "stateLogs": { "message": "Logs de estado" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Descargar logs de estados" }, "revealSeedWords": { diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index f54ef98ca..ef3ed4025 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -223,7 +223,7 @@ "done": { "message": "Finito" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Scarica i log di Stato" }, "edit": { diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index c9eb178f9..e770392d0 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -223,7 +223,7 @@ "done": { "message": "Finalizado" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Descarregar Registos de Estado" }, "edit": { diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js index 00b1aab8e..75552924b 100644 --- a/ui/app/accounts/import/index.js +++ b/ui/app/accounts/import/index.js @@ -2,7 +2,6 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') const connect = require('../../metamask-connect') -const t = require('../../../i18n-helper').getMessage import Select from 'react-select' // Subviews @@ -15,8 +14,8 @@ module.exports = connect(mapStateToProps)(AccountImportSubview) function mapStateToProps (state) { return { menuItems: [ - t(this.props.localeMessages, 'privateKey'), - t(this.props.localeMessages, 'jsonFile'), + this.props.t('privateKey'), + this.props.t('jsonFile'), ], } } @@ -36,7 +35,7 @@ AccountImportSubview.prototype.render = function () { h('div.new-account-import-form', [ h('.new-account-import-disclaimer', [ - h('span', t('importAccountMsg')), + h('span', this.props.t('importAccountMsg')), h('span', { style: { cursor: 'pointer', @@ -47,12 +46,12 @@ AccountImportSubview.prototype.render = function () { url: 'https://metamask.helpscoutdocs.com/article/17-what-are-loose-accounts', }) }, - }, t('here')), + }, this.props.t('here')), ]), h('div.new-account-import-form__select-section', [ - h('div.new-account-import-form__select-label', t('selectType')), + h('div.new-account-import-form__select-label', this.props.t('selectType')), h(Select, { className: 'new-account-import-form__select', @@ -85,9 +84,9 @@ AccountImportSubview.prototype.renderImportView = function () { const current = type || menuItems[0] switch (current) { - case t(this.props.localeMessages, 'privateKey'): + case this.props.t('privateKey'): return h(PrivateKeyImportView) - case t(this.props.localeMessages, 'jsonFile'): + case this.props.t('jsonFile'): return h(JsonImportView) default: return h(JsonImportView) diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index 326e052f2..8bcc1a14e 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -4,7 +4,6 @@ const h = require('react-hyperscript') const connect = require('../../metamask-connect') const actions = require('../../actions') const FileInput = require('react-simple-file-input').default -const t = require('../../../i18n-helper').getMessage const HELP_LINK = 'https://support.metamask.io/kb/article/7-importing-accounts' @@ -25,11 +24,11 @@ class JsonImportSubview extends Component { return ( h('div.new-account-import-form__json', [ - h('p', t(this.props.localeMessages, 'usedByClients')), + h('p', this.props.t('usedByClients')), h('a.warning', { href: HELP_LINK, target: '_blank', - }, t(this.props.localeMessages, 'fileImportFail')), + }, this.props.t('fileImportFail')), h(FileInput, { readAs: 'text', @@ -44,7 +43,7 @@ class JsonImportSubview extends Component { h('input.new-account-import-form__input-password', { type: 'password', - placeholder: t(this.props.localeMessages, 'enterPassword'), + placeholder: this.props.t('enterPassword'), id: 'json-password-box', onKeyPress: this.createKeyringOnEnter.bind(this), }), @@ -54,13 +53,13 @@ class JsonImportSubview extends Component { h('button.new-account-create-form__button-cancel', { onClick: () => this.props.goHome(), }, [ - t(this.props.localeMessages, 'cancel'), + this.props.t('cancel'), ]), h('button.new-account-create-form__button-create', { onClick: () => this.createNewKeychain(), }, [ - t(this.props.localeMessages, 'import'), + this.props.t('import'), ]), ]), @@ -85,14 +84,14 @@ class JsonImportSubview extends Component { const state = this.state if (!state) { - const message = t('validFileImport') + const message = this.props.t('validFileImport') return this.props.displayWarning(message) } const { fileContents } = state if (!fileContents) { - const message = t(this.props.localeMessages, 'needImportFile') + const message = this.props.t('needImportFile') return this.props.displayWarning(message) } @@ -100,7 +99,7 @@ class JsonImportSubview extends Component { const password = passwordInput.value if (!password) { - const message = t(this.props.localeMessages, 'needImportPassword') + const message = this.props.t('needImportPassword') return this.props.displayWarning(message) } diff --git a/ui/app/accounts/import/private-key.js b/ui/app/accounts/import/private-key.js index 9a23b791a..40114ceca 100644 --- a/ui/app/accounts/import/private-key.js +++ b/ui/app/accounts/import/private-key.js @@ -3,7 +3,6 @@ const Component = require('react').Component const h = require('react-hyperscript') const connect = require('../../metamask-connect') const actions = require('../../actions') -const t = require('../../../i18n-helper').getMessage module.exports = connect(mapStateToProps, mapDispatchToProps)(PrivateKeyImportView) @@ -34,7 +33,7 @@ PrivateKeyImportView.prototype.render = function () { return ( h('div.new-account-import-form__private-key', [ - h('span.new-account-create-form__instruction', t(this.props.localeMessages, 'pastePrivateKey')), + h('span.new-account-create-form__instruction', this.props.t('pastePrivateKey')), h('div.new-account-import-form__private-key-password-container', [ @@ -51,13 +50,13 @@ PrivateKeyImportView.prototype.render = function () { h('button.new-account-create-form__button-cancel.allcaps', { onClick: () => goHome(), }, [ - t(this.props.localeMessages, 'cancel'), + this.props.t('cancel'), ]), h('button.new-account-create-form__button-create.allcaps', { onClick: () => this.createNewKeychain(), }, [ - t(this.props.localeMessages, 'import'), + this.props.t('import'), ]), ]), diff --git a/ui/app/accounts/import/seed.js b/ui/app/accounts/import/seed.js index d701feedc..5479a6be9 100644 --- a/ui/app/accounts/import/seed.js +++ b/ui/app/accounts/import/seed.js @@ -2,7 +2,6 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') const connect = require('../../metamask-connect') -const t = require('../../../i18n-helper').getMessage module.exports = connect(mapStateToProps)(SeedImportSubview) @@ -21,10 +20,10 @@ SeedImportSubview.prototype.render = function () { style: { }, }, [ - t(this.props.localeMessages, 'pasteSeed'), + this.props.t('pasteSeed'), h('textarea'), h('br'), - h('button', t(this.props.localeMessages, 'submit')), + h('button', this.props.t('submit')), ]) ) } diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js index 6eed0215c..b0e109cd7 100644 --- a/ui/app/accounts/new-account/create-form.js +++ b/ui/app/accounts/new-account/create-form.js @@ -3,7 +3,6 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const connect = require('../../metamask-connect') const actions = require('../../actions') -const t = require('../../../i18n-helper').getMessage class NewAccountCreateForm extends Component { constructor (props) { @@ -14,7 +13,7 @@ class NewAccountCreateForm extends Component { this.state = { newAccountName: '', - defaultAccountName: t(this.props.localeMessages, 'newAccountNumberName', [newAccountNumber]), + defaultAccountName: this.props.t('newAccountNumberName', [newAccountNumber]), } } @@ -25,7 +24,7 @@ class NewAccountCreateForm extends Component { return h('div.new-account-create-form', [ h('div.new-account-create-form__input-label', {}, [ - t(this.props.localeMessages, 'accountName'), + this.props.t('accountName'), ]), h('div.new-account-create-form__input-wrapper', {}, [ @@ -41,13 +40,13 @@ class NewAccountCreateForm extends Component { h('button.new-account-create-form__button-cancel.allcaps', { onClick: () => this.props.goHome(), }, [ - t(this.props.localeMessages, 'cancel'), + this.props.t('cancel'), ]), h('button.new-account-create-form__button-create.allcaps', { onClick: () => this.props.createAccount(newAccountName || defaultAccountName), }, [ - t(this.props.localeMessages, 'create'), + this.props.t('create'), ]), ]), diff --git a/ui/app/accounts/new-account/index.js b/ui/app/accounts/new-account/index.js index 8c305bfae..584016974 100644 --- a/ui/app/accounts/new-account/index.js +++ b/ui/app/accounts/new-account/index.js @@ -3,7 +3,6 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('../../metamask-connect') const actions = require('../../actions') -const t = require('../../../i18n-helper').getMessage const { getCurrentViewContext } = require('../../selectors') const classnames = require('classnames') @@ -46,7 +45,7 @@ AccountDetailsModal.prototype.render = function () { h('div.new-account__header', [ - h('div.new-account__title', t(this.props.localeMessages, 'newAccount')), + h('div.new-account__title', this.props.t('newAccount')), h('div.new-account__tabs', [ @@ -56,7 +55,7 @@ AccountDetailsModal.prototype.render = function () { 'new-account__tabs__unselected cursor-pointer': displayedForm !== 'CREATE', }), onClick: () => displayForm('CREATE'), - }, t(this.props.localeMessages, 'createDen')), + }, this.props.t('createDen')), h('div.new-account__tabs__tab', { className: classnames('new-account__tabs__tab', { @@ -64,7 +63,7 @@ AccountDetailsModal.prototype.render = function () { 'new-account__tabs__unselected cursor-pointer': displayedForm !== 'IMPORT', }), onClick: () => displayForm('IMPORT'), - }, t(this.props.localeMessages, 'import')), + }, this.props.t('import')), ]), diff --git a/ui/app/add-token.js b/ui/app/add-token.js index 9576a7aef..b4846510e 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -26,7 +26,6 @@ const fuse = new Fuse(contractList, { const actions = require('./actions') const ethUtil = require('ethereumjs-util') const { tokenInfoGetter } = require('./token-util') -const t = require('../i18n') const emptyAddr = '0x0000000000000000000000000000000000000000' @@ -140,28 +139,28 @@ AddTokenScreen.prototype.validate = function () { if (customAddress) { const validAddress = ethUtil.isValidAddress(customAddress) if (!validAddress) { - errors.customAddress = t('invalidAddress') + errors.customAddress = this.props.t('invalidAddress') } const validDecimals = customDecimals !== null && customDecimals >= 0 && customDecimals < 36 if (!validDecimals) { - errors.customDecimals = t('decimalsMustZerotoTen') + errors.customDecimals = this.props.t('decimalsMustZerotoTen') } const symbolLen = customSymbol.trim().length const validSymbol = symbolLen > 0 && symbolLen < 10 if (!validSymbol) { - errors.customSymbol = t('symbolBetweenZeroTen') + errors.customSymbol = this.props.t('symbolBetweenZeroTen') } const ownAddress = identitiesList.includes(standardAddress) if (ownAddress) { - errors.customAddress = t('personalAddressDetected') + errors.customAddress = this.props.t('personalAddressDetected') } const tokenAlreadyAdded = this.checkExistingAddresses(customAddress) if (tokenAlreadyAdded) { - errors.customAddress = t('tokenAlreadyAdded') + errors.customAddress = this.props.t('tokenAlreadyAdded') } } else if ( Object.entries(selectedTokens) @@ -169,7 +168,7 @@ AddTokenScreen.prototype.validate = function () { isEmpty && !isSelected ), true) ) { - errors.tokenSelector = t('mustSelectOne') + errors.tokenSelector = this.props.t('mustSelectOne') } return { @@ -199,7 +198,7 @@ AddTokenScreen.prototype.renderCustomForm = function () { 'add-token__add-custom-field--error': errors.customAddress, }), }, [ - h('div.add-token__add-custom-label', t('tokenAddress')), + h('div.add-token__add-custom-label', this.props.t('tokenAddress')), h('input.add-token__add-custom-input', { type: 'text', onChange: this.tokenAddressDidChange, @@ -212,7 +211,7 @@ AddTokenScreen.prototype.renderCustomForm = function () { 'add-token__add-custom-field--error': errors.customSymbol, }), }, [ - h('div.add-token__add-custom-label', t('tokenSymbol')), + h('div.add-token__add-custom-label', this.props.t('tokenSymbol')), h('input.add-token__add-custom-input', { type: 'text', onChange: this.tokenSymbolDidChange, @@ -226,7 +225,7 @@ AddTokenScreen.prototype.renderCustomForm = function () { 'add-token__add-custom-field--error': errors.customDecimals, }), }, [ - h('div.add-token__add-custom-label', t('decimal')), + h('div.add-token__add-custom-label', this.props.t('decimal')), h('input.add-token__add-custom-input', { type: 'number', onChange: this.tokenDecimalsDidChange, @@ -300,11 +299,11 @@ AddTokenScreen.prototype.renderConfirmation = function () { h('div.add-token', [ h('div.add-token__wrapper', [ h('div.add-token__title-container.add-token__confirmation-title', [ - h('div.add-token__title', t('addToken')), - h('div.add-token__description', t('likeToAddTokens')), + h('div.add-token__title', this.props.t('addToken')), + h('div.add-token__description', this.props.t('likeToAddTokens')), ]), h('div.add-token__content-container.add-token__confirmation-content', [ - h('div.add-token__description.add-token__confirmation-description', t('balances')), + h('div.add-token__description.add-token__confirmation-description', this.props.t('balances')), h('div.add-token__confirmation-token-list', Object.entries(tokens) .map(([ address, token ]) => ( @@ -323,10 +322,10 @@ AddTokenScreen.prototype.renderConfirmation = function () { h('div.add-token__buttons', [ h('button.btn-cancel.add-token__button', { onClick: () => this.setState({ isShowingConfirmation: false }), - }, t('back')), + }, this.props.t('back')), h('button.btn-clear.add-token__button', { onClick: () => addTokens(tokens).then(goHome), - }, t('addTokens')), + }, this.props.t('addTokens')), ]), ]) ) @@ -342,15 +341,15 @@ AddTokenScreen.prototype.render = function () { h('div.add-token', [ h('div.add-token__wrapper', [ h('div.add-token__title-container', [ - h('div.add-token__title', t('addToken')), - h('div.add-token__description', t('tokenWarning1')), - h('div.add-token__description', t('tokenSelection')), + h('div.add-token__title', this.props.t('addToken')), + h('div.add-token__description', this.props.t('tokenWarning1')), + h('div.add-token__description', this.props.t('tokenSelection')), ]), h('div.add-token__content-container', [ h('div.add-token__input-container', [ h('input.add-token__input', { type: 'text', - placeholder: t('search'), + placeholder: this.props.t('search'), onChange: e => this.setState({ searchQuery: e.target.value }), }), h('div.add-token__search-input-error-message', errors.tokenSelector), @@ -364,7 +363,7 @@ AddTokenScreen.prototype.render = function () { h('div.add-token__add-custom', { onClick: () => this.setState({ isCollapsed: !isCollapsed }), }, [ - t('addCustomToken'), + this.props.t('addCustomToken'), h(`i.fa.fa-angle-${isCollapsed ? 'down' : 'up'}`), ]), this.renderCustomForm(), @@ -373,10 +372,10 @@ AddTokenScreen.prototype.render = function () { h('div.add-token__buttons', [ h('button.btn-cancel.add-token__button', { onClick: goHome, - }, t('cancel')), + }, this.props.t('cancel')), h('button.btn-clear.add-token__button', { onClick: this.onNext, - }, t('next')), + }, this.props.t('next')), ]), ]) ) diff --git a/ui/app/app.js b/ui/app/app.js index f69efd1c7..91d5af899 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -4,7 +4,6 @@ const connect = require('./metamask-connect') const h = require('react-hyperscript') const actions = require('./actions') const classnames = require('classnames') -const t = require('../i18n-helper').getMessage // mascara const MascaraFirstTime = require('../../mascara/src/app/first-time').default @@ -294,8 +293,8 @@ App.prototype.renderAppBar = function () { // metamask name h('.flex-row', [ - h('h1', t(this.props.localeMessages, 'appName')), - h('div.beta-label', t(this.props.localeMessages, 'beta')), + h('h1', this.props.t('appName')), + h('div.beta-label', this.props.t('beta')), ]), ]), @@ -557,15 +556,15 @@ App.prototype.getConnectingLabel = function () { let name if (providerName === 'mainnet') { - name = t('connectingToMainnet') + name = this.props.t('connectingToMainnet') } else if (providerName === 'ropsten') { - name = t('connectingToRopsten') + name = this.props.t('connectingToRopsten') } else if (providerName === 'kovan') { - name = t('connectingToRopsten') + name = this.props.t('connectingToRopsten') } else if (providerName === 'rinkeby') { - name = t('connectingToRinkeby') + name = this.props.t('connectingToRinkeby') } else { - name = t('connectingToUnknown') + name = this.props.t('connectingToUnknown') } return name @@ -578,15 +577,15 @@ App.prototype.getNetworkName = function () { let name if (providerName === 'mainnet') { - name = t('mainnet') + name = this.props.t('mainnet') } else if (providerName === 'ropsten') { - name = t('ropsten') + name = this.props.t('ropsten') } else if (providerName === 'kovan') { - name = t('kovan') + name = this.props.t('kovan') } else if (providerName === 'rinkeby') { - name = t('rinkeby') + name = this.props.t('rinkeby') } else { - name = t('unknownNetwork') + name = this.props.t('unknownNetwork') } return name diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index f725e7d86..88c7dbb60 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -9,7 +9,6 @@ const DropdownMenuItem = require('./dropdown').DropdownMenuItem const Identicon = require('./identicon') const ethUtil = require('ethereumjs-util') const copyToClipboard = require('copy-to-clipboard') -const t = require('../../i18n-helper').getMessage class AccountDropdowns extends Component { constructor (props) { @@ -80,7 +79,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label.allcaps', t(this.props.localeMessages, 'loose')) : null + return isLoose ? h('.keyring-label.allcaps', this.props.t('loose')) : null } catch (e) { return } } @@ -130,7 +129,7 @@ class AccountDropdowns extends Component { diameter: 32, }, ), - h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, t(this.props.localeMessages, 'createAccount')), + h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, this.props.t('createAccount')), ], ), h( @@ -155,7 +154,7 @@ class AccountDropdowns extends Component { fontSize: '24px', marginBottom: '5px', }, - }, t(this.props.localeMessages, 'importAccount')), + }, this.props.t('importAccount')), ] ), ] @@ -193,7 +192,7 @@ class AccountDropdowns extends Component { global.platform.openWindow({ url }) }, }, - t(this.props.localeMessages, 'etherscanView'), + this.props.t('etherscanView'), ), h( DropdownMenuItem, @@ -205,7 +204,7 @@ class AccountDropdowns extends Component { actions.showQrView(selected, identity ? identity.name : '') }, }, - t(this.props.localeMessages, 'showQRCode'), + this.props.t('showQRCode'), ), h( DropdownMenuItem, @@ -217,7 +216,7 @@ class AccountDropdowns extends Component { copyToClipboard(checkSumAddress) }, }, - t(this.props.localeMessages, 'copyAddress'), + this.props.t('copyAddress'), ), h( DropdownMenuItem, @@ -227,7 +226,7 @@ class AccountDropdowns extends Component { actions.requestAccountExport() }, }, - t(this.props.localeMessages, 'exportPrivateKey'), + this.props.t('exportPrivateKey'), ), ] ) diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js index 3bb7ec337..8889f88a7 100644 --- a/ui/app/components/account-export.js +++ b/ui/app/components/account-export.js @@ -6,7 +6,6 @@ const copyToClipboard = require('copy-to-clipboard') const actions = require('../actions') const ethUtil = require('ethereumjs-util') const connect = require('../metamask-connect') -const t = require('../../i18n-helper').getMessage module.exports = connect(mapStateToProps)(ExportAccountView) @@ -36,7 +35,7 @@ ExportAccountView.prototype.render = function () { if (notExporting) return h('div') if (exportRequested) { - const warning = t(this.props.localeMessages, 'exportPrivateKeyWarning') + const warning = this.props.t('exportPrivateKeyWarning') return ( h('div', { style: { @@ -54,7 +53,7 @@ ExportAccountView.prototype.render = function () { h('p.error', warning), h('input#exportAccount.sizing-input', { type: 'password', - placeholder: t(this.props.localeMessages, 'confirmPassword').toLowerCase(), + placeholder: this.props.t('confirmPassword').toLowerCase(), onKeyPress: this.onExportKeyPress.bind(this), style: { position: 'relative', @@ -75,10 +74,10 @@ ExportAccountView.prototype.render = function () { style: { marginRight: '10px', }, - }, t(this.props.localeMessages, 'submit')), + }, this.props.t('submit')), h('button', { onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)), - }, t(this.props.localeMessages, 'cancel')), + }, this.props.t('cancel')), ]), (this.props.warning) && ( h('span.error', { @@ -99,7 +98,7 @@ ExportAccountView.prototype.render = function () { margin: '0 20px', }, }, [ - h('label', t(this.props.localeMessages, 'copyPrivateKey') + ':'), + h('label', this.props.t('copyPrivateKey') + ':'), h('p.error.cursor-pointer', { style: { textOverflow: 'ellipsis', @@ -113,13 +112,13 @@ ExportAccountView.prototype.render = function () { }, plainKey), h('button', { onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)), - }, t(this.props.localeMessages, 'done')), + }, this.props.t('done')), h('button', { style: { marginLeft: '10px', }, onClick: () => exportAsFile(`MetaMask ${nickname} Private Key`, plainKey), - }, t(this.props.localeMessages, 'saveAsFile')), + }, this.props.t('saveAsFile')), ]) } } diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js index dc9c36c40..a9120f9db 100644 --- a/ui/app/components/account-menu/index.js +++ b/ui/app/components/account-menu/index.js @@ -6,7 +6,6 @@ const actions = require('../../actions') const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu') const Identicon = require('../identicon') const { formatBalance } = require('../../util') -const t = require('../../../i18n-helper').getMessage module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountMenu) @@ -71,10 +70,10 @@ AccountMenu.prototype.render = function () { h(Item, { className: 'account-menu__header', }, [ - t(this.props.localeMessages, 'myAccounts'), + this.props.t('myAccounts'), h('button.account-menu__logout-button', { onClick: lockMetamask, - }, t(this.props.localeMessages, 'logout')), + }, this.props.t('logout')), ]), h(Divider), h('div.account-menu__accounts', this.renderAccounts()), @@ -82,23 +81,23 @@ AccountMenu.prototype.render = function () { h(Item, { onClick: () => showNewAccountPage('CREATE'), icon: h('img.account-menu__item-icon', { src: 'images/plus-btn-white.svg' }), - text: t(this.props.localeMessages, 'createAccount'), + text: this.props.t('createAccount'), }), h(Item, { onClick: () => showNewAccountPage('IMPORT'), icon: h('img.account-menu__item-icon', { src: 'images/import-account.svg' }), - text: t(this.props.localeMessages, 'importAccount'), + text: this.props.t('importAccount'), }), h(Divider), h(Item, { onClick: showInfoPage, icon: h('img', { src: 'images/mm-info-icon.svg' }), - text: t(this.props.localeMessages, 'infoHelp'), + text: this.props.t('infoHelp'), }), h(Item, { onClick: showConfigPage, icon: h('img.account-menu__item-icon', { src: 'images/settings.svg' }), - text: t(this.props.localeMessages, 'settings'), + text: this.props.t('settings'), }), ]) } @@ -156,6 +155,6 @@ AccountMenu.prototype.indicateIfLoose = function (keyring) { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label.allcaps', t(this.props.localeMessages, 'imported')) : null + return isLoose ? h('.keyring-label.allcaps', this.props.t('imported')) : null } catch (e) { return } } diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js index 5b83b4332..0ace2b840 100644 --- a/ui/app/components/bn-as-decimal-input.js +++ b/ui/app/components/bn-as-decimal-input.js @@ -4,9 +4,9 @@ const inherits = require('util').inherits const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const extend = require('xtend') -const t = require('../../i18n-helper').getMessage +const connect = require('../metamask-connect') -module.exports = BnAsDecimalInput +module.exports = connect()(BnAsDecimalInput) inherits(BnAsDecimalInput, Component) function BnAsDecimalInput () { @@ -137,13 +137,13 @@ BnAsDecimalInput.prototype.constructWarning = function () { let message = name ? name + ' ' : '' if (min && max) { - message += t(this.props.localeMessages, 'betweenMinAndMax', [`${newMin} ${suffix}`, `${newMax} ${suffix}`]) + message += this.props.t('betweenMinAndMax', [`${newMin} ${suffix}`, `${newMax} ${suffix}`]) } else if (min) { - message += t(this.props.localeMessages, 'greaterThanMin', [`${newMin} ${suffix}`]) + message += this.props.t('greaterThanMin', [`${newMin} ${suffix}`]) } else if (max) { - message += t(this.props.localeMessages, 'lessThanMax', [`${newMax} ${suffix}`]) + message += this.props.t('lessThanMax', [`${newMax} ${suffix}`]) } else { - message += t(this.props.localeMessages, 'invalidInput') + message += this.props.t('invalidInput') } return message diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js index b2b8cbbd5..2243ce38b 100644 --- a/ui/app/components/buy-button-subview.js +++ b/ui/app/components/buy-button-subview.js @@ -9,7 +9,6 @@ const Loading = require('./loading') const AccountPanel = require('./account-panel') const RadioList = require('./custom-radio-list') const networkNames = require('../../../app/scripts/config.js').networkNames -const t = require('../../i18n-helper.js').getMessage module.exports = connect(mapStateToProps)(BuyButtonSubview) @@ -77,7 +76,7 @@ BuyButtonSubview.prototype.headerSubview = function () { paddingTop: '4px', paddingBottom: '4px', }, - }, t(this.props.localeMessages, 'depositEth')), + }, this.props.t('depositEth')), ]), // loading indication @@ -119,7 +118,7 @@ BuyButtonSubview.prototype.headerSubview = function () { paddingTop: '4px', paddingBottom: '4px', }, - }, t(this.props.localeMessages, 'selectService')), + }, this.props.t('selectService')), ]), ]) @@ -165,14 +164,14 @@ BuyButtonSubview.prototype.primarySubview = function () { style: { marginTop: '15px', }, - }, t(this.props.localeMessages, 'borrowDharma')) + }, this.props.t('borrowDharma')) ) : null, ]) ) default: return ( - h('h2.error', t(this.props.localeMessages, 'unknownNetworkId')) + h('h2.error', this.props.t('unknownNetworkId')) ) } @@ -205,7 +204,7 @@ BuyButtonSubview.prototype.mainnetSubview = function () { ], subtext: { 'Coinbase': `${t('crypto')}/${t('fiat')} (${t('usaOnly')})`, - 'ShapeShift': t(this.props.localeMessages, 'crypto'), + 'ShapeShift': this.props.t('crypto'), }, onClick: this.radioHandler.bind(this), }), diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js index be413905e..0f980fbd5 100644 --- a/ui/app/components/coinbase-form.js +++ b/ui/app/components/coinbase-form.js @@ -3,7 +3,6 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('../metamask-connect') const actions = require('../actions') -const t = require('../../i18n-helper').getMessage module.exports = connect(mapStateToProps)(CoinbaseForm) @@ -38,11 +37,11 @@ CoinbaseForm.prototype.render = function () { }, [ h('button.btn-green', { onClick: this.toCoinbase.bind(this), - }, t(this.props.localeMessages, 'continueToCoinbase')), + }, this.props.t('continueToCoinbase')), h('button.btn-red', { onClick: () => props.dispatch(actions.goHome()), - }, t(this.props.localeMessages, 'cancel')), + }, this.props.t('cancel')), ]), ]) } diff --git a/ui/app/components/copyButton.js b/ui/app/components/copyButton.js index db43668cb..ea1c43d54 100644 --- a/ui/app/components/copyButton.js +++ b/ui/app/components/copyButton.js @@ -2,11 +2,11 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const copyToClipboard = require('copy-to-clipboard') -const t = require('../../i18n-helper').getMessage +const connect = require('../metamask-connect') const Tooltip = require('./tooltip') -module.exports = CopyButton +module.exports = connect()(CopyButton) inherits(CopyButton, Component) function CopyButton () { @@ -23,7 +23,7 @@ CopyButton.prototype.render = function () { const value = props.value const copied = state.copied - const message = copied ? t(this.props.localeMessages, 'copiedButton') : props.title || t(this.props.localeMessages, 'copyButton') + const message = copied ? this.props.t('copiedButton') : props.title || this.props.t('copyButton') return h('.copy-button', { style: { diff --git a/ui/app/components/copyable.js b/ui/app/components/copyable.js index 92a337a37..28def9adb 100644 --- a/ui/app/components/copyable.js +++ b/ui/app/components/copyable.js @@ -4,9 +4,9 @@ const inherits = require('util').inherits const Tooltip = require('./tooltip') const copyToClipboard = require('copy-to-clipboard') -const t = require('../../i18n-helper').getMessage +const connect = require('../metamask-connect') -module.exports = Copyable +module.exports = connect()(Copyable) inherits(Copyable, Component) function Copyable () { @@ -23,7 +23,7 @@ Copyable.prototype.render = function () { const { copied } = state return h(Tooltip, { - title: copied ? t(this.props.localeMessages, 'copiedExclamation') : t(this.props.localeMessages, 'copy'), + title: copied ? this.props.t('copiedExclamation') : this.props.t('copy'), position: 'bottom', }, h('span', { style: { diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index e44675880..1ea64de27 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -4,7 +4,6 @@ const inherits = require('util').inherits const connect = require('../../metamask-connect') const actions = require('../../actions') const GasModalCard = require('./gas-modal-card') -const t = require('../../../i18n-helper').getMessage const ethUtil = require('ethereumjs-util') @@ -150,7 +149,7 @@ CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) { }) if (!balanceIsSufficient) { - error = t(this.props.localeMessages, 'balanceIsInsufficientGas') + error = this.props.t('balanceIsInsufficientGas') } const gasLimitTooLow = gasLimit && conversionGreaterThan( @@ -166,7 +165,7 @@ CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) { ) if (gasLimitTooLow) { - error = t(this.props.localeMessages, 'gasLimitTooLow') + error = this.props.t('gasLimitTooLow') } this.setState({ error }) @@ -259,7 +258,7 @@ CustomizeGasModal.prototype.render = function () { }, [ h('div.send-v2__customize-gas__header', {}, [ - h('div.send-v2__customize-gas__title', t(this.props.localeMessages, 'customGas')), + h('div.send-v2__customize-gas__title', this.props.t('customGas')), h('div.send-v2__customize-gas__close', { onClick: hideModal, @@ -275,8 +274,8 @@ CustomizeGasModal.prototype.render = function () { // max: 1000, step: multiplyCurrencies(MIN_GAS_PRICE_GWEI, 10), onChange: value => this.convertAndSetGasPrice(value), - title: t(this.props.localeMessages, 'gasPrice'), - copy: t(this.props.localeMessages, 'gasPriceCalculation'), + title: this.props.t('gasPrice'), + copy: this.props.t('gasPriceCalculation'), }), h(GasModalCard, { @@ -285,8 +284,8 @@ CustomizeGasModal.prototype.render = function () { // max: 100000, step: 1, onChange: value => this.convertAndSetGasLimit(value), - title: t(this.props.localeMessages, 'gasLimit'), - copy: t(this.props.localeMessages, 'gasLimitCalculation'), + title: this.props.t('gasLimit'), + copy: this.props.t('gasLimitCalculation'), }), ]), @@ -299,16 +298,16 @@ CustomizeGasModal.prototype.render = function () { h('div.send-v2__customize-gas__revert', { onClick: () => this.revert(), - }, [t(this.props.localeMessages, 'revert')]), + }, [this.props.t('revert')]), h('div.send-v2__customize-gas__buttons', [ h('div.send-v2__customize-gas__cancel.allcaps', { onClick: this.props.hideModal, - }, [t(this.props.localeMessages, 'cancel')]), + }, [this.props.t('cancel')]), h(`div.send-v2__customize-gas__save${error ? '__error' : ''}.allcaps`, { onClick: () => !error && this.save(newGasPrice, gasLimit, gasTotal), - }, [t(this.props.localeMessages, 'save')]), + }, [this.props.t('save')]), ]), ]), diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index 6de4d8280..d570b3d36 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -10,7 +10,6 @@ const Identicon = require('../../identicon') const ethUtil = require('ethereumjs-util') const copyToClipboard = require('copy-to-clipboard') const { formatBalance } = require('../../../util') -const t = require('../../../../i18n-helper').getMessage class AccountDropdowns extends Component { @@ -131,7 +130,7 @@ class AccountDropdowns extends Component { actions.showEditAccountModal(identity) }, }, [ - t(this.props.localeMessages, 'edit'), + this.props.t('edit'), ]), ]), @@ -145,7 +144,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label.allcaps', t(this.props.localeMessages, 'loose')) : null + return isLoose ? h('.keyring-label.allcaps', this.props.t('loose')) : null } catch (e) { return } } @@ -203,7 +202,7 @@ class AccountDropdowns extends Component { fontSize: '16px', lineHeight: '23px', }, - }, t(this.props.localeMessages, 'createAccount')), + }, this.props.t('createAccount')), ], ), h( @@ -237,7 +236,7 @@ class AccountDropdowns extends Component { fontSize: '16px', lineHeight: '23px', }, - }, t(this.props.localeMessages, 'importAccount')), + }, this.props.t('importAccount')), ] ), ] @@ -288,7 +287,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t(this.props.localeMessages, 'accountDetails'), + this.props.t('accountDetails'), ), h( DropdownMenuItem, @@ -304,7 +303,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t(this.props.localeMessages, 'etherscanView'), + this.props.t('etherscanView'), ), h( DropdownMenuItem, @@ -320,7 +319,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t(this.props.localeMessages, 'copyAddress'), + this.props.t('copyAddress'), ), h( DropdownMenuItem, @@ -332,7 +331,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t(this.props.localeMessages, 'exportPrivateKey'), + this.props.t('exportPrivateKey'), ), h( DropdownMenuItem, @@ -347,7 +346,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t(this.props.localeMessages, 'addToken'), + this.props.t('addToken'), ), ] diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index 61c574aed..aac7a9ee5 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -7,7 +7,6 @@ const Dropdown = require('./components/dropdown').Dropdown const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem const NetworkDropdownIcon = require('./components/network-dropdown-icon') const R = require('ramda') -const t = require('../../../i18n-helper').getMessage // classes from nodes of the toggle element. @@ -95,13 +94,13 @@ NetworkDropdown.prototype.render = function () { }, [ h('div.network-dropdown-header', {}, [ - h('div.network-dropdown-title', {}, t(this.props.localeMessages, 'networks')), + h('div.network-dropdown-title', {}, this.props.t('networks')), h('div.network-dropdown-divider'), h('div.network-dropdown-content', {}, - t(this.props.localeMessages, 'defaultNetwork') + this.props.t('defaultNetwork') ), ]), @@ -123,7 +122,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'mainnet' ? '#ffffff' : '#9b9b9b', }, - }, t(this.props.localeMessages, 'mainnet')), + }, this.props.t('mainnet')), ] ), @@ -145,7 +144,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'ropsten' ? '#ffffff' : '#9b9b9b', }, - }, t(this.props.localeMessages, 'ropsten')), + }, this.props.t('ropsten')), ] ), @@ -167,7 +166,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'kovan' ? '#ffffff' : '#9b9b9b', }, - }, t(this.props.localeMessages, 'kovan')), + }, this.props.t('kovan')), ] ), @@ -189,7 +188,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'rinkeby' ? '#ffffff' : '#9b9b9b', }, - }, t(this.props.localeMessages, 'rinkeby')), + }, this.props.t('rinkeby')), ] ), @@ -211,7 +210,7 @@ NetworkDropdown.prototype.render = function () { style: { color: activeNetwork === 'http://localhost:8545' ? '#ffffff' : '#9b9b9b', }, - }, t(this.props.localeMessages, 'localhost')), + }, this.props.t('localhost')), ] ), @@ -235,7 +234,7 @@ NetworkDropdown.prototype.render = function () { style: { color: activeNetwork === 'custom' ? '#ffffff' : '#9b9b9b', }, - }, t(this.props.localeMessages, 'customRPC')), + }, this.props.t('customRPC')), ] ), @@ -250,15 +249,15 @@ NetworkDropdown.prototype.getNetworkName = function () { let name if (providerName === 'mainnet') { - name = t(this.props.localeMessages, 'mainnet') + name = this.props.t('mainnet') } else if (providerName === 'ropsten') { - name = t(this.props.localeMessages, 'ropsten') + name = this.props.t('ropsten') } else if (providerName === 'kovan') { - name = t(this.props.localeMessages, 'kovan') + name = this.props.t('kovan') } else if (providerName === 'rinkeby') { - name = t(this.props.localeMessages, 'rinkeby') + name = this.props.t('rinkeby') } else { - name = t(this.props.localeMessages, 'unknownNetwork') + name = this.props.t('unknownNetwork') } return name diff --git a/ui/app/components/dropdowns/token-menu-dropdown.js b/ui/app/components/dropdowns/token-menu-dropdown.js index 403d17591..630e1f99d 100644 --- a/ui/app/components/dropdowns/token-menu-dropdown.js +++ b/ui/app/components/dropdowns/token-menu-dropdown.js @@ -3,7 +3,6 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('../../metamask-connect') const actions = require('../../actions') -const t = require('../../../i18n-helper').getMessage module.exports = connect(null, mapDispatchToProps)(TokenMenuDropdown) @@ -45,7 +44,7 @@ TokenMenuDropdown.prototype.render = function () { showHideTokenConfirmationModal(this.props.token) this.props.onClose() }, - }, t(this.props.localeMessages, 'hideToken')), + }, this.props.t('hideToken')), ]), ]), diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index ea26acbca..e731286bb 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -8,10 +8,10 @@ const ENS = require('ethjs-ens') const networkMap = require('ethjs-ens/lib/network-map.json') const ensRE = /.+\..+$/ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' -const t = require('../../i18n-helper').getMessage +const connect = require('../metamask-connect') -module.exports = EnsInput +module.exports = connect()(EnsInput) inherits(EnsInput, Component) function EnsInput () { @@ -90,13 +90,13 @@ EnsInput.prototype.lookupEnsName = function () { log.info(`ENS attempting to resolve name: ${recipient}`) this.ens.lookup(recipient.trim()) .then((address) => { - if (address === ZERO_ADDRESS) throw new Error(t(this.props.localeMessages, 'noAddressForName')) + if (address === ZERO_ADDRESS) throw new Error(this.props.t('noAddressForName')) if (address !== ensResolution) { this.setState({ loadingEns: false, ensResolution: address, nickname: recipient.trim(), - hoverText: address + '\n' + t(this.props.localeMessages, 'clickCopy'), + hoverText: address + '\n' + this.props.t('clickCopy'), ensFailure: false, }) } diff --git a/ui/app/components/hex-as-decimal-input.js b/ui/app/components/hex-as-decimal-input.js index 7e53ba2f0..be7ba4c9e 100644 --- a/ui/app/components/hex-as-decimal-input.js +++ b/ui/app/components/hex-as-decimal-input.js @@ -4,9 +4,9 @@ const inherits = require('util').inherits const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const extend = require('xtend') -const t = require('../../i18n-helper').getMessage +const connect = require('../metamask-connect') -module.exports = HexAsDecimalInput +module.exports = connect()(HexAsDecimalInput) inherits(HexAsDecimalInput, Component) function HexAsDecimalInput () { @@ -127,13 +127,13 @@ HexAsDecimalInput.prototype.constructWarning = function () { let message = name ? name + ' ' : '' if (min && max) { - message += t(this.props.localeMessages, 'betweenMinAndMax', [min, max]) + message += this.props.t('betweenMinAndMax', [min, max]) } else if (min) { - message += t(this.props.localeMessages, 'greaterThanMin', [min]) + message += this.props.t('greaterThanMin', [min]) } else if (max) { - message += t(this.props.localeMessages, 'lessThanMax', [max]) + message += this.props.t('lessThanMax', [max]) } else { - message += t(this.props.localeMessages, 'invalidInput') + message += this.props.t('invalidInput') } return message diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js index e4f2009aa..24d856b43 100644 --- a/ui/app/components/modals/account-details-modal.js +++ b/ui/app/components/modals/account-details-modal.js @@ -8,7 +8,6 @@ const { getSelectedIdentity } = require('../../selectors') const genAccountLink = require('../../../lib/account-link.js') const QrView = require('../qr-code') const EditableLabel = require('../editable-label') -const t = require('../../../i18n-helper').getMessage function mapStateToProps (state) { return { @@ -65,12 +64,12 @@ AccountDetailsModal.prototype.render = function () { h('button.btn-clear.account-modal__button', { onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }), - }, t(this.props.localeMessages, 'etherscanView')), + }, this.props.t('etherscanView')), // Holding on redesign for Export Private Key functionality h('button.btn-clear.account-modal__button', { onClick: () => showExportPrivateKeyModal(), - }, t(this.props.localeMessages, 'exportPrivateKey')), + }, this.props.t('exportPrivateKey')), ]) } diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js index ac6457b37..70efe16cb 100644 --- a/ui/app/components/modals/account-modal-container.js +++ b/ui/app/components/modals/account-modal-container.js @@ -5,7 +5,6 @@ const connect = require('../../metamask-connect') const actions = require('../../actions') const { getSelectedIdentity } = require('../../selectors') const Identicon = require('../identicon') -const t = require('../../../i18n-helper').getMessage function mapStateToProps (state) { return { @@ -60,7 +59,7 @@ AccountModalContainer.prototype.render = function () { h('i.fa.fa-angle-left.fa-lg'), - h('span.account-modal-back__text', ' ' + t(this.props.localeMessages, 'back')), + h('span.account-modal-back__text', ' ' + this.props.t('back')), ]), diff --git a/ui/app/components/modals/buy-options-modal.js b/ui/app/components/modals/buy-options-modal.js index 0e93e9a2d..c0ee3632e 100644 --- a/ui/app/components/modals/buy-options-modal.js +++ b/ui/app/components/modals/buy-options-modal.js @@ -4,7 +4,6 @@ const inherits = require('util').inherits const connect = require('../../metamask-connect') const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames -const t = require('../../../i18n-helper').getMessage function mapStateToProps (state) { return { @@ -57,15 +56,15 @@ BuyOptions.prototype.render = function () { }, [ h('div.buy-modal-content-title', { style: {}, - }, t(this.props.localeMessages, 'transfers')), - h('div', {}, t(this.props.localeMessages, 'howToDeposit')), + }, this.props.t('transfers')), + h('div', {}, this.props.t('howToDeposit')), ]), h('div.buy-modal-content-options.flex-column.flex-center', {}, [ isTestNetwork - ? this.renderModalContentOption(networkName, t(this.props.localeMessages, 'testFaucet'), () => toFaucet(network)) - : this.renderModalContentOption('Coinbase', t(this.props.localeMessages, 'depositFiat'), () => toCoinbase(address)), + ? this.renderModalContentOption(networkName, this.props.t('testFaucet'), () => toFaucet(network)) + : this.renderModalContentOption('Coinbase', this.props.t('depositFiat'), () => toCoinbase(address)), // h('div.buy-modal-content-option', {}, [ // h('div.buy-modal-content-option-title', {}, 'Shapeshift'), @@ -73,8 +72,8 @@ BuyOptions.prototype.render = function () { // ]),, this.renderModalContentOption( - t(this.props.localeMessages, 'directDeposit'), - t(this.props.localeMessages, 'depositFromAccount'), + this.props.t('directDeposit'), + this.props.t('depositFromAccount'), () => this.goToAccountDetailsModal() ), @@ -85,7 +84,7 @@ BuyOptions.prototype.render = function () { background: 'white', }, onClick: () => { this.props.hideModal() }, - }, h('div.buy-modal-content-footer#buy-modal-content-footer-text', {}, t(this.props.localeMessages, 'cancel'))), + }, h('div.buy-modal-content-footer#buy-modal-content-footer-text', {}, this.props.t('cancel'))), ]), ]) } diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index 307e89a47..0b097d546 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -5,7 +5,6 @@ const connect = require('../../metamask-connect') const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames const ShapeshiftForm = require('../shapeshift-form') -const t = require('../../../i18n-helper').getMessage let DIRECT_DEPOSIT_ROW_TITLE let DIRECT_DEPOSIT_ROW_TEXT @@ -16,7 +15,7 @@ let SHAPESHIFT_ROW_TEXT let FAUCET_ROW_TITLE const facuetRowText = (networkName) => { - return t(this.props.localeMessages, 'getEtherFromFaucet', [networkName]) + return this.props.t('getEtherFromFaucet', [networkName]) } function mapStateToProps (state) { @@ -49,13 +48,13 @@ function DepositEtherModal () { Component.call(this) // need to set after i18n locale has loaded - DIRECT_DEPOSIT_ROW_TITLE = t(this.props.localeMessages, 'directDepositEther') - DIRECT_DEPOSIT_ROW_TEXT = t(this.props.localeMessages, 'directDepositEtherExplainer') - COINBASE_ROW_TITLE = t(this.props.localeMessages, 'buyCoinbase') - COINBASE_ROW_TEXT = t(this.props.localeMessages, 'buyCoinbaseExplainer') - SHAPESHIFT_ROW_TITLE = t(this.props.localeMessages, 'depositShapeShift') - SHAPESHIFT_ROW_TEXT = t(this.props.localeMessages, 'depositShapeShiftExplainer') - FAUCET_ROW_TITLE = t(this.props.localeMessages, 'testFaucet') + DIRECT_DEPOSIT_ROW_TITLE = this.props.t('directDepositEther') + DIRECT_DEPOSIT_ROW_TEXT = this.props.t('directDepositEtherExplainer') + COINBASE_ROW_TITLE = this.props.t('buyCoinbase') + COINBASE_ROW_TEXT = this.props.t('buyCoinbaseExplainer') + SHAPESHIFT_ROW_TITLE = this.props.t('depositShapeShift') + SHAPESHIFT_ROW_TEXT = this.props.t('depositShapeShiftExplainer') + FAUCET_ROW_TITLE = this.props.t('testFaucet') this.state = { buyingWithShapeshift: false, @@ -123,10 +122,10 @@ DepositEtherModal.prototype.render = function () { h('div.page-container__header', [ - h('div.page-container__title', [t(this.props.localeMessages, 'depositEther')]), + h('div.page-container__title', [this.props.t('depositEther')]), h('div.page-container__subtitle', [ - t(this.props.localeMessages, 'needEtherInWallet'), + this.props.t('needEtherInWallet'), ]), h('div.page-container__header-close', { @@ -149,7 +148,7 @@ DepositEtherModal.prototype.render = function () { }), title: DIRECT_DEPOSIT_ROW_TITLE, text: DIRECT_DEPOSIT_ROW_TEXT, - buttonLabel: t(this.props.localeMessages, 'viewAccount'), + buttonLabel: this.props.t('viewAccount'), onButtonClick: () => this.goToAccountDetailsModal(), hide: buyingWithShapeshift, }), @@ -158,7 +157,7 @@ DepositEtherModal.prototype.render = function () { logo: h('i.fa.fa-tint.fa-2x'), title: FAUCET_ROW_TITLE, text: facuetRowText(networkName), - buttonLabel: t(this.props.localeMessages, 'getEther'), + buttonLabel: this.props.t('getEther'), onButtonClick: () => toFaucet(network), hide: !isTestNetwork || buyingWithShapeshift, }), @@ -172,7 +171,7 @@ DepositEtherModal.prototype.render = function () { }), title: COINBASE_ROW_TITLE, text: COINBASE_ROW_TEXT, - buttonLabel: t(this.props.localeMessages, 'continueToCoinbase'), + buttonLabel: this.props.t('continueToCoinbase'), onButtonClick: () => toCoinbase(address), hide: isTestNetwork || buyingWithShapeshift, }), @@ -185,7 +184,7 @@ DepositEtherModal.prototype.render = function () { }), title: SHAPESHIFT_ROW_TITLE, text: SHAPESHIFT_ROW_TEXT, - buttonLabel: t(this.props.localeMessages, 'shapeshiftBuy'), + buttonLabel: this.props.t('shapeshiftBuy'), onButtonClick: () => this.setState({ buyingWithShapeshift: true }), hide: isTestNetwork, hideButton: buyingWithShapeshift, diff --git a/ui/app/components/modals/edit-account-name-modal.js b/ui/app/components/modals/edit-account-name-modal.js index a64a41b27..4f5bc001a 100644 --- a/ui/app/components/modals/edit-account-name-modal.js +++ b/ui/app/components/modals/edit-account-name-modal.js @@ -4,7 +4,6 @@ const inherits = require('util').inherits const connect = require('../../metamask-connect') const actions = require('../../actions') const { getSelectedAccount } = require('../../selectors') -const t = require('../../../i18n-helper').getMessage function mapStateToProps (state) { return { @@ -51,7 +50,7 @@ EditAccountNameModal.prototype.render = function () { ]), h('div.edit-account-name-modal-title', { - }, [t(this.props.localeMessages, 'editAccountName')]), + }, [this.props.t('editAccountName')]), h('input.edit-account-name-modal-input', { placeholder: identity.name, @@ -70,7 +69,7 @@ EditAccountNameModal.prototype.render = function () { }, disabled: this.state.inputText.length === 0, }, [ - t(this.props.localeMessages, 'save'), + this.props.t('save'), ]), ]), diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js index fac5366a4..b92d250fa 100644 --- a/ui/app/components/modals/export-private-key-modal.js +++ b/ui/app/components/modals/export-private-key-modal.js @@ -7,7 +7,6 @@ const actions = require('../../actions') const AccountModalContainer = require('./account-modal-container') const { getSelectedIdentity } = require('../../selectors') const ReadOnlyInput = require('../readonly-input') -const t = require('../../../i18n-helper').getMessage const copyToClipboard = require('copy-to-clipboard') function mapStateToProps (state) { @@ -49,8 +48,8 @@ ExportPrivateKeyModal.prototype.exportAccountAndGetPrivateKey = function (passwo ExportPrivateKeyModal.prototype.renderPasswordLabel = function (privateKey) { return h('span.private-key-password-label', privateKey - ? t(this.props.localeMessages, 'copyPrivateKey') - : t(this.props.localeMessages, 'typePassword') + ? this.props.t('copyPrivateKey') + : this.props.t('typePassword') ) } @@ -87,8 +86,8 @@ ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, password, ), (privateKey - ? this.renderButton('btn-clear export-private-key__button', () => hideModal(), t(this.props.localeMessages, 'done')) - : this.renderButton('btn-clear export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), t(this.props.localeMessages, 'confirm')) + ? this.renderButton('btn-clear export-private-key__button', () => hideModal(), this.props.t('done')) + : this.renderButton('btn-clear export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), this.props.t('confirm')) ), ]) @@ -121,7 +120,7 @@ ExportPrivateKeyModal.prototype.render = function () { h('div.account-modal-divider'), - h('span.modal-body-title', t(this.props.localeMessages, 'showPrivateKeys')), + h('span.modal-body-title', this.props.t('showPrivateKeys')), h('div.private-key-password', {}, [ this.renderPasswordLabel(privateKey), @@ -131,7 +130,7 @@ ExportPrivateKeyModal.prototype.render = function () { !warning ? null : h('span.private-key-password-error', warning), ]), - h('div.private-key-password-warning', t(this.props.localeMessages, 'privateKeyWarning')), + h('div.private-key-password-warning', this.props.t('privateKeyWarning')), this.renderButtons(privateKey, this.state.password, address, hideModal), diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js index a6cf2889f..5207b4c95 100644 --- a/ui/app/components/modals/hide-token-confirmation-modal.js +++ b/ui/app/components/modals/hide-token-confirmation-modal.js @@ -4,7 +4,6 @@ const inherits = require('util').inherits const connect = require('../../metamask-connect') const actions = require('../../actions') const Identicon = require('../identicon') -const t = require('../../../i18n-helper').getMessage function mapStateToProps (state) { return { @@ -42,7 +41,7 @@ HideTokenConfirmationModal.prototype.render = function () { h('div.hide-token-confirmation__container', { }, [ h('div.hide-token-confirmation__title', {}, [ - t(this.props.localeMessages, 'hideTokenPrompt'), + this.props.t('hideTokenPrompt'), ]), h(Identicon, { @@ -55,19 +54,19 @@ HideTokenConfirmationModal.prototype.render = function () { h('div.hide-token-confirmation__symbol', {}, symbol), h('div.hide-token-confirmation__copy', {}, [ - t(this.props.localeMessages, 'readdToken'), + this.props.t('readdToken'), ]), h('div.hide-token-confirmation__buttons', {}, [ h('button.btn-cancel.hide-token-confirmation__button.allcaps', { onClick: () => hideModal(), }, [ - t(this.props.localeMessages, 'cancel'), + this.props.t('cancel'), ]), h('button.btn-clear.hide-token-confirmation__button.allcaps', { onClick: () => hideToken(address), }, [ - t(this.props.localeMessages, 'hide'), + this.props.t('hide'), ]), ]), ]), diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index d0f4b486c..9250cc77e 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const FadeModal = require('boron').FadeModal const actions = require('../../actions') const isMobileView = require('../../../lib/is-mobile-view') diff --git a/ui/app/components/modals/new-account-modal.js b/ui/app/components/modals/new-account-modal.js index 23613ec9c..c46980855 100644 --- a/ui/app/components/modals/new-account-modal.js +++ b/ui/app/components/modals/new-account-modal.js @@ -3,7 +3,6 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const connect = require('../../metamask-connect') const actions = require('../../actions') -const t = require('../../../i18n-helper').getMessage class NewAccountModal extends Component { constructor (props) { @@ -23,7 +22,7 @@ class NewAccountModal extends Component { h('div.new-account-modal-wrapper', { }, [ h('div.new-account-modal-header', {}, [ - t(this.props.localeMessages, 'newAccount'), + this.props.t('newAccount'), ]), h('div.modal-close-x', { @@ -31,19 +30,19 @@ class NewAccountModal extends Component { }), h('div.new-account-modal-content', {}, [ - t(this.props.localeMessages, 'accountName'), + this.props.t('accountName'), ]), h('div.new-account-input-wrapper', {}, [ h('input.new-account-input', { value: this.state.newAccountName, - placeholder: t(this.props.localeMessages, 'sampleAccountName'), + placeholder: this.props.t('sampleAccountName'), onChange: event => this.setState({ newAccountName: event.target.value }), }, []), ]), h('div.new-account-modal-content.after-input', {}, [ - t(this.props.localeMessages, 'or'), + this.props.t('or'), ]), h('div.new-account-modal-content.after-input.pointer', { @@ -51,13 +50,13 @@ class NewAccountModal extends Component { this.props.hideModal() this.props.showImportPage() }, - }, t(this.props.localeMessages, 'importAnAccount')), + }, this.props.t('importAnAccount')), h('div.new-account-modal-content.button.allcaps', {}, [ h('button.btn-clear', { onClick: () => this.props.createAccount(newAccountName), }, [ - t(this.props.localeMessages, 'save'), + this.props.t('save'), ]), ]), ]), diff --git a/ui/app/components/modals/notification-modal.js b/ui/app/components/modals/notification-modal.js index 3898f1c44..3c4ab5194 100644 --- a/ui/app/components/modals/notification-modal.js +++ b/ui/app/components/modals/notification-modal.js @@ -3,7 +3,6 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const connect = require('../../metamask-connect') const actions = require('../../actions') -const t = require('../../../i18n-helper').getMessage class NotificationModal extends Component { render () { @@ -23,12 +22,12 @@ class NotificationModal extends Component { }, [ h('div.notification-modal__header', {}, [ - t(this.props.localeMessages, header), + this.props.t(header), ]), h('div.notification-modal__message-wrapper', {}, [ h('div.notification-modal__message', {}, [ - t(this.props.localeMessages, message), + this.props.t(message), ]), ]), diff --git a/ui/app/components/network.js b/ui/app/components/network.js index 55bc14c3c..10961390e 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -4,7 +4,6 @@ const connect = require('../metamask-connect') const classnames = require('classnames') const inherits = require('util').inherits const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') -const t = require('../../i18n-helper').getMessage module.exports = connect()(Network) @@ -35,7 +34,7 @@ Network.prototype.render = function () { onClick: (event) => this.props.onClick(event), }, [ h('img', { - title: t(props.localeMessages, 'attemptingConnect'), + title: props.t('attemptingConnect'), style: { width: '27px', }, @@ -43,22 +42,22 @@ Network.prototype.render = function () { }), ]) } else if (providerName === 'mainnet') { - hoverText = t(props.localeMessages, 'mainnet') + hoverText = props.t('mainnet') iconName = 'ethereum-network' } else if (providerName === 'ropsten') { - hoverText = t(props.localeMessages, 'ropsten') + hoverText = props.t('ropsten') iconName = 'ropsten-test-network' } else if (parseInt(networkNumber) === 3) { - hoverText = t(props.localeMessages, 'ropsten') + hoverText = props.t('ropsten') iconName = 'ropsten-test-network' } else if (providerName === 'kovan') { - hoverText = t(props.localeMessages, 'kovan') + hoverText = props.t('kovan') iconName = 'kovan-test-network' } else if (providerName === 'rinkeby') { - hoverText = t(props.localeMessages, 'rinkeby') + hoverText = props.t('rinkeby') iconName = 'rinkeby-test-network' } else { - hoverText = t(props.localeMessages, 'unknownNetwork') + hoverText = props.t('unknownNetwork') iconName = 'unknown-private-network' } @@ -86,7 +85,7 @@ Network.prototype.render = function () { backgroundColor: '#038789', // $blue-lagoon nonSelectBackgroundColor: '#15afb2', }), - h('.network-name', t(props.localeMessages, 'mainnet')), + h('.network-name', props.t('mainnet')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'ropsten-test-network': @@ -95,7 +94,7 @@ Network.prototype.render = function () { backgroundColor: '#e91550', // $crimson nonSelectBackgroundColor: '#ec2c50', }), - h('.network-name', t(props.localeMessages, 'ropsten')), + h('.network-name', props.t('ropsten')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'kovan-test-network': @@ -104,7 +103,7 @@ Network.prototype.render = function () { backgroundColor: '#690496', // $purple nonSelectBackgroundColor: '#b039f3', }), - h('.network-name', t(props.localeMessages, 'kovan')), + h('.network-name', props.t('kovan')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'rinkeby-test-network': @@ -113,7 +112,7 @@ Network.prototype.render = function () { backgroundColor: '#ebb33f', // $tulip-tree nonSelectBackgroundColor: '#ecb23e', }), - h('.network-name', t(props.localeMessages, 'rinkeby')), + h('.network-name', props.t('rinkeby')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) default: @@ -125,7 +124,7 @@ Network.prototype.render = function () { }, }), - h('.network-name', t(props.localeMessages, 'privateNetwork')), + h('.network-name', props.t('privateNetwork')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) } diff --git a/ui/app/components/notice.js b/ui/app/components/notice.js index ffc5ec6f1..a999ffd88 100644 --- a/ui/app/components/notice.js +++ b/ui/app/components/notice.js @@ -4,9 +4,9 @@ const h = require('react-hyperscript') const ReactMarkdown = require('react-markdown') const linker = require('extension-link-enabler') const findDOMNode = require('react-dom').findDOMNode -const t = require('../../i18n-helper').getMessage +const connect = require('../metamask-connect') -module.exports = Notice +module.exports = connect()(Notice) inherits(Notice, Component) function Notice () { @@ -111,7 +111,7 @@ Notice.prototype.render = function () { style: { marginTop: '18px', }, - }, t(this.props.localeMessages, 'accept')), + }, this.props.t('accept')), ]) ) } diff --git a/ui/app/components/pending-msg-details.js b/ui/app/components/pending-msg-details.js index 8edf21b48..ddec8470d 100644 --- a/ui/app/components/pending-msg-details.js +++ b/ui/app/components/pending-msg-details.js @@ -1,11 +1,11 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const t = require('../../i18n-helper').getMessage +const connect = require('../metamask-connect') const AccountPanel = require('./account-panel') -module.exports = PendingMsgDetails +module.exports = connect()(PendingMsgDetails) inherits(PendingMsgDetails, Component) function PendingMsgDetails () { @@ -40,7 +40,7 @@ PendingMsgDetails.prototype.render = function () { // message data h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [ h('.flex-column.flex-space-between', [ - h('label.font-small.allcaps', t(this.props.localeMessages, 'message')), + h('label.font-small.allcaps', this.props.t('message')), h('span.font-small', msgParams.data), ]), ]), diff --git a/ui/app/components/pending-msg.js b/ui/app/components/pending-msg.js index 2364353be..56e646a1c 100644 --- a/ui/app/components/pending-msg.js +++ b/ui/app/components/pending-msg.js @@ -2,9 +2,9 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const PendingTxDetails = require('./pending-msg-details') -const t = require('../../i18n-helper').getMessage +const connect = require('../metamask-connect') -module.exports = PendingMsg +module.exports = connect()(PendingMsg) inherits(PendingMsg, Component) function PendingMsg () { @@ -30,14 +30,14 @@ PendingMsg.prototype.render = function () { fontWeight: 'bold', textAlign: 'center', }, - }, t(this.props.localeMessages, 'signMessage')), + }, this.props.t('signMessage')), h('.error', { style: { margin: '10px', }, }, [ - t(this.props.localeMessages, 'signNotice'), + this.props.t('signNotice'), h('a', { href: 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527', style: { color: 'rgb(247, 134, 28)' }, @@ -46,7 +46,7 @@ PendingMsg.prototype.render = function () { const url = 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527' global.platform.openWindow({ url }) }, - }, t(this.props.localeMessages, 'readMore')), + }, this.props.t('readMore')), ]), // message details @@ -56,10 +56,10 @@ PendingMsg.prototype.render = function () { h('.flex-row.flex-space-around', [ h('button', { onClick: state.cancelMessage, - }, t(this.props.localeMessages, 'cancel')), + }, this.props.t('cancel')), h('button', { onClick: state.signMessage, - }, t(this.props.localeMessages, 'sign')), + }, this.props.t('sign')), ]), ]) diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index 8e04fb84d..6b912af7f 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -8,7 +8,6 @@ const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const hexToBn = require('../../../../app/scripts/lib/hex-to-bn') const { conversionUtil } = require('../../conversion-util') -const t = require('../../../i18n-helper').getMessage const SenderToRecipient = require('../sender-to-recipient') const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') @@ -177,7 +176,7 @@ class ConfirmDeployContract extends Component { return ( h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'gasFee') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('gasFee') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${fiatGas} ${currentCurrency.toUpperCase()}`), @@ -216,8 +215,8 @@ class ConfirmDeployContract extends Component { return ( h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ t(this.props.localeMessages, 'total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ t(this.props.localeMessages, 'amountPlusGas') ]), + h('span.confirm-screen-label', [ this.props.t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ this.props.t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -246,9 +245,9 @@ class ConfirmDeployContract extends Component { h('.page-container__header', [ h('.page-container__back-button', { onClick: () => backToAccountDetail(selectedAddress), - }, t(this.props.localeMessages, 'back')), - h('.page-container__title', t(this.props.localeMessages, 'confirmContract')), - h('.page-container__subtitle', t(this.props.localeMessages, 'pleaseReviewTransaction')), + }, this.props.t('back')), + h('.page-container__title', this.props.t('confirmContract')), + h('.page-container__subtitle', this.props.t('pleaseReviewTransaction')), ]), // Main Send token Card h('.page-container__content', [ @@ -271,7 +270,7 @@ class ConfirmDeployContract extends Component { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'from') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -279,9 +278,9 @@ class ConfirmDeployContract extends Component { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'to') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('to') ]), h('div.confirm-screen-section-column', [ - h('div.confirm-screen-row-info', t(this.props.localeMessages, 'newContract')), + h('div.confirm-screen-row-info', this.props.t('newContract')), ]), ]), @@ -299,12 +298,12 @@ class ConfirmDeployContract extends Component { // Cancel Button h('button.btn-cancel.page-container__footer-button.allcaps', { onClick: event => this.cancel(event, txMeta), - }, t(this.props.localeMessages, 'cancel')), + }, this.props.t('cancel')), // Accept Button h('button.btn-confirm.page-container__footer-button.allcaps', { onClick: event => this.onSubmit(event), - }, t(this.props.localeMessages, 'confirm')), + }, this.props.t('confirm')), ]), ]), ]) @@ -344,7 +343,7 @@ const mapDispatchToProps = dispatch => { return { backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)), cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })), - displayWarning: warning => actions.displayWarning(t(this.props.localeMessages, warning)), + displayWarning: warning => actions.displayWarning(this.props.t(warning)), } } diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index 253b69b7a..02394b0c5 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -14,7 +14,6 @@ const { multiplyCurrencies, } = require('../../conversion-util') const GasFeeDisplay = require('../send/gas-fee-display-v2') -const t = require('../../../i18n-helper').getMessage const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') @@ -196,7 +195,7 @@ ConfirmSendEther.prototype.getData = function () { }, to: { address: txParams.to, - name: identities[txParams.to] ? identities[txParams.to].name : t(this.props.localeMessages, 'newRecipient'), + name: identities[txParams.to] ? identities[txParams.to].name : this.props.t('newRecipient'), }, memo: txParams.memo || '', gasFeeInFIAT, @@ -311,7 +310,7 @@ ConfirmSendEther.prototype.render = function () { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'from') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -319,7 +318,7 @@ ConfirmSendEther.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'to') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('to') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', toName), h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`), @@ -327,7 +326,7 @@ ConfirmSendEther.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'gasFee') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('gasFee') ]), h('div.confirm-screen-section-column', [ h(GasFeeDisplay, { gasTotal: gasTotal || gasFeeInHex, @@ -340,8 +339,8 @@ ConfirmSendEther.prototype.render = function () { h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ t(this.props.localeMessages, 'total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ t(this.props.localeMessages, 'amountPlusGas') ]), + h('span.confirm-screen-label', [ this.props.t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ this.props.t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -442,10 +441,10 @@ ConfirmSendEther.prototype.render = function () { clearSend() this.cancel(event, txMeta) }, - }, t(this.props.localeMessages, 'cancel')), + }, this.props.t('cancel')), // Accept Button - h('button.btn-confirm.page-container__footer-button.allcaps', [t(this.props.localeMessages, 'confirm')]), + h('button.btn-confirm.page-container__footer-button.allcaps', [this.props.t('confirm')]), ]), ]), ]), @@ -462,7 +461,7 @@ ConfirmSendEther.prototype.onSubmit = function (event) { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.dispatch(actions.displayWarning(t(this.props.localeMessages, 'invalidGasParams'))) + this.props.dispatch(actions.displayWarning(this.props.t('invalidGasParams'))) this.setState({ submitting: false }) } } diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index 54963ae9a..d53f8b32f 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -6,7 +6,6 @@ const tokenAbi = require('human-standard-token-abi') const abiDecoder = require('abi-decoder') abiDecoder.addABI(tokenAbi) const actions = require('../../actions') -const t = require('../../../i18n-helper').getMessage const clone = require('clone') const Identicon = require('../identicon') const GasFeeDisplay = require('../send/gas-fee-display-v2.js') @@ -22,7 +21,7 @@ const { } = require('../../token-util') const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') - +// const { getTokenExchangeRate, getSelectedAddress, @@ -168,7 +167,7 @@ ConfirmSendToken.prototype.getAmount = function () { ? +(sendTokenAmount * tokenExchangeRate * conversionRate).toFixed(2) : null, token: typeof value === 'undefined' - ? t(this.props.localeMessages, 'unknown') + ? this.props.t('unknown') : +sendTokenAmount.toFixed(decimals), } @@ -240,7 +239,7 @@ ConfirmSendToken.prototype.getData = function () { }, to: { address: value, - name: identities[value] ? identities[value].name : t(this.props.localeMessages, 'newRecipient'), + name: identities[value] ? identities[value].name : this.props.t('newRecipient'), }, memo: txParams.memo || '', } @@ -286,7 +285,7 @@ ConfirmSendToken.prototype.renderGasFee = function () { return ( h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'gasFee') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('gasFee') ]), h('div.confirm-screen-section-column', [ h(GasFeeDisplay, { gasTotal: gasTotal || gasFeeInHex, @@ -308,8 +307,8 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { ? ( h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ t(this.props.localeMessages, 'total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ t(this.props.localeMessages, 'amountPlusGas') ]), + h('span.confirm-screen-label', [ this.props.t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ this.props.t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -321,8 +320,8 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { : ( h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ t(this.props.localeMessages, 'total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ t(this.props.localeMessages, 'amountPlusGas') ]), + h('span.confirm-screen-label', [ this.props.t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ this.props.t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -350,10 +349,10 @@ ConfirmSendToken.prototype.render = function () { this.inputs = [] const isTxReprice = Boolean(txMeta.lastGasPrice) - const title = isTxReprice ? t(this.props.localeMessages, 'reprice:title') : t(this.props.localeMessages, 'confirm') + const title = isTxReprice ? this.props.t('reprice:title') : this.props.t('confirm') const subtitle = isTxReprice - ? t(this.props.localeMessages, 'reprice:subtitle') - : t(this.props.localeMessages, 'pleaseReviewTransaction') + ? this.props.t('reprice:subtitle') + : this.props.t('pleaseReviewTransaction') return ( h('div.confirm-screen-container.confirm-send-token', [ @@ -362,7 +361,7 @@ ConfirmSendToken.prototype.render = function () { h('div.page-container__header', [ !txMeta.lastGasPrice && h('button.confirm-screen-back-button', { onClick: () => editTransaction(txMeta), - }, t(this.props.localeMessages, 'edit')), + }, this.props.t('edit')), h('div.page-container__title', title), h('div.page-container__subtitle', subtitle), ]), @@ -406,7 +405,7 @@ ConfirmSendToken.prototype.render = function () { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'from') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -414,7 +413,7 @@ ConfirmSendToken.prototype.render = function () { ]), toAddress && h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t(this.props.localeMessages, 'to') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('to') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', toName), h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`), @@ -436,10 +435,10 @@ ConfirmSendToken.prototype.render = function () { // Cancel Button h('button.btn-cancel.page-container__footer-button.allcaps', { onClick: (event) => this.cancel(event, txMeta), - }, t(this.props.localeMessages, 'cancel')), + }, this.props.t('cancel')), // Accept Button - h('button.btn-confirm.page-container__footer-button.allcaps', [t(this.props.localeMessages, 'confirm')]), + h('button.btn-confirm.page-container__footer-button.allcaps', [this.props.t('confirm')]), ]), ]), ]), @@ -456,7 +455,7 @@ ConfirmSendToken.prototype.onSubmit = function (event) { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.dispatch(actions.displayWarning(t(this.props.localeMessages, 'invalidGasParams'))) + this.props.dispatch(actions.displayWarning(this.props.t('invalidGasParams'))) this.setState({ submitting: false }) } } diff --git a/ui/app/components/send/currency-display.js b/ui/app/components/send/currency-display.js index 819fee0a0..a0aaada4d 100644 --- a/ui/app/components/send/currency-display.js +++ b/ui/app/components/send/currency-display.js @@ -10,7 +10,7 @@ inherits(CurrencyDisplay, Component) function CurrencyDisplay () { Component.call(this) } - +// function toHexWei (value) { return conversionUtil(value, { fromNumericBase: 'dec', diff --git a/ui/app/components/send/gas-fee-display-v2.js b/ui/app/components/send/gas-fee-display-v2.js index 04a43df2f..76ed1b5d4 100644 --- a/ui/app/components/send/gas-fee-display-v2.js +++ b/ui/app/components/send/gas-fee-display-v2.js @@ -2,9 +2,9 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const CurrencyDisplay = require('./currency-display') -const t = require('../../../i18n-helper').getMessage +const connect = require('../../metamask-connect') -module.exports = GasFeeDisplay +module.exports = connect()(GasFeeDisplay) inherits(GasFeeDisplay, Component) function GasFeeDisplay () { @@ -33,8 +33,8 @@ GasFeeDisplay.prototype.render = function () { readOnly: true, }) : gasLoadingError - ? h('div.currency-display.currency-display--message', t(this.props.localeMessages, 'setGasPrice')) - : h('div.currency-display', t(this.props.localeMessages, 'loading')), + ? h('div.currency-display.currency-display--message', this.props.t('setGasPrice')) + : h('div.currency-display', this.props.t('loading')), h('button.sliders-icon-container', { onClick, diff --git a/ui/app/components/send/gas-tooltip.js b/ui/app/components/send/gas-tooltip.js index 7bdb164c7..607394c8b 100644 --- a/ui/app/components/send/gas-tooltip.js +++ b/ui/app/components/send/gas-tooltip.js @@ -2,9 +2,9 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const InputNumber = require('../input-number.js') -const t = require('../../../i18n-helper').getMessage +const connect = require('../../metamask-connect') -module.exports = GasTooltip +module.exports = connect()(GasTooltip) inherits(GasTooltip, Component) function GasTooltip () { @@ -82,7 +82,7 @@ GasTooltip.prototype.render = function () { 'marginTop': '81px', }, }, [ - h('span.gas-tooltip-label', {}, [t(this.props.localeMessages, 'gasLimit')]), + h('span.gas-tooltip-label', {}, [this.props.t('gasLimit')]), h('i.fa.fa-info-circle'), ]), h(InputNumber, { diff --git a/ui/app/components/send/send-v2-container.js b/ui/app/components/send/send-v2-container.js index 25902cfce..d90a6bf75 100644 --- a/ui/app/components/send/send-v2-container.js +++ b/ui/app/components/send/send-v2-container.js @@ -53,6 +53,7 @@ function mapStateToProps (state) { tokenContract: getSelectedTokenContract(state), unapprovedTxs: state.metamask.unapprovedTxs, network: state.metamask.network, + t: t.bind(null, state.localeMessages), } } diff --git a/ui/app/components/send/to-autocomplete.js b/ui/app/components/send/to-autocomplete.js index ca034d855..4c54701cb 100644 --- a/ui/app/components/send/to-autocomplete.js +++ b/ui/app/components/send/to-autocomplete.js @@ -2,9 +2,9 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const AccountListItem = require('./account-list-item') -const t = require('../../../i18n-helper').getMessage +const connect = require('../../metamask-connect') -module.exports = ToAutoComplete +module.exports = connect()(ToAutoComplete) inherits(ToAutoComplete, Component) function ToAutoComplete () { @@ -93,7 +93,7 @@ ToAutoComplete.prototype.render = function () { return h('div.send-v2__to-autocomplete', {}, [ h('input.send-v2__to-autocomplete__input', { - placeholder: t(this.props.localeMessages, 'recipientAddress'), + placeholder: this.props.t('recipientAddress'), className: inError ? `send-v2__error-border` : '', value: to, onChange: event => onChange(event.target.value), diff --git a/ui/app/components/sender-to-recipient.js b/ui/app/components/sender-to-recipient.js index 02b6d96ea..dc72dc303 100644 --- a/ui/app/components/sender-to-recipient.js +++ b/ui/app/components/sender-to-recipient.js @@ -2,7 +2,6 @@ const { Component } = require('react') const h = require('react-hyperscript') const connect = require('../metamask-connect') const PropTypes = require('prop-types') -const t = require('../../i18n-helper').getMessage const Identicon = require('./identicon') class SenderToRecipient extends Component { @@ -31,7 +30,7 @@ class SenderToRecipient extends Component { ]), h('.sender-to-recipient__recipient', [ h('i.fa.fa-file-text-o'), - h('.sender-to-recipient__name.sender-to-recipient__recipient-name', t(this.props.localeMessages, 'newContract')), + h('.sender-to-recipient__name.sender-to-recipient__recipient-name', this.props.t('newContract')), ]), ]) ) diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js index f915135f6..31af74b36 100644 --- a/ui/app/components/shapeshift-form.js +++ b/ui/app/components/shapeshift-form.js @@ -7,7 +7,6 @@ const { qrcode } = require('qrcode-npm') const { shapeShiftSubview, pairUpdate, buyWithShapeShift } = require('../actions') const { isValidAddress } = require('../util') const SimpleDropdown = require('./dropdowns/simple-dropdown') -const t = require('../../i18n-helper').getMessage function mapStateToProps (state) { const { @@ -94,7 +93,7 @@ ShapeshiftForm.prototype.onBuyWithShapeShift = function () { })) .catch(() => this.setState({ showQrCode: false, - errorMessage: t(this.props.localeMessages, 'invalidRequest'), + errorMessage: this.props.t('invalidRequest'), isLoading: false, })) } @@ -126,10 +125,10 @@ ShapeshiftForm.prototype.renderMarketInfo = function () { return h('div.shapeshift-form__metadata', {}, [ - this.renderMetadata(t(this.props.localeMessages, 'status'), limit ? t(this.props.localeMessages, 'available') : t(this.props.localeMessages, 'unavailable')), - this.renderMetadata(t(this.props.localeMessages, 'limit'), limit), - this.renderMetadata(t(this.props.localeMessages, 'exchangeRate'), rate), - this.renderMetadata(t(this.props.localeMessages, 'min'), minimum), + this.renderMetadata(this.props.t('status'), limit ? this.props.t('available') : this.props.t('unavailable')), + this.renderMetadata(this.props.t('limit'), limit), + this.renderMetadata(this.props.t('exchangeRate'), rate), + this.renderMetadata(this.props.t('min'), minimum), ]) } @@ -143,7 +142,7 @@ ShapeshiftForm.prototype.renderQrCode = function () { return h('div.shapeshift-form', {}, [ h('div.shapeshift-form__deposit-instruction', [ - t(this.props.localeMessages, 'depositCoin', [depositCoin.toUpperCase()]), + this.props.t('depositCoin', [depositCoin.toUpperCase()]), ]), h('div', depositAddress), @@ -180,7 +179,7 @@ ShapeshiftForm.prototype.render = function () { h('div.shapeshift-form__selector', [ - h('div.shapeshift-form__selector-label', t(this.props.localeMessages, 'deposit')), + h('div.shapeshift-form__selector-label', this.props.t('deposit')), h(SimpleDropdown, { selectedOption: this.state.depositCoin, @@ -200,7 +199,7 @@ ShapeshiftForm.prototype.render = function () { h('div.shapeshift-form__selector', [ h('div.shapeshift-form__selector-label', [ - t(this.props.localeMessages, 'receive'), + this.props.t('receive'), ]), h('div.shapeshift-form__selector-input', ['ETH']), @@ -218,7 +217,7 @@ ShapeshiftForm.prototype.render = function () { }, [ h('div.shapeshift-form__address-input-label', [ - t(this.props.localeMessages, 'refundAddress'), + this.props.t('refundAddress'), ]), h('input.shapeshift-form__address-input', { @@ -240,7 +239,7 @@ ShapeshiftForm.prototype.render = function () { className: btnClass, disabled: !token, onClick: () => this.onBuyWithShapeShift(), - }, [t(this.props.localeMessages, 'buy')]), + }, [this.props.t('buy')]), ]) } diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index cc401bc34..d810eddc9 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -6,7 +6,6 @@ const vreme = new (require('vreme'))() const explorerLink = require('etherscan-link').createExplorerLink const actions = require('../actions') const addressSummary = require('../util').addressSummary -const t = require('../../i18n-helper').getMessage const CopyButton = require('./copyButton') const EthBalance = require('./eth-balance') @@ -76,7 +75,7 @@ ShiftListItem.prototype.renderUtilComponents = function () { value: this.props.depositAddress, }), h(Tooltip, { - title: t(this.props.localeMessages, 'qrCode'), + title: this.props.t('qrCode'), }, [ h('i.fa.fa-qrcode.pointer.pop-hover', { onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType)), @@ -136,8 +135,8 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, t(this.props.localeMessages, 'toETHviaShapeShift', [props.depositType])), - h('div', t(this.props.localeMessages, 'noDeposits')), + }, this.props.t('toETHviaShapeShift', [props.depositType])), + h('div', this.props.t('noDeposits')), h('div', { style: { fontSize: 'x-small', @@ -159,8 +158,8 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, t(this.props.localeMessages, 'toETHviaShapeShift', [props.depositType])), - h('div', t(this.props.localeMessages, 'conversionProgress')), + }, this.props.t('toETHviaShapeShift', [props.depositType])), + h('div', this.props.t('conversionProgress')), h('div', { style: { fontSize: 'x-small', @@ -185,7 +184,7 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, t(this.props.localeMessages, 'fromShapeShift')), + }, this.props.t('fromShapeShift')), h('div', formatDate(props.time)), h('div', { style: { @@ -197,7 +196,7 @@ ShiftListItem.prototype.renderInfo = function () { ]) case 'failed': - return h('span.error', '(' + t(this.props.localeMessages, 'failed') + ')') + return h('span.error', '(' + this.props.t('failed') + ')') default: return '' } diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index 7f4493b66..a1ed049f7 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -9,7 +9,6 @@ const classnames = require('classnames') const AccountDropdownMini = require('./dropdowns/account-dropdown-mini') const actions = require('../actions') -const t = require('../../i18n-helper').getMessage const { conversionUtil } = require('../conversion-util') const { @@ -55,7 +54,7 @@ SignatureRequest.prototype.renderHeader = function () { h('div.request-signature__header-background'), - h('div.request-signature__header__text', t(this.props.localeMessages, 'sigRequest')), + h('div.request-signature__header__text', this.props.t('sigRequest')), h('div.request-signature__header__tip-container', [ h('div.request-signature__header__tip'), @@ -76,7 +75,7 @@ SignatureRequest.prototype.renderAccountDropdown = function () { return h('div.request-signature__account', [ - h('div.request-signature__account-text', [t(this.props.localeMessages, 'account') + ':']), + h('div.request-signature__account-text', [this.props.t('account') + ':']), h(AccountDropdownMini, { selectedAccount, @@ -103,7 +102,7 @@ SignatureRequest.prototype.renderBalance = function () { return h('div.request-signature__balance', [ - h('div.request-signature__balance-text', [t(this.props.localeMessages, 'balance')]), + h('div.request-signature__balance-text', [this.props.t('balance')]), h('div.request-signature__balance-value', `${balanceInEther} ETH`), @@ -137,7 +136,7 @@ SignatureRequest.prototype.renderRequestInfo = function () { return h('div.request-signature__request-info', [ h('div.request-signature__headline', [ - t(this.props.localeMessages, 'yourSigRequested'), + this.props.t('yourSigRequested'), ]), ]) @@ -155,18 +154,18 @@ SignatureRequest.prototype.msgHexToText = function (hex) { SignatureRequest.prototype.renderBody = function () { let rows - let notice = t(this.props.localeMessages, 'youSign') + ':' + let notice = this.props.t('youSign') + ':' const { txData } = this.props const { type, msgParams: { data } } = txData if (type === 'personal_sign') { - rows = [{ name: t(this.props.localeMessages, 'message'), value: this.msgHexToText(data) }] + rows = [{ name: this.props.t('message'), value: this.msgHexToText(data) }] } else if (type === 'eth_signTypedData') { rows = data } else if (type === 'eth_sign') { - rows = [{ name: t(this.props.localeMessages, 'message'), value: data }] - notice = t(this.props.localeMessages, 'signNotice') + rows = [{ name: this.props.t('message'), value: data }] + notice = this.props.t('signNotice') } return h('div.request-signature__body', {}, [ @@ -225,10 +224,10 @@ SignatureRequest.prototype.renderFooter = function () { return h('div.request-signature__footer', [ h('button.request-signature__footer__cancel-button', { onClick: cancel, - }, t(this.props.localeMessages, 'cancel')), + }, this.props.t('cancel')), h('button.request-signature__footer__sign-button', { onClick: sign, - }, t(this.props.localeMessages, 'sign')), + }, this.props.t('sign')), ]) } diff --git a/ui/app/components/token-list.js b/ui/app/components/token-list.js index 439619158..ae22f3702 100644 --- a/ui/app/components/token-list.js +++ b/ui/app/components/token-list.js @@ -5,7 +5,6 @@ const TokenTracker = require('eth-token-tracker') const TokenCell = require('./token-cell.js') const connect = require('../metamask-connect') const selectors = require('../selectors') -const t = require('../../i18n-helper').getMessage function mapStateToProps (state) { return { @@ -43,7 +42,7 @@ TokenList.prototype.render = function () { const { tokens, isLoading, error } = state if (isLoading) { - return this.message(t(this.props.localeMessages, 'loadingTokens')) + return this.message(this.props.t('loadingTokens')) } if (error) { @@ -53,7 +52,7 @@ TokenList.prototype.render = function () { padding: '80px', }, }, [ - t(this.props.localeMessages, 'troubleTokenBalances'), + this.props.t('troubleTokenBalances'), h('span.hotFix', { style: { color: 'rgba(247, 134, 28, 1)', @@ -64,7 +63,7 @@ TokenList.prototype.render = function () { url: `https://ethplorer.io/address/${userAddress}`, }) }, - }, t(this.props.localeMessages, 'here')), + }, this.props.t('here')), ]) } diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index 3819de195..5e88d38d3 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -14,7 +14,6 @@ const { conversionUtil, multiplyCurrencies } = require('../conversion-util') const { calcTokenAmount } = require('../token-util') const { getCurrentCurrency } = require('../selectors') -const t = require('../../i18n-helper').getMessage module.exports = connect(mapStateToProps, mapDispatchToProps)(TxListItem) @@ -75,7 +74,7 @@ TxListItem.prototype.getAddressText = function () { default: return address ? `${address.slice(0, 10)}...${address.slice(-4)}` - : t(this.props.localeMessages, 'contractDeployment') + : this.props.t('contractDeployment') } } @@ -307,21 +306,21 @@ TxListItem.prototype.txStatusIndicator = function () { let name if (transactionStatus === 'unapproved') { - name = t('unapproved') + name = this.props.t('unapproved') } else if (transactionStatus === 'rejected') { - name = t('rejected') + name = this.props.t('rejected') } else if (transactionStatus === 'approved') { - name = t('approved') + name = this.props.t('approved') } else if (transactionStatus === 'signed') { - name = t('signed') + name = this.props.t('signed') } else if (transactionStatus === 'submitted') { - name = t('submitted') + name = this.props.t('submitted') } else if (transactionStatus === 'confirmed') { - name = t('confirmed') + name = this.props.t('confirmed') } else if (transactionStatus === 'failed') { - name = t('failed') + name = this.props.t('failed') } else if (transactionStatus === 'dropped') { - name = t('dropped') + name = this.props.t('dropped') } return name } diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js index d8c882ae2..7c2da30fe 100644 --- a/ui/app/components/tx-list.js +++ b/ui/app/components/tx-list.js @@ -10,7 +10,6 @@ const { formatDate } = require('../util') const { showConfTxPage } = require('../actions') const classnames = require('classnames') const { tokenInfoGetter } = require('../token-util') -const t = require('../../i18n-helper').getMessage module.exports = connect(mapStateToProps, mapDispatchToProps)(TxList) @@ -40,7 +39,7 @@ TxList.prototype.render = function () { return h('div.flex-column', [ h('div.flex-row.tx-list-header-wrapper', [ h('div.flex-row.tx-list-header', [ - h('div', t('transactions')), + h('div', this.props.t('transactions')), ]), ]), h('div.flex-column.tx-list-container', {}, [ @@ -57,7 +56,7 @@ TxList.prototype.renderTransaction = function () { : [h( 'div.tx-list-item.tx-list-item--empty', { key: 'tx-list-none' }, - [ t(this.props.localeMessages, 'noTransactions') ], + [ this.props.t('noTransactions') ], )] } @@ -111,7 +110,7 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa if (isUnapproved) { opts.onClick = () => showConfTxPage({ id: transactionId }) - opts.transactionStatus = t(this.props.localeMessages, 'Not Started') + opts.transactionStatus = this.props.t('Not Started') } else if (transactionHash) { opts.onClick = () => this.view(transactionHash, transactionNetworkId) } diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js index f7ca9cc97..81aee4308 100644 --- a/ui/app/components/tx-view.js +++ b/ui/app/components/tx-view.js @@ -5,7 +5,6 @@ const ethUtil = require('ethereumjs-util') const inherits = require('util').inherits const actions = require('../actions') const selectors = require('../selectors') -const t = require('../../i18n-helper').getMessage const BalanceComponent = require('./balance-component') const TxList = require('./tx-list') @@ -73,21 +72,21 @@ TxView.prototype.renderButtons = function () { onClick: () => showModal({ name: 'DEPOSIT_ETHER', }), - }, t(this.props.localeMessages, 'deposit')), + }, this.props.t('deposit')), h('button.btn-clear.hero-balance-button.allcaps', { style: { marginLeft: '0.8em', }, onClick: showSendPage, - }, t(this.props.localeMessages, 'send')), + }, this.props.t('send')), ]) ) : ( h('div.flex-row.flex-center.hero-balance-buttons', [ h('button.btn-clear.hero-balance-button', { onClick: showSendTokenPage, - }, t(this.props.localeMessages, 'send')), + }, this.props.t('send')), ]) ) } diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index 54770e436..c42fedf9a 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -11,7 +11,6 @@ const actions = require('../actions') const BalanceComponent = require('./balance-component') const TokenList = require('./token-list') const selectors = require('../selectors') -const t = require('../../i18n-helper').getMessage module.exports = connect(mapStateToProps, mapDispatchToProps)(WalletView) @@ -117,7 +116,7 @@ WalletView.prototype.render = function () { onClick: hideSidebar, }), - h('div.wallet-view__keyring-label.allcaps', isLoose ? t(this.props.localeMessages, 'imported') : ''), + h('div.wallet-view__keyring-label.allcaps', isLoose ? this.props.t('imported') : ''), h('div.flex-column.flex-center.wallet-view__name-container', { style: { margin: '0 auto' }, @@ -134,13 +133,13 @@ WalletView.prototype.render = function () { selectedIdentity.name, ]), - h('button.btn-clear.wallet-view__details-button.allcaps', t(this.props.localeMessages, 'details')), + h('button.btn-clear.wallet-view__details-button.allcaps', this.props.t('details')), ]), ]), h(Tooltip, { position: 'bottom', - title: this.state.hasCopied ? t(this.props.localeMessages, 'copiedExclamation') : t(this.props.localeMessages, 'copyToClipboard'), + title: this.state.hasCopied ? this.props.t('copiedExclamation') : this.props.t('copyToClipboard'), wrapperClassName: 'wallet-view__tooltip', }, [ h('button.wallet-view__address', { @@ -173,7 +172,7 @@ WalletView.prototype.render = function () { showAddTokenPage() hideSidebar() }, - }, t(this.props.localeMessages, 'addToken')), + }, this.props.t('addToken')), ]) } diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js index 797718498..c0c2d3ed0 100644 --- a/ui/app/first-time/init-menu.js +++ b/ui/app/first-time/init-menu.js @@ -6,7 +6,6 @@ const h = require('react-hyperscript') const Mascot = require('../components/mascot') const actions = require('../actions') const Tooltip = require('../components/tooltip') -const t = require('../../i18n-helper').getMessage const getCaretCoordinates = require('textarea-caret') const environmentType = require('../../../app/scripts/lib/environment-type') const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums @@ -60,7 +59,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: '#7F8082', marginBottom: 10, }, - }, t(this.props.localeMessages, 'appName')), + }, this.props.t('appName')), h('div', [ @@ -70,10 +69,10 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: '#7F8082', display: 'inline', }, - }, t(this.props.localeMessages, 'encryptNewDen')), + }, this.props.t('encryptNewDen')), h(Tooltip, { - title: t(this.props.localeMessages, 'denExplainer'), + title: this.props.t('denExplainer'), }, [ h('i.fa.fa-question-circle.pointer', { style: { @@ -93,7 +92,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: t(this.props.localeMessages, 'newPassword'), + placeholder: this.props.t('newPassword'), onInput: this.inputChanged.bind(this), style: { width: 260, @@ -105,7 +104,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box-confirm', - placeholder: t(this.props.localeMessages, 'confirmPassword'), + placeholder: this.props.t('confirmPassword'), onKeyPress: this.createVaultOnEnter.bind(this), onInput: this.inputChanged.bind(this), style: { @@ -120,7 +119,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { style: { margin: 12, }, - }, t(this.props.localeMessages, 'createDen')), + }, this.props.t('createDen')), h('.flex-row.flex-center.flex-grow', [ h('p.pointer', { @@ -130,7 +129,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: 'rgb(247, 134, 28)', textDecoration: 'underline', }, - }, t(this.props.localeMessages, 'importDen')), + }, this.props.t('importDen')), ]), h('.flex-row.flex-center.flex-grow', [ @@ -179,12 +178,12 @@ InitializeMenuScreen.prototype.createNewVaultAndKeychain = function () { var passwordConfirm = passwordConfirmBox.value if (password.length < 8) { - this.warning = t(this.props.localeMessages, 'passwordShort') + this.warning = this.props.t('passwordShort') this.props.dispatch(actions.displayWarning(this.warning)) return } if (password !== passwordConfirm) { - this.warning = t(this.props.localeMessages, 'passwordMismatch') + this.warning = this.props.t('passwordMismatch') this.props.dispatch(actions.displayWarning(this.warning)) return } diff --git a/ui/app/keychains/hd/recover-seed/confirmation.js b/ui/app/keychains/hd/recover-seed/confirmation.js index 4a62c8803..f97ac66fe 100644 --- a/ui/app/keychains/hd/recover-seed/confirmation.js +++ b/ui/app/keychains/hd/recover-seed/confirmation.js @@ -4,7 +4,6 @@ const Component = require('react').Component const connect = require('../../../metamask-connect') const h = require('react-hyperscript') const actions = require('../../../actions') -const t = require('../../../../i18n') module.exports = connect(mapStateToProps)(RevealSeedConfirmation) @@ -50,13 +49,13 @@ RevealSeedConfirmation.prototype.render = function () { }, }, [ - h('h4', t('revealSeedWordsWarning')), + h('h4', this.props.t('revealSeedWordsWarning')), // confirmation h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: t('enterPasswordConfirm'), + placeholder: this.props.t('enterPasswordConfirm'), onKeyPress: this.checkConfirmation.bind(this), style: { width: 260, @@ -92,7 +91,7 @@ RevealSeedConfirmation.prototype.render = function () { ), props.inProgress && ( - h('span.in-progress-notification', t('generatingSeed')) + h('span.in-progress-notification', this.props.t('generatingSeed')) ), ]), ]) diff --git a/ui/app/keychains/hd/restore-vault.js b/ui/app/keychains/hd/restore-vault.js index 164cf28dc..f47a2641a 100644 --- a/ui/app/keychains/hd/restore-vault.js +++ b/ui/app/keychains/hd/restore-vault.js @@ -2,7 +2,6 @@ const inherits = require('util').inherits const PersistentForm = require('../../../lib/persistent-form') const connect = require('../../metamask-connect') const h = require('react-hyperscript') -const t = require('../../../i18n') const actions = require('../../actions') module.exports = connect(mapStateToProps)(RestoreVaultScreen) @@ -37,23 +36,23 @@ RestoreVaultScreen.prototype.render = function () { padding: 6, }, }, [ - t('restoreVault'), + this.props.t('restoreVault'), ]), // wallet seed entry - h('h3', t('walletSeed')), + h('h3', this.props.t('walletSeed')), h('textarea.twelve-word-phrase.letter-spacey', { dataset: { persistentFormId: 'wallet-seed', }, - placeholder: t('secretPhrase'), + placeholder: this.props.t('secretPhrase'), }), // password h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: t('newPassword8Chars'), + placeholder: this.props.t('newPassword8Chars'), dataset: { persistentFormId: 'password', }, @@ -67,7 +66,7 @@ RestoreVaultScreen.prototype.render = function () { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box-confirm', - placeholder: t('confirmPassword'), + placeholder: this.props.t('confirmPassword'), onKeyPress: this.createOnEnter.bind(this), dataset: { persistentFormId: 'password-confirmation', @@ -97,7 +96,7 @@ RestoreVaultScreen.prototype.render = function () { style: { textTransform: 'uppercase', }, - }, t('cancel')), + }, this.props.t('cancel')), // submit h('button.primary', { @@ -105,7 +104,7 @@ RestoreVaultScreen.prototype.render = function () { style: { textTransform: 'uppercase', }, - }, t('ok')), + }, this.props.t('ok')), ]), ]) ) @@ -136,13 +135,13 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () { var passwordConfirmBox = document.getElementById('password-box-confirm') var passwordConfirm = passwordConfirmBox.value if (password.length < 8) { - this.warning = t('passwordNotLongEnough') + this.warning = this.props.t('passwordNotLongEnough') this.props.dispatch(actions.displayWarning(this.warning)) return } if (password !== passwordConfirm) { - this.warning = t('passwordsDontMatch') + this.warning = this.props.t('passwordsDontMatch') this.props.dispatch(actions.displayWarning(this.warning)) return } @@ -152,18 +151,18 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () { // true if the string has more than a space between words. if (seed.split(' ').length > 1) { - this.warning = t('spaceBetween') + this.warning = this.props.t('spaceBetween') this.props.dispatch(actions.displayWarning(this.warning)) return } // true if seed contains a character that is not between a-z or a space if (!seed.match(/^[a-z ]+$/)) { - this.warning = t('loweCaseWords') + this.warning = this.props.t('loweCaseWords') this.props.dispatch(actions.displayWarning(this.warning)) return } if (seed.split(' ').length !== 12) { - this.warning = t('seedPhraseReq') + this.warning = this.props.t('seedPhraseReq') this.props.dispatch(actions.displayWarning(this.warning)) return } diff --git a/ui/app/metamask-connect.js b/ui/app/metamask-connect.js index d13f8e87e..38fc05930 100644 --- a/ui/app/metamask-connect.js +++ b/ui/app/metamask-connect.js @@ -1,4 +1,5 @@ const connect = require('react-redux').connect +const t = require('../i18n-helper').getMessage const metamaskConnect = (mapStateToProps, mapDispatchToProps) => { return connect( @@ -12,7 +13,8 @@ const _higherOrderMapStateToProps = (mapStateToProps) => { const stateProps = mapStateToProps ? mapStateToProps(state, ownProps) : ownProps - stateProps.localeMessages = state.localeMessages || {} + console.log(`state.localeMessages`, state.localeMessages); + stateProps.t = t.bind(null, state.localeMessages) return stateProps } } diff --git a/ui/app/reducers/locale.js b/ui/app/reducers/locale.js index edfe9e865..bdd97acb4 100644 --- a/ui/app/reducers/locale.js +++ b/ui/app/reducers/locale.js @@ -8,7 +8,9 @@ function reduceMetamask (state, action) { switch (action.type) { case actions.SET_LOCALE_MESSAGES: - return action.value + return extend(localeMessagesState, { + current: action.value, + }) default: return localeMessagesState } diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index 31118378d..49947a11c 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -1,7 +1,6 @@ const { inherits } = require('util') const PersistentForm = require('../lib/persistent-form') const h = require('react-hyperscript') -const t = require('../i18n') const ethAbi = require('ethereumjs-abi') const ethUtil = require('ethereumjs-util') @@ -189,9 +188,9 @@ SendTransactionScreen.prototype.renderHeader = function () { return h('div.page-container__header', [ - h('div.page-container__title', selectedToken ? t('sendTokens') : t('sendETH')), + h('div.page-container__title', selectedToken ? this.props.t('sendTokens') : this.props.t('sendETH')), - h('div.page-container__subtitle', t('onlySendToEtherAddress')), + h('div.page-container__subtitle', this.props.t('onlySendToEtherAddress')), h('div.page-container__header-close', { onClick: () => { @@ -262,11 +261,11 @@ SendTransactionScreen.prototype.handleToChange = function (to) { let toError = null if (!to) { - toError = t('required') + toError = this.props.t('required') } else if (!isValidAddress(to)) { - toError = t('invalidAddressRecipient') + toError = this.props.t('invalidAddressRecipient') } else if (to === from) { - toError = t('fromToSame') + toError = this.props.t('fromToSame') } updateSendTo(to) @@ -282,9 +281,9 @@ SendTransactionScreen.prototype.renderToRow = function () { h('div.send-v2__form-label', [ - t('to'), + this.props.t('to'), - this.renderErrorMessage(t('to')), + this.renderErrorMessage(this.props.t('to')), ]), @@ -382,11 +381,11 @@ SendTransactionScreen.prototype.validateAmount = function (value) { ) if (conversionRate && !sufficientBalance) { - amountError = t('insufficientFunds') + amountError = this.props.t('insufficientFunds') } else if (verifyTokenBalance && !sufficientTokens) { - amountError = t('insufficientTokens') + amountError = this.props.t('insufficientTokens') } else if (amountLessThanZero) { - amountError = t('negativeETH') + amountError = this.props.t('negativeETH') } updateSendErrors({ amount: amountError }) @@ -416,7 +415,7 @@ SendTransactionScreen.prototype.renderAmountRow = function () { setMaxModeTo(true) this.setAmountToMax() }, - }, [ !maxModeOn ? t('max') : '' ]), + }, [ !maxModeOn ? this.props.t('max') : '' ]), ]), h('div.send-v2__form-field', [ @@ -514,11 +513,11 @@ SendTransactionScreen.prototype.renderFooter = function () { clearSend() goHome() }, - }, t('cancel')), + }, this.props.t('cancel')), h('button.btn-clear.page-container__footer-button', { disabled: !noErrors || !gasTotal || missingTokenBalance, onClick: event => this.onSubmit(event), - }, t('next')), + }, this.props.t('next')), ]) } diff --git a/ui/app/settings.js b/ui/app/settings.js index f75b1e8b4..d3525e9c0 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -10,7 +10,6 @@ const TabBar = require('./components/tab-bar') const SimpleDropdown = require('./components/dropdowns/simple-dropdown') const ToggleButton = require('react-toggle-button') const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums -const t = require('../i18n') const getInfuraCurrencyOptions = () => { const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => { @@ -62,8 +61,8 @@ class Settings extends Component { return h('div.settings__tabs', [ h(TabBar, { tabs: [ - { content: t('settings'), key: 'settings' }, - { content: t('info'), key: 'info' }, + { content: this.props.t('settings'), key: 'settings' }, + { content: this.props.t('info'), key: 'info' }, ], defaultTab: activeTab, tabSelected: key => this.setState({ activeTab: key }), @@ -76,7 +75,7 @@ class Settings extends Component { return h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', t('blockiesIdenticon')), + h('span', this.props.t('blockiesIdenticon')), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ @@ -96,13 +95,13 @@ class Settings extends Component { return h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', t('currentConversion')), + h('span', this.props.t('currentConversion')), h('span.settings__content-description', `Updated ${Date(conversionDate)}`), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h(SimpleDropdown, { - placeholder: t('selectCurrency'), + placeholder: this.props.t('selectCurrency'), options: getInfuraCurrencyOptions(), selectedOption: currentCurrency, onSelect: newCurrency => setCurrentCurrency(newCurrency), @@ -142,31 +141,31 @@ class Settings extends Component { switch (provider.type) { case 'mainnet': - title = t('currentNetwork') - value = t('mainnet') + title = this.props.t('currentNetwork') + value = this.props.t('mainnet') color = '#038789' break case 'ropsten': - title = t('currentNetwork') - value = t('ropsten') + title = this.props.t('currentNetwork') + value = this.props.t('ropsten') color = '#e91550' break case 'kovan': - title = t('currentNetwork') - value = t('kovan') + title = this.props.t('currentNetwork') + value = this.props.t('kovan') color = '#690496' break case 'rinkeby': - title = t('currentNetwork') - value = t('rinkeby') + title = this.props.t('currentNetwork') + value = this.props.t('rinkeby') color = '#ebb33f' break default: - title = t('currentRpc') + title = this.props.t('currentRpc') value = provider.rpcTarget } @@ -187,12 +186,12 @@ class Settings extends Component { return ( h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', t('newRPC')), + h('span', this.props.t('newRPC')), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('input.settings__input', { - placeholder: t('newRPC'), + placeholder: this.props.t('newRPC'), onChange: event => this.setState({ newRpc: event.target.value }), onKeyPress: event => { if (event.key === 'Enter') { @@ -205,7 +204,7 @@ class Settings extends Component { event.preventDefault() this.validateRpc(this.state.newRpc) }, - }, t('save')), + }, this.props.t('save')), ]), ]), ]) @@ -221,9 +220,9 @@ class Settings extends Component { const appendedRpc = `http://${newRpc}` if (validUrl.isWebUri(appendedRpc)) { - displayWarning(t('uriErrorMsg')) + displayWarning(this.props.t('uriErrorMsg')) } else { - displayWarning(t('invalidRPC')) + displayWarning(this.props.t('invalidRPC')) } } } @@ -232,10 +231,10 @@ class Settings extends Component { return ( h('div.settings__content-row', [ h('div.settings__content-item', [ - h('div', t('stateLogs')), + h('div', this.props.t('stateLogs')), h( 'div.settings__content-description', - t('stateLogsDescription') + this.props.t('stateLogsDescription') ), ]), h('div.settings__content-item', [ @@ -244,13 +243,13 @@ class Settings extends Component { onClick (event) { window.logStateString((err, result) => { if (err) { - this.state.dispatch(actions.displayWarning(t('stateLogError'))) + this.state.dispatch(actions.displayWarning(this.props.t('stateLogError'))) } else { exportAsFile('MetaMask State Logs.json', result) } }) }, - }, t('downloadStateLogs')), + }, this.props.t('downloadStateLogs')), ]), ]), ]) @@ -262,7 +261,7 @@ class Settings extends Component { return ( h('div.settings__content-row', [ - h('div.settings__content-item', t('revealSeedWords')), + h('div.settings__content-item', this.props.t('revealSeedWords')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('button.settings__clear-button.settings__clear-button--red', { @@ -270,7 +269,7 @@ class Settings extends Component { event.preventDefault() revealSeedConfirmation() }, - }, t('revealSeedWords')), + }, this.props.t('revealSeedWords')), ]), ]), ]) @@ -282,7 +281,7 @@ class Settings extends Component { return ( h('div.settings__content-row', [ - h('div.settings__content-item', t('useOldUI')), + h('div.settings__content-item', this.props.t('useOldUI')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('button.settings__clear-button.settings__clear-button--orange', { @@ -290,7 +289,7 @@ class Settings extends Component { event.preventDefault() setFeatureFlagToBeta() }, - }, t('useOldUI')), + }, this.props.t('useOldUI')), ]), ]), ]) @@ -301,7 +300,7 @@ class Settings extends Component { const { showResetAccountConfirmationModal } = this.props return h('div.settings__content-row', [ - h('div.settings__content-item', t('resetAccount')), + h('div.settings__content-item', this.props.t('resetAccount')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('button.settings__clear-button.settings__clear-button--orange', { @@ -309,7 +308,7 @@ class Settings extends Component { event.preventDefault() showResetAccountConfirmationModal() }, - }, t('resetAccount')), + }, this.props.t('resetAccount')), ]), ]), ]) @@ -345,13 +344,13 @@ class Settings extends Component { renderInfoLinks () { return ( h('div.settings__content-item.settings__content-item--without-height', [ - h('div.settings__info-link-header', t('links')), + h('div.settings__info-link-header', this.props.t('links')), h('div.settings__info-link-item', [ h('a', { href: 'https://metamask.io/privacy.html', target: '_blank', }, [ - h('span.settings__info-link', t('privacyMsg')), + h('span.settings__info-link', this.props.t('privacyMsg')), ]), ]), h('div.settings__info-link-item', [ @@ -359,7 +358,7 @@ class Settings extends Component { href: 'https://metamask.io/terms.html', target: '_blank', }, [ - h('span.settings__info-link', t('terms')), + h('span.settings__info-link', this.props.t('terms')), ]), ]), h('div.settings__info-link-item', [ @@ -367,7 +366,7 @@ class Settings extends Component { href: 'https://metamask.io/attributions.html', target: '_blank', }, [ - h('span.settings__info-link', t('attributions')), + h('span.settings__info-link', this.props.t('attributions')), ]), ]), h('hr.settings__info-separator'), @@ -376,7 +375,7 @@ class Settings extends Component { href: 'https://support.metamask.io', target: '_blank', }, [ - h('span.settings__info-link', t('supportCenter')), + h('span.settings__info-link', this.props.t('supportCenter')), ]), ]), h('div.settings__info-link-item', [ @@ -384,7 +383,7 @@ class Settings extends Component { href: 'https://metamask.io/', target: '_blank', }, [ - h('span.settings__info-link', t('visitWebSite')), + h('span.settings__info-link', this.props.t('visitWebSite')), ]), ]), h('div.settings__info-link-item', [ @@ -392,7 +391,7 @@ class Settings extends Component { target: '_blank', href: 'mailto:help@metamask.io?subject=Feedback', }, [ - h('span.settings__info-link', t('emailUs')), + h('span.settings__info-link', this.props.t('emailUs')), ]), ]), ]) @@ -414,7 +413,7 @@ class Settings extends Component { h('div.settings__info-item', [ h( 'div.settings__info-about', - t('builtInCalifornia') + this.props.t('builtInCalifornia') ), ]), ]), diff --git a/ui/app/unlock.js b/ui/app/unlock.js index 423e76e10..e8e1ba051 100644 --- a/ui/app/unlock.js +++ b/ui/app/unlock.js @@ -5,7 +5,6 @@ const connect = require('./metamask-connect') const actions = require('./actions') const getCaretCoordinates = require('textarea-caret') const EventEmitter = require('events').EventEmitter -const t = require('../i18n-helper').getMessage const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums const environmentType = require('../../app/scripts/lib/environment-type') @@ -41,7 +40,7 @@ UnlockScreen.prototype.render = function () { textTransform: 'uppercase', color: '#7F8082', }, - }, t(this.props.localeMessages, 'appName')), + }, this.props.t('appName')), h('input.large-input', { type: 'password', @@ -67,7 +66,7 @@ UnlockScreen.prototype.render = function () { style: { margin: 10, }, - }, t('login')), + }, this.props.t('login')), h('p.pointer', { onClick: () => { @@ -81,7 +80,7 @@ UnlockScreen.prototype.render = function () { color: 'rgb(247, 134, 28)', textDecoration: 'underline', }, - }, t('restoreFromSeed')), + }, this.props.t('restoreFromSeed')), h('p.pointer', { onClick: () => { @@ -94,7 +93,7 @@ UnlockScreen.prototype.render = function () { textDecoration: 'underline', marginTop: '32px', }, - }, t('classicInterface')), + }, this.props.t('classicInterface')), ]) ) } diff --git a/ui/i18n-helper.js b/ui/i18n-helper.js index 10147b0f6..70555f239 100644 --- a/ui/i18n-helper.js +++ b/ui/i18n-helper.js @@ -2,13 +2,15 @@ const log = require('loglevel') const getMessage = (locale, key, substitutions) => { + console.log(`locale, key, substitutions`, locale, key, substitutions); // check locale is loaded if (!locale) { // throw new Error('Translator - has not loaded a locale yet.') return '' } // check entry is present - const entry = locale[key] + const { current, en } = locale + const entry = current[key] || en[key] if (!entry) { log.error(`Translator - Unable to find value for "${key}"`) // throw new Error(`Translator - Unable to find value for "${key}"`) diff --git a/ui/index.js b/ui/index.js index 598d2876b..fe57f791a 100644 --- a/ui/index.js +++ b/ui/index.js @@ -31,6 +31,7 @@ async function startApp (metamaskState, accountManager, opts) { if (!metamaskState.featureFlags) metamaskState.featureFlags = {} const currentLocaleMessages = await fetchLocale(metamaskState.currentLocale) + const enLocaleMessages = await fetchLocale('en') const store = configureStore({ @@ -40,7 +41,10 @@ async function startApp (metamaskState, accountManager, opts) { // appState represents the current tab's popup state appState: {}, - localeMessages: currentLocaleMessages, + localeMessages: { + current: currentLocaleMessages, + en: enLocaleMessages, + }, // Which blockchain we are using: networkVersion: opts.networkVersion, diff --git a/yarn.lock b/yarn.lock index 7512e10db..c1b9bef83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -253,6 +253,10 @@ ansi-colors@^1.0.1: dependencies: ansi-wrap "^0.1.0" +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + ansi-escapes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" @@ -299,6 +303,10 @@ ansi-wrap@0.1.0, ansi-wrap@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" +ansi@^0.3.0, ansi@~0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/ansi/-/ansi-0.3.1.tgz#0c42d4fb17160d5a9af1e484bace1c66922c1b21" + ansicolors@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" @@ -1611,7 +1619,7 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@^3.0.5, bluebird@^3.1.1, bluebird@^3.3.0, bluebird@^3.4.6, bluebird@^3.5.0: +bluebird@^3.0.5, bluebird@^3.1.1, bluebird@^3.3.0, bluebird@^3.4.6, bluebird@^3.4.7, bluebird@^3.5.0: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" @@ -2021,6 +2029,10 @@ buffer-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" +buffer-from@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" + buffer-more-ints@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz#26b3885d10fa13db7fc01aae3aab870199e0124c" @@ -2155,6 +2167,22 @@ caniuse-lite@^1.0.30000810, caniuse-lite@^1.0.30000813: version "1.0.30000814" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000814.tgz#73eb6925ac2e54d495218f1ea0007da3940e488b" +caporal@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/caporal/-/caporal-0.10.0.tgz#2ddfbe5ede26d2bd356f042f564ff57803cdabc9" + dependencies: + bluebird "^3.4.7" + chalk "^1.1.3" + cli-table2 "^0.2.0" + fast-levenshtein "^2.0.6" + lodash.camelcase "^4.3.0" + lodash.kebabcase "^4.1.1" + lodash.merge "^4.6.0" + micromist "^1.0.1" + prettyjson "^1.2.1" + tabtab "^2.2.2" + winston "^2.3.1" + caseless@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" @@ -2353,12 +2381,27 @@ classnames@^2.2.4, classnames@^2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: restore-cursor "^2.0.0" +cli-table2@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" + dependencies: + lodash "^3.10.1" + string-width "^1.0.1" + optionalDependencies: + colors "^1.1.2" + cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" @@ -2635,6 +2678,15 @@ concat-stream@^1.4.3, concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@ readable-stream "^2.2.2" typedarray "^0.0.6" +concat-stream@^1.4.7: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + concat-stream@~1.5.0, concat-stream@~1.5.1: version "1.5.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" @@ -3677,6 +3729,14 @@ es-abstract@^1.5.0, es-abstract@^1.6.1, es-abstract@^1.7.0: is-callable "^1.1.3" is-regex "^1.0.4" +es-check@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-check/-/es-check-2.0.3.tgz#04eafde54f5bfcf0881b1ae35c4a5205a9041ee2" + dependencies: + acorn "^5.1.2" + caporal "^0.10.0" + glob "^7.1.2" + es-to-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" @@ -4462,6 +4522,10 @@ exists-stat@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + expand-braces@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/expand-braces/-/expand-braces-0.1.2.tgz#488b1d1d2451cb3d3a6b192cfc030f44c5855fea" @@ -4579,6 +4643,14 @@ extensionizer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/extensionizer/-/extensionizer-1.0.0.tgz#01c209bbea6d9c0acba77129c3aa4a9a98fc3538" +external-editor@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" + dependencies: + extend "^3.0.0" + spawn-sync "^1.0.15" + tmp "^0.0.29" + external-editor@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" @@ -4696,6 +4768,13 @@ fetch-ponyfill@^4.0.0: dependencies: node-fetch "~1.7.1" +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -5068,6 +5147,16 @@ gather-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b" +gauge@~1.2.5: + version "1.2.7" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-1.2.7.tgz#e9cec5483d3d4ee0ef44b60a7d99e4935e136d93" + dependencies: + ansi "^0.3.0" + has-unicode "^2.0.0" + lodash.pad "^4.1.0" + lodash.padend "^4.1.0" + lodash.padstart "^4.1.0" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -6046,6 +6135,25 @@ inline-source-map@~0.6.0: dependencies: source-map "~0.5.3" +inquirer@^1.0.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" + dependencies: + ansi-escapes "^1.1.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + external-editor "^1.1.0" + figures "^1.3.5" + lodash "^4.3.0" + mute-stream "0.0.6" + pinkie-promise "^2.0.0" + run-async "^2.2.0" + rx "^4.1.0" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + inquirer@^3.0.6: version "3.3.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" @@ -7173,6 +7281,10 @@ lodash.assignin@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + lodash.castarray@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" @@ -7191,6 +7303,10 @@ lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" +lodash.difference@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" + lodash.escape@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" @@ -7228,6 +7344,10 @@ lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" +lodash.kebabcase@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" + lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" @@ -7244,10 +7364,26 @@ lodash.memoize@~3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" +lodash.merge@^4.6.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" + lodash.mergewith@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55" +lodash.pad@^4.1.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/lodash.pad/-/lodash.pad-4.5.1.tgz#4330949a833a7c8da22cc20f6a26c4d59debba70" + +lodash.padend@^4.1.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e" + +lodash.padstart@^4.1.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b" + lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" @@ -7281,10 +7417,18 @@ lodash.templatesettings@^3.0.0: lodash._reinterpolate "^3.0.0" lodash.escape "^3.0.0" +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + lodash.uniqby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" +lodash@^3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + lodash@^4.0.0, lodash@^4.1.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.0, lodash@~4.17.2, lodash@~4.17.4: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -7655,6 +7799,12 @@ micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" +micromist@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromist/-/micromist-1.0.2.tgz#41f84949a04c30cdc60a394d0cb06aaa08b86364" + dependencies: + lodash.camelcase "^4.3.0" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -7883,6 +8033,10 @@ mute-stdout@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.0.tgz#5b32ea07eb43c9ded6130434cf926f46b2a7fd4d" +mute-stream@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" + mute-stream@0.0.7, mute-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -8203,6 +8357,14 @@ npm-run-path@^2.0.0: gauge "~2.7.3" set-blocking "~2.0.0" +npmlog@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-2.0.4.tgz#98b52530f2514ca90d09ec5b22c8846722375692" + dependencies: + ansi "~0.3.1" + are-we-there-yet "~1.1.2" + gauge "~1.2.5" + nth-check@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" @@ -8437,6 +8599,10 @@ onecolor@^3.0.4: version "3.0.5" resolved "https://registry.yarnpkg.com/onecolor/-/onecolor-3.0.5.tgz#36eff32201379efdf1180fb445e51a8e2425f9f6" +onetime@^1.0.0: + version "1.1.0" + resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" @@ -8505,7 +8671,11 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: +os-shim@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -8967,6 +9137,13 @@ pretty-hrtime@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" +prettyjson@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prettyjson/-/prettyjson-1.2.1.tgz#fcffab41d19cab4dfae5e575e64246619b12d289" + dependencies: + colors "^1.1.2" + minimist "^1.2.0" + printf@^0.2.3: version "0.2.5" resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" @@ -9967,6 +10144,13 @@ response-stream@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/response-stream/-/response-stream-0.0.0.tgz#da4b17cc7684c98c962beb4d95f668c8dcad09d5" +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -10038,6 +10222,10 @@ rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" +rx@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -10538,6 +10726,13 @@ spawn-args@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" +spawn-sync@^1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + dependencies: + concat-stream "^1.4.7" + os-shim "^0.1.2" + spawn-wrap@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.4.2.tgz#cff58e73a8224617b6561abdc32586ea0c82248c" @@ -11034,6 +11229,19 @@ table@^4.0.1: slice-ansi "1.0.0" string-width "^2.1.1" +tabtab@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tabtab/-/tabtab-2.2.2.tgz#7a047f143b010b4cbd31f857e82961512cbf4e14" + dependencies: + debug "^2.2.0" + inquirer "^1.0.2" + lodash.difference "^4.5.0" + lodash.uniq "^4.5.0" + minimist "^1.2.0" + mkdirp "^0.5.1" + npmlog "^2.0.3" + object-assign "^4.1.0" + tap-parser@^5.1.0: version "5.4.0" resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-5.4.0.tgz#6907e89725d7b7fa6ae41ee2c464c3db43188aec" @@ -11252,6 +11460,12 @@ tmp@0.0.33, tmp@0.0.x, tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +tmp@^0.0.29: + version "0.0.29" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + dependencies: + os-tmpdir "~1.0.1" + to-absolute-glob@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b" @@ -12055,6 +12269,17 @@ winston@2.1.x: pkginfo "0.3.x" stack-trace "0.0.x" +winston@^2.3.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.1.tgz#a3a9265105564263c6785b4583b8c8aca26fded6" + dependencies: + async "~1.0.0" + colors "1.0.x" + cycle "1.0.x" + eyes "0.1.x" + isstream "0.1.x" + stack-trace "0.0.x" + wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" From 6cbadc0aa342550654cbdb00c3b276542fbd19c5 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 21 Mar 2018 22:54:52 -0230 Subject: [PATCH 016/246] Missed modifications of t() in merge resolution. --- ui/app/components/network-display.js | 3 +-- ui/app/components/pending-tx/confirm-deploy-contract.js | 1 - ui/app/components/pending-tx/confirm-send-ether.js | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/ui/app/components/network-display.js b/ui/app/components/network-display.js index 9dc31b5c7..0bc5cdaf8 100644 --- a/ui/app/components/network-display.js +++ b/ui/app/components/network-display.js @@ -3,7 +3,6 @@ const h = require('react-hyperscript') const PropTypes = require('prop-types') const { connect } = require('react-redux') const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') -const t = require('../../i18n') const networkToColorHash = { 1: '#038789', @@ -31,7 +30,7 @@ class NetworkDisplay extends Component { const { provider: { type } } = this.props return h('.network-display__container', [ this.renderNetworkIcon(), - h('.network-name', t(type)), + h('.network-name', this.props.t(type)), ]) } } diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index 512aa793d..60afdc7ae 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -8,7 +8,6 @@ const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const hexToBn = require('../../../../app/scripts/lib/hex-to-bn') const { conversionUtil } = require('../../conversion-util') -const t = require('../../../i18n') const SenderToRecipient = require('../sender-to-recipient') const NetworkDisplay = require('../network-display') diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index 68c6f14d2..b76dc94d8 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -13,7 +13,6 @@ const { multiplyCurrencies, } = require('../../conversion-util') const GasFeeDisplay = require('../send/gas-fee-display-v2') -const t = require('../../../i18n') const SenderToRecipient = require('../sender-to-recipient') const NetworkDisplay = require('../network-display') From 3c144302d65053fc3082b8b24662fc3e0231ca3a Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 21 Mar 2018 22:57:09 -0230 Subject: [PATCH 017/246] Remove console.logs --- ui/app/metamask-connect.js | 1 - ui/i18n-helper.js | 1 - 2 files changed, 2 deletions(-) diff --git a/ui/app/metamask-connect.js b/ui/app/metamask-connect.js index 38fc05930..097be8dc3 100644 --- a/ui/app/metamask-connect.js +++ b/ui/app/metamask-connect.js @@ -13,7 +13,6 @@ const _higherOrderMapStateToProps = (mapStateToProps) => { const stateProps = mapStateToProps ? mapStateToProps(state, ownProps) : ownProps - console.log(`state.localeMessages`, state.localeMessages); stateProps.t = t.bind(null, state.localeMessages) return stateProps } diff --git a/ui/i18n-helper.js b/ui/i18n-helper.js index 70555f239..dc83f45c9 100644 --- a/ui/i18n-helper.js +++ b/ui/i18n-helper.js @@ -2,7 +2,6 @@ const log = require('loglevel') const getMessage = (locale, key, substitutions) => { - console.log(`locale, key, substitutions`, locale, key, substitutions); // check locale is loaded if (!locale) { // throw new Error('Translator - has not loaded a locale yet.') From 18f85835296f12814e0593dfc67b29ac672ddf53 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 21 Mar 2018 23:10:28 -0230 Subject: [PATCH 018/246] Fix references to undefined 'this.props' --- ui/app/accounts/import/index.js | 22 +++++++--------- .../components/modals/deposit-ether-modal.js | 26 +++++++++---------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js index 75552924b..3720e637f 100644 --- a/ui/app/accounts/import/index.js +++ b/ui/app/accounts/import/index.js @@ -9,26 +9,24 @@ const JsonImportView = require('./json.js') const PrivateKeyImportView = require('./private-key.js') -module.exports = connect(mapStateToProps)(AccountImportSubview) - -function mapStateToProps (state) { - return { - menuItems: [ - this.props.t('privateKey'), - this.props.t('jsonFile'), - ], - } -} +module.exports = connect()(AccountImportSubview) inherits(AccountImportSubview, Component) function AccountImportSubview () { Component.call(this) } +AccountImportSubview.prototype.getMenuItemTexts = function () { + return [ + this.props.t('privateKey'), + this.props.t('jsonFile'), + ] +} + AccountImportSubview.prototype.render = function () { const props = this.props const state = this.state || {} - const { menuItems } = props + const menuItems = this.getMenuItemTexts() const { type } = state return ( @@ -80,7 +78,7 @@ AccountImportSubview.prototype.renderImportView = function () { const props = this.props const state = this.state || {} const { type } = state - const { menuItems } = props + const menuItems = this.getMenuItemTexts() const current = type || menuItems[0] switch (current) { diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index 0b097d546..40f805181 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -14,10 +14,6 @@ let SHAPESHIFT_ROW_TITLE let SHAPESHIFT_ROW_TEXT let FAUCET_ROW_TITLE -const facuetRowText = (networkName) => { - return this.props.t('getEtherFromFaucet', [networkName]) -} - function mapStateToProps (state) { return { network: state.metamask.network, @@ -44,17 +40,17 @@ function mapDispatchToProps (dispatch) { } inherits(DepositEtherModal, Component) -function DepositEtherModal () { +function DepositEtherModal (props) { Component.call(this) // need to set after i18n locale has loaded - DIRECT_DEPOSIT_ROW_TITLE = this.props.t('directDepositEther') - DIRECT_DEPOSIT_ROW_TEXT = this.props.t('directDepositEtherExplainer') - COINBASE_ROW_TITLE = this.props.t('buyCoinbase') - COINBASE_ROW_TEXT = this.props.t('buyCoinbaseExplainer') - SHAPESHIFT_ROW_TITLE = this.props.t('depositShapeShift') - SHAPESHIFT_ROW_TEXT = this.props.t('depositShapeShiftExplainer') - FAUCET_ROW_TITLE = this.props.t('testFaucet') + DIRECT_DEPOSIT_ROW_TITLE = props.t('directDepositEther') + DIRECT_DEPOSIT_ROW_TEXT = props.t('directDepositEtherExplainer') + COINBASE_ROW_TITLE = props.t('buyCoinbase') + COINBASE_ROW_TEXT = props.t('buyCoinbaseExplainer') + SHAPESHIFT_ROW_TITLE = props.t('depositShapeShift') + SHAPESHIFT_ROW_TEXT = props.t('depositShapeShiftExplainer') + FAUCET_ROW_TITLE = props.t('testFaucet') this.state = { buyingWithShapeshift: false, @@ -63,6 +59,10 @@ function DepositEtherModal () { module.exports = connect(mapStateToProps, mapDispatchToProps)(DepositEtherModal) +DepositEtherModal.prototype.facuetRowText = function (networkName) { + return this.props.t('getEtherFromFaucet', [networkName]) +} + DepositEtherModal.prototype.renderRow = function ({ logo, title, @@ -156,7 +156,7 @@ DepositEtherModal.prototype.render = function () { this.renderRow({ logo: h('i.fa.fa-tint.fa-2x'), title: FAUCET_ROW_TITLE, - text: facuetRowText(networkName), + text: this.facuetRowText(networkName), buttonLabel: this.props.t('getEther'), onButtonClick: () => toFaucet(network), hide: !isTestNetwork || buyingWithShapeshift, From a82631791efb496efc9f611a2a3edbac7123d221 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 21 Mar 2018 23:48:10 -0230 Subject: [PATCH 019/246] Lint fixes --- ui/app/accounts/import/index.js | 4 +--- ui/app/accounts/import/json.js | 2 +- ui/app/accounts/new-account/create-form.js | 2 +- ui/app/components/account-dropdowns.js | 2 +- ui/app/components/buy-button-subview.js | 4 ++-- ui/app/components/dropdowns/components/account-dropdowns.js | 2 +- ui/app/components/modals/new-account-modal.js | 4 ++-- ui/app/components/modals/notification-modal.js | 2 +- ui/app/components/network-display.js | 1 + ui/app/components/pending-tx/confirm-deploy-contract.js | 5 +++-- ui/app/components/pending-tx/confirm-send-token.js | 2 +- ui/app/components/send/send-v2-container.js | 1 - ui/app/components/sender-to-recipient.js | 4 ++-- ui/app/settings.js | 1 + 14 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js index 3720e637f..b09b50ef7 100644 --- a/ui/app/accounts/import/index.js +++ b/ui/app/accounts/import/index.js @@ -17,14 +17,13 @@ function AccountImportSubview () { } AccountImportSubview.prototype.getMenuItemTexts = function () { - return [ + return [ this.props.t('privateKey'), this.props.t('jsonFile'), ] } AccountImportSubview.prototype.render = function () { - const props = this.props const state = this.state || {} const menuItems = this.getMenuItemTexts() const { type } = state @@ -75,7 +74,6 @@ AccountImportSubview.prototype.render = function () { } AccountImportSubview.prototype.renderImportView = function () { - const props = this.props const state = this.state || {} const { type } = state const menuItems = this.getMenuItemTexts() diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index 8bcc1a14e..431c693ee 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -112,7 +112,7 @@ JsonImportSubview.propTypes = { goHome: PropTypes.func, displayWarning: PropTypes.func, importNewJsonAccount: PropTypes.func, - localeMessages: PropTypes.object, + t: PropTypes.func, } const mapStateToProps = state => { diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js index b0e109cd7..728088568 100644 --- a/ui/app/accounts/new-account/create-form.js +++ b/ui/app/accounts/new-account/create-form.js @@ -61,7 +61,7 @@ NewAccountCreateForm.propTypes = { createAccount: PropTypes.func, goHome: PropTypes.func, numberOfExistingAccounts: PropTypes.number, - localeMessages: PropTypes.object, + t: PropTypes.object, } const mapStateToProps = state => { diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index 88c7dbb60..84678fee6 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -300,7 +300,7 @@ AccountDropdowns.propTypes = { style: PropTypes.object, enableAccountOptions: PropTypes.bool, enableAccountsSelector: PropTypes.bool, - localeMessages: PropTypes.object, + t: PropTypes.func, } const mapDispatchToProps = (dispatch) => { diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js index 2243ce38b..eafa2af91 100644 --- a/ui/app/components/buy-button-subview.js +++ b/ui/app/components/buy-button-subview.js @@ -143,7 +143,7 @@ BuyButtonSubview.prototype.primarySubview = function () { case '4': case '42': const networkName = networkNames[network] - const label = `${networkName} ${t('testFaucet')}` + const label = `${networkName} ${this.props.t('testFaucet')}` return ( h('div.flex-column', { style: { @@ -203,7 +203,7 @@ BuyButtonSubview.prototype.mainnetSubview = function () { 'ShapeShift', ], subtext: { - 'Coinbase': `${t('crypto')}/${t('fiat')} (${t('usaOnly')})`, + 'Coinbase': `${this.props.t('crypto')}/${this.props.t('fiat')} (${this.props.t('usaOnly')})`, 'ShapeShift': this.props.t('crypto'), }, onClick: this.radioHandler.bind(this), diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index d570b3d36..5e7c0d554 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -425,7 +425,7 @@ AccountDropdowns.propTypes = { enableAccountsSelector: PropTypes.bool, enableAccountOption: PropTypes.bool, enableAccountOptions: PropTypes.bool, - localeMessages: PropTypes.object, + t: PropTypes.func, } const mapDispatchToProps = (dispatch) => { diff --git a/ui/app/components/modals/new-account-modal.js b/ui/app/components/modals/new-account-modal.js index c46980855..372b65251 100644 --- a/ui/app/components/modals/new-account-modal.js +++ b/ui/app/components/modals/new-account-modal.js @@ -11,7 +11,7 @@ class NewAccountModal extends Component { const newAccountNumber = numberOfExistingAccounts + 1 this.state = { - newAccountName: `${t('account')} ${newAccountNumber}`, + newAccountName: `${props.t('account')} ${newAccountNumber}`, } } @@ -69,7 +69,7 @@ NewAccountModal.propTypes = { showImportPage: PropTypes.func, createAccount: PropTypes.func, numberOfExistingAccounts: PropTypes.number, - localeMessages: PropTypes.object, + t: PropTypes.func, } const mapStateToProps = state => { diff --git a/ui/app/components/modals/notification-modal.js b/ui/app/components/modals/notification-modal.js index 3c4ab5194..5d6dca177 100644 --- a/ui/app/components/modals/notification-modal.js +++ b/ui/app/components/modals/notification-modal.js @@ -62,7 +62,7 @@ NotificationModal.propTypes = { showCancelButton: PropTypes.bool, showConfirmButton: PropTypes.bool, onConfirm: PropTypes.func, - localeMessages: PropTypes.object, + t: PropTypes.func, } const mapDispatchToProps = dispatch => { diff --git a/ui/app/components/network-display.js b/ui/app/components/network-display.js index 0bc5cdaf8..ce1ab21a5 100644 --- a/ui/app/components/network-display.js +++ b/ui/app/components/network-display.js @@ -38,6 +38,7 @@ class NetworkDisplay extends Component { NetworkDisplay.propTypes = { network: PropTypes.string, provider: PropTypes.object, + t: PropTypes.func, } const mapStateToProps = ({ metamask: { network, provider } }) => { diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index 60afdc7ae..370ffdda3 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -32,7 +32,7 @@ class ConfirmDeployContract extends Component { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.displayWarning('invalidGasParams') + this.props.displayWarning(this.props.t('invalidGasParams')) this.setState({ submitting: false }) } } @@ -324,6 +324,7 @@ ConfirmDeployContract.propTypes = { conversionRate: PropTypes.number, currentCurrency: PropTypes.string, selectedAddress: PropTypes.string, + t: PropTypes.func, } const mapStateToProps = state => { @@ -346,7 +347,7 @@ const mapDispatchToProps = dispatch => { return { backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)), cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })), - displayWarning: warning => actions.displayWarning(t(warning)), + displayWarning: warning => actions.displayWarning(warning), } } diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index 50d803fc4..f9b6bb79e 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -327,7 +327,7 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${tokenAmount} ${symbol}`), - h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} ${t('gas')}`), + h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} ${this.props.t('gas')}`), ]), ]) ) diff --git a/ui/app/components/send/send-v2-container.js b/ui/app/components/send/send-v2-container.js index d90a6bf75..25902cfce 100644 --- a/ui/app/components/send/send-v2-container.js +++ b/ui/app/components/send/send-v2-container.js @@ -53,7 +53,6 @@ function mapStateToProps (state) { tokenContract: getSelectedTokenContract(state), unapprovedTxs: state.metamask.unapprovedTxs, network: state.metamask.network, - t: t.bind(null, state.localeMessages), } } diff --git a/ui/app/components/sender-to-recipient.js b/ui/app/components/sender-to-recipient.js index 420d50e42..590769b02 100644 --- a/ui/app/components/sender-to-recipient.js +++ b/ui/app/components/sender-to-recipient.js @@ -59,9 +59,9 @@ class SenderToRecipient extends Component { SenderToRecipient.propTypes = { senderName: PropTypes.string, senderAddress: PropTypes.string, - localeMessages: PropTypes.object, - recipientName: PropTypes.string, + recipientName: PropTypes.string, recipientAddress: PropTypes.string, + t: PropTypes.func, } module.exports = { diff --git a/ui/app/settings.js b/ui/app/settings.js index d3525e9c0..96790cb10 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -459,6 +459,7 @@ Settings.propTypes = { isMascara: PropTypes.bool, updateCurrentLocale: PropTypes.func, currentLocale: PropTypes.object, + t: PropTypes.func, } const mapStateToProps = state => { From 3d3bd0eaf001e153eb3c7e9cea5c269bd17d1978 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 22 Mar 2018 00:08:01 -0230 Subject: [PATCH 020/246] Correct connect reference in confirm-send-ether, confirm-deploy-contract, network-display. --- ui/app/components/network-display.js | 2 +- ui/app/components/pending-tx/confirm-deploy-contract.js | 2 +- ui/app/components/pending-tx/confirm-send-ether.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/app/components/network-display.js b/ui/app/components/network-display.js index ce1ab21a5..111a82be1 100644 --- a/ui/app/components/network-display.js +++ b/ui/app/components/network-display.js @@ -1,7 +1,7 @@ const { Component } = require('react') const h = require('react-hyperscript') const PropTypes = require('prop-types') -const { connect } = require('react-redux') +const connect = require('../metamask-connect') const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') const networkToColorHash = { diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index 370ffdda3..f41fa51e6 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -1,5 +1,5 @@ const { Component } = require('react') -const { connect } = require('react-redux') +const connect = require('../../metamask-connect') const h = require('react-hyperscript') const PropTypes = require('prop-types') const actions = require('../../actions') diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index b76dc94d8..255f0e8a2 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const { connect } = require('react-redux') +const connect = require('../../metamask-connect') const h = require('react-hyperscript') const inherits = require('util').inherits const actions = require('../../actions') From ca5bce477e9acdd5f8457b99de2c32a7b4f26e33 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 22 Mar 2018 00:54:44 -0230 Subject: [PATCH 021/246] Fix sender-to-recipient export and non-existent translation key. --- ui/app/components/sender-to-recipient.js | 6 ++---- ui/app/components/tx-list.js | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/ui/app/components/sender-to-recipient.js b/ui/app/components/sender-to-recipient.js index 590769b02..4c3881668 100644 --- a/ui/app/components/sender-to-recipient.js +++ b/ui/app/components/sender-to-recipient.js @@ -59,11 +59,9 @@ class SenderToRecipient extends Component { SenderToRecipient.propTypes = { senderName: PropTypes.string, senderAddress: PropTypes.string, - recipientName: PropTypes.string, + recipientName: PropTypes.string, recipientAddress: PropTypes.string, t: PropTypes.func, } -module.exports = { - AccountDropdowns: connect()(SenderToRecipient), -} \ No newline at end of file +module.exports = connect()(SenderToRecipient) diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js index 7c2da30fe..5f09d887e 100644 --- a/ui/app/components/tx-list.js +++ b/ui/app/components/tx-list.js @@ -110,7 +110,7 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa if (isUnapproved) { opts.onClick = () => showConfTxPage({ id: transactionId }) - opts.transactionStatus = this.props.t('Not Started') + opts.transactionStatus = this.props.t('notStarted') } else if (transactionHash) { opts.onClick = () => this.view(transactionHash, transactionNetworkId) } From edf63f8b51ec0717e580ec69b495987a00062b92 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 22 Mar 2018 01:09:21 -0230 Subject: [PATCH 022/246] Add en localeMessages to test states. --- development/genStates.js | 5 +++++ development/get-locale-messages.js | 12 ++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 development/get-locale-messages.js diff --git a/development/genStates.js b/development/genStates.js index bc274c757..1b21a42e5 100644 --- a/development/genStates.js +++ b/development/genStates.js @@ -1,6 +1,7 @@ const fs = require('fs') const path = require('path') const promisify = require('pify') +const getLocaleMessages = require('./get-locale-messages') start().catch(console.error) @@ -12,6 +13,10 @@ async function start () { const stateFilePath = path.join(__dirname, 'states', stateFileName) const stateFileContent = await promisify(fs.readFile)(stateFilePath, 'utf8') const state = JSON.parse(stateFileContent) + + const enLocaleMessages = await getLocaleMessages() + state.localeMessages = { en: enLocaleMessages, current: {} } + const stateName = stateFileName.split('.')[0].replace(/-/g, ' ', 'g') states[stateName] = state })) diff --git a/development/get-locale-messages.js b/development/get-locale-messages.js new file mode 100644 index 000000000..3b76a851d --- /dev/null +++ b/development/get-locale-messages.js @@ -0,0 +1,12 @@ +const fs = require('fs') +const path = require('path') +const promisify = require('pify') + +async function getLocaleMessages () { + const localeMessagesPath = path.join(process.cwd(), 'app', '_locales', 'en', 'messages.json') + const enLocaleMessagesJSON = await promisify(fs.readFile)(localeMessagesPath) + const enLocaleMessages = JSON.parse(enLocaleMessagesJSON) + return enLocaleMessages +} + +module.exports = getLocaleMessages From d613dfb43419ea1e18691659d39f6ac403c21d75 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 22 Mar 2018 01:19:00 -0230 Subject: [PATCH 023/246] Correct reprice title and subtitle key names. --- app/_locales/en/messages.json | 4 ++-- ui/app/components/pending-tx/confirm-send-token.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 7f6b9e72d..9fac9c248 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -659,10 +659,10 @@ "save": { "message": "Save" }, - "reprice:title": { + "reprice_title": { "message": "Reprice Transaction" }, - "reprice:subtitle": { + "reprice_subtitle": { "message": "Increase your gas price to attempt to overwrite and speed up your transaction" }, "saveAsFile": { diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index f9b6bb79e..9196f9ab1 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -350,9 +350,9 @@ ConfirmSendToken.prototype.render = function () { this.inputs = [] const isTxReprice = Boolean(txMeta.lastGasPrice) - const title = isTxReprice ? this.props.t('reprice:title') : this.props.t('confirm') + const title = isTxReprice ? this.props.t('reprice_title') : this.props.t('confirm') const subtitle = isTxReprice - ? this.props.t('reprice:subtitle') + ? this.props.t('reprice_subtitle') : this.props.t('pleaseReviewTransaction') return ( From a0df4b6892f3a8f15d2915a062ebe1d9cdeabaec Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 22 Mar 2018 12:36:13 -0230 Subject: [PATCH 024/246] Correct proptypes for t in new-account/create-form.js --- ui/app/accounts/new-account/create-form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js index 728088568..65f29914c 100644 --- a/ui/app/accounts/new-account/create-form.js +++ b/ui/app/accounts/new-account/create-form.js @@ -61,7 +61,7 @@ NewAccountCreateForm.propTypes = { createAccount: PropTypes.func, goHome: PropTypes.func, numberOfExistingAccounts: PropTypes.number, - t: PropTypes.object, + t: PropTypes.func, } const mapStateToProps = state => { From b9309f689be7f55fde0a32a6e576784aa9fc1061 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 22 Mar 2018 12:39:16 -0230 Subject: [PATCH 025/246] Use extension api to get initial locale. --- app/scripts/background.js | 10 ++++++---- app/scripts/controllers/preferences.js | 2 +- .../lib/get-first-preferred-lang-code.js | 18 ++++++++++++++++++ app/scripts/metamask-controller.js | 2 +- package.json | 1 + 5 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 app/scripts/lib/get-first-preferred-lang-code.js diff --git a/app/scripts/background.js b/app/scripts/background.js index 8bd7766ad..c8fe1cd63 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -19,7 +19,7 @@ const setupRaven = require('./lib/setupRaven') const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry') const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics') const EdgeEncryptor = require('./edge-encryptor') - +const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code') const STORAGE_KEY = 'metamask-config' const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' @@ -58,7 +58,8 @@ setupMetamaskMeshMetrics() async function initialize () { const initState = await loadStateFromPersistence() - await setupController(initState) + const initLangCode = await getFirstPreferredLangCode() + await setupController(initState, initLangCode) log.debug('MetaMask initialization complete.') } @@ -90,11 +91,10 @@ async function loadStateFromPersistence () { return versionedData.data } -function setupController (initState) { +function setupController (initState, initLangCode) { // // MetaMask Controller // - const controller = new MetamaskController({ // User confirmation callbacks: showUnconfirmedMessage: triggerUi, @@ -102,6 +102,8 @@ function setupController (initState) { showUnapprovedTx: triggerUi, // initial state initState, + // initial locale code + initLangCode, // platform specific api platform, encryptor: isEdge ? new EdgeEncryptor() : undefined, diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index dc7da90d0..b4819d951 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -11,7 +11,7 @@ class PreferencesController { tokens: [], useBlockie: false, featureFlags: {}, - currentLocale: 'ja', + currentLocale: opts.initLangCode, }, opts.initState) this.store = new ObservableStore(initState) } diff --git a/app/scripts/lib/get-first-preferred-lang-code.js b/app/scripts/lib/get-first-preferred-lang-code.js new file mode 100644 index 000000000..74dfe246c --- /dev/null +++ b/app/scripts/lib/get-first-preferred-lang-code.js @@ -0,0 +1,18 @@ +const fs = require('fs') +const path = require('path') +const extension = require('extensionizer') +const promisify = require('pify') + +const existingLocaleCodes = fs.readdirSync(path.join(__dirname, '..', '..', '_locales')) + +async function getFirstPreferredLangCode () { + const userPreferredLocaleCodes = await promisify( + extension.i18n.getAcceptLanguages, + { errorFirst: false } + )().catch(err => console.log('err123', err)) + const firstPreferredLangCode = userPreferredLocaleCodes.find(code => existingLocaleCodes.includes(code)) + // const firstPreferredLangCode = userPreferredLocaleCodes[0] + return firstPreferredLangCode || 'en' +} + +module.exports = getFirstPreferredLangCode diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index bd092cea0..6e82f6011 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -57,7 +57,6 @@ module.exports = class MetamaskController extends EventEmitter { this.defaultMaxListeners = 20 this.sendUpdate = debounce(this.privateSendUpdate.bind(this), 200) - this.opts = opts const initState = opts.initState || {} this.recordFirstTimeInfo(initState) @@ -82,6 +81,7 @@ module.exports = class MetamaskController extends EventEmitter { // preferences controller this.preferencesController = new PreferencesController({ initState: initState.PreferencesController, + initLangCode: opts.initLangCode, }) // currency controller diff --git a/package.json b/package.json index 1aae1092e..f10491fd1 100644 --- a/package.json +++ b/package.json @@ -141,6 +141,7 @@ "promise-filter": "^1.1.0", "promise-to-callback": "^1.0.0", "pump": "^3.0.0", + "pify": "^3.0.0", "pumpify": "^1.3.4", "qrcode-npm": "0.0.3", "ramda": "^0.24.1", From 11a30378d7aea9d5e331ff52f61b136820a54fb1 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 23 Mar 2018 14:21:32 -0230 Subject: [PATCH 026/246] Memoize t function in metamask-connect --- ui/app/metamask-connect.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ui/app/metamask-connect.js b/ui/app/metamask-connect.js index 097be8dc3..8da594635 100644 --- a/ui/app/metamask-connect.js +++ b/ui/app/metamask-connect.js @@ -9,11 +9,17 @@ const metamaskConnect = (mapStateToProps, mapDispatchToProps) => { } const _higherOrderMapStateToProps = (mapStateToProps) => { + let _t + let currentLocale return (state, ownProps = {}) => { const stateProps = mapStateToProps ? mapStateToProps(state, ownProps) : ownProps - stateProps.t = t.bind(null, state.localeMessages) + if (currentLocale !== state.metamask.currentLocale) { + currentLocale = state.metamask.currentLocale + _t = t.bind(null, state.localeMessages) + } + stateProps.t = _t return stateProps } } From 3ed9933adbd138d00ea8f85a7def8a1020b99060 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 23 Mar 2018 14:28:34 -0230 Subject: [PATCH 027/246] Include locales in served test files. --- test/base.conf.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/base.conf.js b/test/base.conf.js index adb5357e8..e2e9d44ba 100644 --- a/test/base.conf.js +++ b/test/base.conf.js @@ -19,11 +19,13 @@ module.exports = function(config) { 'test/integration/jquery-3.1.0.min.js', { pattern: 'dist/chrome/images/**/*.*', watched: false, included: false, served: true }, { pattern: 'dist/chrome/fonts/**/*.*', watched: false, included: false, served: true }, + { pattern: 'dist/chrome/_locales/**/*.*', watched: false, included: false, served: true }, ], proxies: { '/images/': '/base/dist/chrome/images/', '/fonts/': '/base/dist/chrome/fonts/', + '/_locales/': '/base/dist/chrome/_locales/', }, // test results reporter to use From 08e67c4e4a7548cc90321e8eb172a428e03568b4 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 23 Mar 2018 14:29:59 -0230 Subject: [PATCH 028/246] Default current locale in metamask reducer to empty string. --- ui/app/reducers/metamask.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 6e226b0e6..89acdaac3 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -46,7 +46,7 @@ function reduceMetamask (state, action) { networkEndpointType: OLD_UI_NETWORK_TYPE, isRevealingSeedWords: false, welcomeScreenSeen: false, - currentLocale: 'ja', + currentLocale: '', }, state.metamask) switch (action.type) { From 0d71dd7ca0c0c3178670a9882c34d180495a7031 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 23 Mar 2018 14:31:15 -0230 Subject: [PATCH 029/246] i18n helper fetchLocale handles 404 gracefully --- ui/i18n-helper.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ui/i18n-helper.js b/ui/i18n-helper.js index dc83f45c9..3ce24ddfb 100644 --- a/ui/i18n-helper.js +++ b/ui/i18n-helper.js @@ -25,10 +25,18 @@ const getMessage = (locale, key, substitutions) => { return phrase } -async function fetchLocale (localeName) { - const response = await fetch(`/_locales/${localeName}/messages.json`) - const locale = await response.json() - return locale +function fetchLocale (localeName) { + return new Promise((resolve, reject) => { + return fetch(`/_locales/${localeName}/messages.json`) + .then(response => response.json()) + .then( + locale => resolve(locale), + error => { + log.error(`failed to fetch ${localeName} locale because of ${error}`) + resolve({}) + } + ) + }) } module.exports = { From cd204ee8036d0efb46aaf5cced5babca94ea97d6 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 23 Mar 2018 14:51:19 -0230 Subject: [PATCH 030/246] Add currentLocale to test states. --- development/states/add-token.json | 3 ++- development/states/confirm-new-ui.json | 3 ++- development/states/confirm-sig-requests.json | 3 ++- development/states/first-time.json | 3 ++- development/states/send-edit.json | 3 ++- development/states/send-new-ui.json | 3 ++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/development/states/add-token.json b/development/states/add-token.json index e78393b7f..9c0f16372 100644 --- a/development/states/add-token.json +++ b/development/states/add-token.json @@ -106,7 +106,8 @@ "errors": {}, "maxModeOn": false, "editingTransactionId": null - } + }, + "currentLocale": "en" }, "appState": { "menuOpen": false, diff --git a/development/states/confirm-new-ui.json b/development/states/confirm-new-ui.json index 6981781a9..ae3098ecb 100644 --- a/development/states/confirm-new-ui.json +++ b/development/states/confirm-new-ui.json @@ -128,7 +128,8 @@ "errors": {}, "maxModeOn": false, "editingTransactionId": null - } + }, + "currentLocale": "en" }, "appState": { "menuOpen": false, diff --git a/development/states/confirm-sig-requests.json b/development/states/confirm-sig-requests.json index 0a691e948..b51003d11 100644 --- a/development/states/confirm-sig-requests.json +++ b/development/states/confirm-sig-requests.json @@ -149,7 +149,8 @@ "errors": {}, "maxModeOn": false, "editingTransactionId": null - } + }, + "currentLocale": "en" }, "appState": { "menuOpen": false, diff --git a/development/states/first-time.json b/development/states/first-time.json index 4f5352992..fe9188b80 100644 --- a/development/states/first-time.json +++ b/development/states/first-time.json @@ -36,7 +36,8 @@ }, "shapeShiftTxList": [], "lostAccounts": [], - "tokens": [] + "tokens": [], + "currentLocale": "en" }, "appState": { "menuOpen": false, diff --git a/development/states/send-edit.json b/development/states/send-edit.json index 6981781a9..ae3098ecb 100644 --- a/development/states/send-edit.json +++ b/development/states/send-edit.json @@ -128,7 +128,8 @@ "errors": {}, "maxModeOn": false, "editingTransactionId": null - } + }, + "currentLocale": "en" }, "appState": { "menuOpen": false, diff --git a/development/states/send-new-ui.json b/development/states/send-new-ui.json index a0a2c66e4..1297a9139 100644 --- a/development/states/send-new-ui.json +++ b/development/states/send-new-ui.json @@ -107,7 +107,8 @@ "errors": {}, "maxModeOn": false, "editingTransactionId": null - } + }, + "currentLocale": "en" }, "appState": { "menuOpen": false, From cecc5c48a7011f2a7a3332961e861384c7f51f96 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sat, 24 Mar 2018 13:20:46 +0000 Subject: [PATCH 031/246] chore(package): update eslint-plugin-mocha to version 5.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index adcd03b3b..9fa3bba94 100644 --- a/package.json +++ b/package.json @@ -201,7 +201,7 @@ "enzyme": "^3.3.0", "enzyme-adapter-react-15": "^1.0.5", "eslint-plugin-chai": "0.0.1", - "eslint-plugin-mocha": "^4.9.0", + "eslint-plugin-mocha": "^5.0.0", "eslint-plugin-react": "^7.4.0", "eth-json-rpc-middleware": "^1.2.7", "fs-promise": "^2.0.3", From 43dde3cbde4118ef5d5b40faca6af8b308a1a902 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Mon, 26 Mar 2018 15:58:36 -0700 Subject: [PATCH 033/246] transactions - only save up to 40 txs totall across all networks --- app/scripts/lib/tx-state-manager.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js index ad07c813f..ab344ae9b 100644 --- a/app/scripts/lib/tx-state-manager.js +++ b/app/scripts/lib/tx-state-manager.js @@ -38,11 +38,6 @@ module.exports = class TransactionStateManager extends EventEmitter { }, opts) } - // Returns the number of txs for the current network. - getTxCount () { - return this.getTxList().length - } - getTxList () { const network = this.getNetwork() const fullTxList = this.getFullTxList() @@ -88,7 +83,7 @@ module.exports = class TransactionStateManager extends EventEmitter { txMeta.history.push(snapshot) const transactions = this.getFullTxList() - const txCount = this.getTxCount() + const txCount = transactions.length const txHistoryLimit = this.txHistoryLimit // checks if the length of the tx history is From 81e2ab20d9264fdd9018f1c714e0fd54d8b1b2ec Mon Sep 17 00:00:00 2001 From: gasolin Date: Tue, 27 Mar 2018 10:16:22 +0800 Subject: [PATCH 034/246] [zh-TW] fix translation and add missing strings --- app/_locales/zh_TW/messages.json | 61 ++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index 90f63c6a6..e39793430 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -171,6 +171,9 @@ "customGas": { "message": "自訂 Gas" }, + "customToken": { + "message": "自訂代幣" + }, "customize": { "message": "自訂" }, @@ -184,7 +187,7 @@ "message": "小數點精度" }, "defaultNetwork": { - "message": "預設Ether交易網路為主網(Main Net)。" + "message": "預設 Ether 交易網路為主網路(Main Net)。" }, "denExplainer": { "message": "你的 DEN 是在你的 MetaMask 中的加密密碼儲存庫。" @@ -215,7 +218,7 @@ "message": "從 ShapeShift 存入" }, "depositShapeShiftExplainer": { - "message": "如果你擁有其他加密貨幣,你可以直接交易並存入 Ether 到你的MetaMask錢包。不需要開帳戶。" + "message": "如果你擁有其他加密貨幣,你可以直接交易並存入 Ether 到你的 MetaMask 錢包。不需要開帳戶。" }, "details": { "message": "詳情" @@ -227,7 +230,7 @@ "message": "直接存入 Ether" }, "directDepositEtherExplainer": { - "message": "如果你已經擁有了一些Ether,使用直接存入功能是讓你的新錢包最快取得Ether的方式。" + "message": "如果你已經擁有了一些 Ether,使用直接存入功能是讓你的新錢包最快取得 Ether 的方式。" }, "done": { "message": "完成" @@ -285,6 +288,9 @@ "message": "檔案導入失敗?點擊這裡!", "description": "Helps user import their account from a JSON file" }, + "followTwitter": { + "message": "追蹤 Twitter" + }, "from": { "message": "來源地址" }, @@ -313,6 +319,9 @@ "gasLimitTooLow": { "message": "Gas 上限至少為 21000" }, + "generatingSeed": { + "message": "產生助憶詞中..." + }, "gasPrice": { "message": "Gas 價格 (GWEI)" }, @@ -362,6 +371,9 @@ "importAccount": { "message": "導入帳戶" }, + "importAccountMsg": { + "message":" 匯入的帳戶與您原有 MetaMask 帳戶的助憶詞並無關聯. 請查看與導入帳戶相關的資料 " + }, "importAnAccount": { "message": "導入一個帳戶" }, @@ -400,12 +412,15 @@ "message": "無效的 RPC URI" }, "jsonFail": { - "message": "有東西出錯了. 請確認你的 JSON 檔案格式正確." + "message": "有東西出錯了. 請確認你的 JSON 檔案格式正確。" }, "jsonFile": { "message": "JSON 檔案", "description": "format for importing an account" }, + "keepTrackTokens": { + "message": "持續追蹤您 MetaMask 帳戶中的代幣。" + }, "kovan": { "message": "Kovan 測試網路" }, @@ -415,6 +430,9 @@ "max": { "message": "最大值" }, + "learnMore": { + "message": "了解更多。" + }, "lessThanMax": { "message": "必須小於等於 $1.", "description": "helper for inputting hex as decimal input" @@ -437,17 +455,20 @@ "localhost": { "message": "Localhost 8545" }, + "login": { + "message": "登入" + }, "logout": { "message": "登出" }, "loose": { - "message": "非Metamask帳號" + "message": "非 MetaMask 帳號" }, "loweCaseWords": { "message": "助憶詞僅包含小寫字元" }, "mainnet": { - "message": "主乙太坊網路" + "message": "乙太坊 主網路" }, "message": { "message": "訊息" @@ -465,7 +486,7 @@ "message": "必須選擇至少 1 代幣." }, "needEtherInWallet": { - "message": "要使用 MetaMask 存取 DAPP時,您的錢包中需要有 Ether。" + "message": "要使用 MetaMask 存取 DAPP 時,您的錢包中需要有 Ether。" }, "needImportFile": { "message": "您必須選擇一個檔案來導入。", @@ -475,6 +496,9 @@ "message": "您必須為選擇好的檔案輸入密碼。", "description": "Password and file needed to import an account" }, + "negativeETH": { + "message": "不能送出負值的 ETH。" + }, "networks": { "message": "網路" }, @@ -525,6 +549,9 @@ "message": "或", "description": "choice between creating or importing a new account" }, + "passwordCorrect": { + "message": "請確認您的密碼是正確的。" + }, "passwordMismatch": { "message": "密碼不一致", "description": "in password creation process, the two new password fields did not match" @@ -546,6 +573,12 @@ "pleaseReviewTransaction": { "message": "請檢查你的交易。" }, + "popularTokens": { + "message": "常見的代幣" + }, + "privacyMsg": { + "message": "隱私政策" + }, "privateKey": { "message": "私鑰", "description": "select this type of file to use to import an account" @@ -681,6 +714,9 @@ "onlySendToEtherAddress": { "message": "只發送 ETH 到乙太坊地址." }, + "searchTokens": { + "message": "搜尋代幣" + }, "sendTokensAnywhere": { "message": "發送代幣給擁有乙太坊帳戶的任何人" }, @@ -700,13 +736,16 @@ "message": "顯示 QR Code" }, "sign": { - "message": "簽名" + "message": "簽署" + }, + "signed": { + "message": "已簽署" }, "signMessage": { "message": "簽署訊息" }, "signNotice": { - "message": "簽署此訊息可能會產生危險的副作用。 \n只從你完全信任的網站上簽名。這種危險的方法;將在未來的版本中被移除。" + "message": "簽署此訊息可能會產生危險地副作用。 \n只從你完全信任的網站上簽署。這種危險的方法;將在未來的版本中被移除。" }, "sigRequest": { "message": "請求簽署" @@ -767,7 +806,7 @@ "message": "代幣餘額:" }, "tokenSelection": { - "message": "搜尋代幣或是從熱門代幣列表中選擇。" + "message": "搜尋代幣或是從常見代幣列表中選擇。" }, "tokenSymbol": { "message": "代幣代號" @@ -804,7 +843,7 @@ "message": "歡迎使用新版界面 (Beta)" }, "uiWelcomeMessage": { - "message": "你現在正在使用新的 Metamask 界面。試試諸如發送代幣等新功能,有任何問題請告知我們。" + "message": "你現在正在使用新版 MetaMask 界面。試試諸如發送代幣等新功能吧,有任何問題請告知我們。" }, "unapproved": { "message": "未同意" From 7c9fcf26ba16288e7fbaa019cdec522284ff611a Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Mar 2018 02:07:31 -0230 Subject: [PATCH 035/246] Stop using navigateTo for external link in settings. --- old-ui/app/config.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/old-ui/app/config.js b/old-ui/app/config.js index 9e07cf348..7da3694ac 100644 --- a/old-ui/app/config.js +++ b/old-ui/app/config.js @@ -168,7 +168,6 @@ ConfigScreen.prototype.render = function () { h('a', { href: 'http://metamask.helpscoutdocs.com/article/36-resetting-an-account', target: '_blank', - onClick (event) { this.navigateTo(event.target.href) }, }, 'Read more.'), ]), h('br'), @@ -260,7 +259,3 @@ function currentProviderDisplay (metamaskState) { h('span', value), ]) } - -ConfigScreen.prototype.navigateTo = function (url) { - global.platform.openWindow({ url }) -} From 91f91d92fe2798789c26739af818e8f18a2547fb Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Mar 2018 03:11:55 -0230 Subject: [PATCH 036/246] Prevent users from adding custom token if decimals is an empty string. --- ui/app/add-token.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/app/add-token.js b/ui/app/add-token.js index b4ea4a532..22d5cbc43 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -143,7 +143,10 @@ AddTokenScreen.prototype.validate = function () { errors.customAddress = t('invalidAddress') } - const validDecimals = customDecimals !== null && customDecimals >= 0 && customDecimals < 36 + const validDecimals = customDecimals !== null + && customDecimals !== '' + && customDecimals >= 0 + && customDecimals < 36 if (!validDecimals) { errors.customDecimals = t('decimalsMustZerotoTen') } From db4800dc3593fa2d5988f1e3c1cb1acf6eac763d Mon Sep 17 00:00:00 2001 From: gasolin Date: Tue, 27 Mar 2018 13:19:44 +0800 Subject: [PATCH 037/246] remove unavailable goToBuyEtherView propType --- mascara/src/app/first-time/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/mascara/src/app/first-time/index.js b/mascara/src/app/first-time/index.js index c0bba53d6..0cc3b4b0e 100644 --- a/mascara/src/app/first-time/index.js +++ b/mascara/src/app/first-time/index.js @@ -20,7 +20,6 @@ class FirstTimeFlow extends Component { seedWords: PropTypes.string, address: PropTypes.string, noActiveNotices: PropTypes.bool, - goToBuyEtherView: PropTypes.func.isRequired, }; static defaultProps = { @@ -171,4 +170,3 @@ export default connect( openBuyEtherModal: () => dispatch(showModal({ name: 'DEPOSIT_ETHER'})), }) )(FirstTimeFlow) - From f2ab3a06b10255e87bc1539c9163843823637030 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Mar 2018 04:00:14 -0230 Subject: [PATCH 038/246] Long token amounts in wallet are truncated with ellipsis. --- ui/app/css/itcss/components/token-list.scss | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ui/app/css/itcss/components/token-list.scss b/ui/app/css/itcss/components/token-list.scss index 9dc4f1055..e8de317e3 100644 --- a/ui/app/css/itcss/components/token-list.scss +++ b/ui/app/css/itcss/components/token-list.scss @@ -10,9 +10,14 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( transition: linear 200ms; background-color: rgba($wallet-balance-bg, 0); position: relative; + flex: 1; + min-width: 0; &__token-balance { font-size: 1.5rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; @media #{$wallet-balance-breakpoint-range} { font-size: 95%; @@ -51,7 +56,8 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( &__balance-ellipsis { display: flex; align-items: center; - width: 100%; + min-width: 0; + flex: 1; } &__ellipsis { @@ -61,6 +67,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( &__balance-wrapper { flex: 1 1 auto; + min-width: 0; } } From 252d69228245f26f9ff2a2ba22db5b17074c009e Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Mar 2018 03:40:34 -0230 Subject: [PATCH 039/246] Prefixes to addresses with 0x before sending. --- ui/app/send-v2.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index 620da73f8..67a470956 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -597,7 +597,7 @@ SendTransactionScreen.prototype.onSubmit = function (event) { event.preventDefault() const { from: {address: from}, - to, + to: _to, amount, gasLimit: gas, gasPrice, @@ -616,6 +616,8 @@ SendTransactionScreen.prototype.onSubmit = function (event) { return } + const to = ethUtil.addHexPrefix(_to) + this.addToAddressBookIfNew(to, toNickname) if (editingTransactionId) { From bfa62f719fa699c9341fe724c6462d087a56845f Mon Sep 17 00:00:00 2001 From: "R.IIzuka" Date: Tue, 27 Mar 2018 22:05:37 +0900 Subject: [PATCH 040/246] Update messages.json Fixed Japanese phrases. Add some translations. --- app/_locales/ja/messages.json | 76 ++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index bab8d3b95..d9762a3e9 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -14,6 +14,9 @@ "address": { "message": "アドレス" }, + "addCustomToken": { + "message": "カスタムトークンを追加" + }, "addToken": { "message": "トークンを追加" }, @@ -63,11 +66,14 @@ "message": "Coinbaseで購入" }, "buyCoinbaseExplainer": { - "message": "Coinbaseは、世界で最もポピュラーなBitcoin、Ethereum、そしてLitecoinの取引所です。" + "message": "Coinbaseは、世界的なBitcoin、Ethereum、そしてLitecoinの取引所です。" }, "cancel": { "message": "キャンセル" }, + "classicInterface": { + "message": "旧インタフェイスを使用" + }, "clickCopy": { "message": "クリックしてコピー" }, @@ -126,6 +132,9 @@ "message": "暗号通貨", "description": "Exchange type (cryptocurrencies)" }, + "currentConversion": { + "message": "基軸通貨" + }, "customGas": { "message": "ガスのカスタマイズ" }, @@ -135,14 +144,17 @@ "customRPC": { "message": "カスタムRPC" }, + "decimal": { + "message": "小数点桁数" + }, "defaultNetwork": { - "message": "Etherトランザクションのデフォルトのネットワークはメインネットです。" + "message": "デフォルトのEther送受信ネットワークはメインネットです。" }, "denExplainer": { "message": "DENとは、あなたのパスワードが暗号化されたMetaMask内のストレージです。" }, "deposit": { - "message": "デポジット" + "message": "受取り" }, "depositBTC": { "message": "あなたのBTCを次のアドレスへデポジット:" @@ -161,13 +173,13 @@ "message": "法定通貨でデポジット" }, "depositFromAccount": { - "message": "別のアカウントからデポジット" + "message": "別のアカウントから入金" }, "depositShapeShift": { - "message": "ShapeShiftでデポジット" + "message": "ShapeShiftで入金" }, "depositShapeShiftExplainer": { - "message": "あなたが他の暗号通貨を持っているなら、Etherにトレードしてダイレクトにメタマスクウォレットへのデポジットが可能です。アカウント作成は不要。" + "message": "他の暗号通貨をEtherと交換してMetaMaskのウォレットへ入金できます。アカウント作成は不要です。" }, "details": { "message": "詳細" @@ -176,10 +188,10 @@ "message": "ダイレクトデポジット" }, "directDepositEther": { - "message": "Etherをダイレクトデポジット" + "message": "Etherを直接受け取り" }, "directDepositEtherExplainer": { - "message": "あなたがEtherをすでにお持ちなら、ダイレクトデポジットは新しいウォレットにEtherを入手する最も迅速な方法です。" + "message": "Etherをすでにお持ちなら、MetaMaskの新しいウォレットにEtherを送信することができます。" }, "done": { "message": "完了" @@ -197,7 +209,7 @@ "message": "パスワードを入力" }, "etherscanView": { - "message": "Etherscanでアカウントを見る" + "message": "Etherscanでアカウントを参照" }, "exchangeRate": { "message": "交換レート" @@ -257,7 +269,7 @@ "message": "Etherをゲット" }, "getEtherFromFaucet": { - "message": "フォーセットで $1のEtherをゲット", + "message": "フォーセットで $1のEtherを得ることができます。", "description": "Displays network name for Ether faucet" }, "greaterThanMin": { @@ -281,12 +293,15 @@ "message": "どのようにEtherをデポジットしますか?" }, "import": { - "message": "インポート", + "message": "追加", "description": "Button to import an account from a selected file" }, "importAccount": { "message": "アカウントのインポート" }, + "importAccountMsg": { + "message":"追加したアカウントはMetaMaskのアカウントシードフレーズとは関連付けられません。インポートしたアカウントについての詳細は" + }, "importAnAccount": { "message": "アカウントをインポート" }, @@ -298,7 +313,10 @@ "description": "status showing that an account has been fully loaded into the keyring" }, "infoHelp": { - "message": "インフォメーションとヘルプ" + "message": "情報とヘルプ" + }, + "insufficientFunds": { + "message": "残高不足" }, "invalidAddress": { "message": "アドレスが無効です。" @@ -354,7 +372,7 @@ "message": "マイアカウント" }, "needEtherInWallet": { - "message": "MetaMaskを使って分散型アプリケーションと対話するためには、あなたのウォレットにEtherが必要になります。" + "message": "MetaMaskを使って分散型アプリケーションを使用するためには、このウォレットにEtherが必要です。" }, "needImportFile": { "message": "インポートするファイルを選択してください。", @@ -383,6 +401,9 @@ "newRecipient": { "message": "新規受取人" }, + "newRPC": { + "message": "新しいRPCのURLを追加" + }, "next": { "message": "次へ" }, @@ -460,12 +481,21 @@ "rejected": { "message": "拒否されました" }, + "resetAccount": { + "message": "アカウントをリセット" + }, + "restoreFromSeed": { + "message": "パスフレーズから復元する" + }, "required": { "message": "必要です。" }, "retryWithMoreGas": { "message": "より高いガスプライスで再度試して下さい。" }, + "revealSeedWords": { + "message": "パスフレーズを表示" + }, "revert": { "message": "元に戻す" }, @@ -495,8 +525,11 @@ "sendTokens": { "message": "トークンを送る" }, + "onlySendToEtherAddress": { + "message": "ETHはイーサリウムアカウントのみに送信できます。" + }, "sendTokensAnywhere": { - "message": "イーサリアムのアカウントを持っている人にトークンを送る" + "message": "イーサリアムアカウントを持っている人にトークンを送る" }, "settings": { "message": "設定" @@ -544,9 +577,21 @@ "message": "ShapeShiftで $1をETHにする", "description": "system will fill in deposit type in start of message" }, + "tokenAddress": { + "message": "トークンアドレス" + }, "tokenBalance": { "message": "あなたのトークン残高:" }, + "tokenSelection": { + "message": "トークンを検索、またはリストから選択してください。" + }, + "tokenSymbol": { + "message": "トークンシンボル" + }, + "tokenWarning1": { + "message": "MetaMaskのアカウントで取得したアカウントのみ追加できます。他のアカウントを使用して取得したトークンは、カスタムトークンを使用してください。" + }, "total": { "message": "合計" }, @@ -591,6 +636,9 @@ "usedByClients": { "message": "様々なクライアントによって使用されています。" }, + "useOldUI": { + "message": "旧UIに切り替え" + }, "viewAccount": { "message": "アカウントを見る" }, From be2254b880c8c7bc17a139c3137dbe1e11c6060d Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Mar 2018 10:37:45 -0230 Subject: [PATCH 041/246] Remove comments and console.logs --- app/scripts/lib/get-first-preferred-lang-code.js | 3 +-- ui/app/components/pending-tx/confirm-send-token.js | 2 +- ui/app/components/send/currency-display.js | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/scripts/lib/get-first-preferred-lang-code.js b/app/scripts/lib/get-first-preferred-lang-code.js index 74dfe246c..849018f26 100644 --- a/app/scripts/lib/get-first-preferred-lang-code.js +++ b/app/scripts/lib/get-first-preferred-lang-code.js @@ -9,9 +9,8 @@ async function getFirstPreferredLangCode () { const userPreferredLocaleCodes = await promisify( extension.i18n.getAcceptLanguages, { errorFirst: false } - )().catch(err => console.log('err123', err)) + )() const firstPreferredLangCode = userPreferredLocaleCodes.find(code => existingLocaleCodes.includes(code)) - // const firstPreferredLangCode = userPreferredLocaleCodes[0] return firstPreferredLangCode || 'en' } diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index 9196f9ab1..3e66705ae 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -21,7 +21,7 @@ const { } = require('../../token-util') const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') -// + const { getTokenExchangeRate, getSelectedAddress, diff --git a/ui/app/components/send/currency-display.js b/ui/app/components/send/currency-display.js index a0aaada4d..819fee0a0 100644 --- a/ui/app/components/send/currency-display.js +++ b/ui/app/components/send/currency-display.js @@ -10,7 +10,7 @@ inherits(CurrencyDisplay, Component) function CurrencyDisplay () { Component.call(this) } -// + function toHexWei (value) { return conversionUtil(value, { fromNumericBase: 'dec', From f74e802026538e81d7d224eb72353b85eb2ac149 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Mar 2018 10:52:19 -0230 Subject: [PATCH 042/246] Undo unnecessary line removals. --- app/scripts/background.js | 1 + app/scripts/metamask-controller.js | 1 + 2 files changed, 2 insertions(+) diff --git a/app/scripts/background.js b/app/scripts/background.js index 98de1d278..7782fc41e 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -94,6 +94,7 @@ function setupController (initState, initLangCode) { // // MetaMask Controller // + const controller = new MetamaskController({ // User confirmation callbacks: showUnconfirmedMessage: triggerUi, diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 6e82f6011..ff7b66572 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -57,6 +57,7 @@ module.exports = class MetamaskController extends EventEmitter { this.defaultMaxListeners = 20 this.sendUpdate = debounce(this.privateSendUpdate.bind(this), 200) + this.opts = opts const initState = opts.initState || {} this.recordFirstTimeInfo(initState) From 651e48dbd6a8bbcf2561d62c93897309143e2a9e Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 12:37:30 -0700 Subject: [PATCH 043/246] sentry - simplify all ethjs errors for better batching --- app/scripts/lib/extractEthjsErrorMessage.js | 27 +++++++++++++++++++++ app/scripts/lib/reportFailedTxToSentry.js | 26 ++------------------ app/scripts/lib/setupRaven.js | 7 +++++- 3 files changed, 35 insertions(+), 25 deletions(-) create mode 100644 app/scripts/lib/extractEthjsErrorMessage.js diff --git a/app/scripts/lib/extractEthjsErrorMessage.js b/app/scripts/lib/extractEthjsErrorMessage.js new file mode 100644 index 000000000..bac541735 --- /dev/null +++ b/app/scripts/lib/extractEthjsErrorMessage.js @@ -0,0 +1,27 @@ +const ethJsRpcSlug = 'Error: [ethjs-rpc] rpc error with payload ' +const errorLabelPrefix = 'Error: ' + +module.exports = extractEthjsErrorMessage + + +// +// ethjs-rpc provides overly verbose error messages +// if we detect this type of message, we extract the important part +// Below is an example input and output +// +// Error: [ethjs-rpc] rpc error with payload {"id":3947817945380,"jsonrpc":"2.0","params":["0xf8eb8208708477359400830398539406012c8cf97bead5deae237070f9587f8e7a266d80b8843d7d3f5a0000000000000000000000000000000000000000000000000000000000081d1a000000000000000000000000000000000000000000000000001ff973cafa800000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000003f48025a04c32a9b630e0d9e7ff361562d850c86b7a884908135956a7e4a336fa0300d19ca06830776423f25218e8d19b267161db526e66895567147015b1f3fc47aef9a3c7"],"method":"eth_sendRawTransaction"} Error: replacement transaction underpriced +// +// Transaction Failed: replacement transaction underpriced +// + + +function extractEthjsErrorMessage(errorMessage) { + const isEthjsRpcError = errorMessage.includes(ethJsRpcSlug) + if (isEthjsRpcError) { + const payloadAndError = errorMessage.slice(ethJsRpcSlug.length) + const originalError = payloadAndError.slice(payloadAndError.indexOf(errorLabelPrefix) + errorLabelPrefix.length) + return originalError + } else { + return errorMessage + } +} diff --git a/app/scripts/lib/reportFailedTxToSentry.js b/app/scripts/lib/reportFailedTxToSentry.js index ee73f6845..e09f4f1f8 100644 --- a/app/scripts/lib/reportFailedTxToSentry.js +++ b/app/scripts/lib/reportFailedTxToSentry.js @@ -1,5 +1,4 @@ -const ethJsRpcSlug = 'Error: [ethjs-rpc] rpc error with payload ' -const errorLabelPrefix = 'Error: ' +const extractEthjsErrorMessage = require('./extractEthjsErrorMessage') module.exports = reportFailedTxToSentry @@ -9,30 +8,9 @@ module.exports = reportFailedTxToSentry // function reportFailedTxToSentry({ raven, txMeta }) { - const errorMessage = extractErrorMessage(txMeta.err.message) + const errorMessage = 'Transaction Failed: ' + extractEthjsErrorMessage(txMeta.err.message) raven.captureMessage(errorMessage, { // "extra" key is required by Sentry extra: txMeta, }) } - -// -// ethjs-rpc provides overly verbose error messages -// if we detect this type of message, we extract the important part -// Below is an example input and output -// -// Error: [ethjs-rpc] rpc error with payload {"id":3947817945380,"jsonrpc":"2.0","params":["0xf8eb8208708477359400830398539406012c8cf97bead5deae237070f9587f8e7a266d80b8843d7d3f5a0000000000000000000000000000000000000000000000000000000000081d1a000000000000000000000000000000000000000000000000001ff973cafa800000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000003f48025a04c32a9b630e0d9e7ff361562d850c86b7a884908135956a7e4a336fa0300d19ca06830776423f25218e8d19b267161db526e66895567147015b1f3fc47aef9a3c7"],"method":"eth_sendRawTransaction"} Error: replacement transaction underpriced -// -// Transaction Failed: replacement transaction underpriced -// - -function extractErrorMessage(errorMessage) { - const isEthjsRpcError = errorMessage.includes(ethJsRpcSlug) - if (isEthjsRpcError) { - const payloadAndError = errorMessage.slice(ethJsRpcSlug.length) - const originalError = payloadAndError.slice(payloadAndError.indexOf(errorLabelPrefix) + errorLabelPrefix.length) - return `Transaction Failed: ${originalError}` - } else { - return `Transaction Failed: ${errorMessage}` - } -} diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js index 02c01b755..a869588d0 100644 --- a/app/scripts/lib/setupRaven.js +++ b/app/scripts/lib/setupRaven.js @@ -1,5 +1,6 @@ const Raven = require('raven-js') const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +const extractEthjsErrorMessage = require('./extractEthjsErrorMessage') const PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505' const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496' @@ -21,8 +22,12 @@ function setupRaven(opts) { const client = Raven.config(ravenTarget, { release, transport: function(opts) { - // modify report urls const report = opts.data + // simplify ethjs error messages + report.exception.values.forEach(item => { + item.value = extractEthjsErrorMessage(item.value) + }) + // modify report urls rewriteReportUrls(report) // make request normally client._makeRequest(opts) From 5a309328f1a1495034656f884e74ea6f1550d097 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 13:36:09 -0700 Subject: [PATCH 044/246] ci - run e2e jobs --- .circleci/config.yml | 17 +++++++++++++++++ package.json | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c14909783..8ebf569a5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,6 +12,9 @@ workflows: - test-lint: requires: - prep-deps-npm + - test-e2e: + requires: + - prep-deps-npm - test-unit: requires: - prep-deps-npm @@ -96,6 +99,20 @@ jobs: name: Test command: npm run lint + test-e2e: + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: dependency-cache-{{ checksum "package-lock.json" }} + - run: + name: Build + command: npm run dist + - run: + name: Test + command: npm run test:e2e + test-unit: docker: - image: circleci/node:8-browsers diff --git a/package.json b/package.json index 09e90ec59..0e5456b1f 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js", "test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara", "test:integration:build": "gulp build:scss", - "test:e2e": "METAMASK_ENV=test mocha test/e2e/metamask.spec --recursive || true", + "test:e2e": "METAMASK_ENV=test mocha test/e2e/metamask.spec --recursive", "test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload", "test:coveralls-upload": "if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi", "test:flat": "npm run test:flat:build && karma start test/flat.conf.js", From c2b5538ff3515fd8a9913e3f3424beba93e6ab91 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 13:54:32 -0700 Subject: [PATCH 045/246] deps - update package-lock --- package-lock.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/package-lock.json b/package-lock.json index 56f6c4305..d6ada40b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11229,6 +11229,12 @@ "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=", "dev": true }, + "es6-promise": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", + "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", + "dev": true + }, "readable-stream": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", From e0d98e73e3fc2cc909b21892da3ac7f5b6d1a05e Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 14:08:20 -0700 Subject: [PATCH 046/246] Revert "Revert "Ci - introduce a build job"" --- .circleci/config.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8ebf569a5..f812767ad 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,6 +6,9 @@ workflows: jobs: - prep-deps-npm - prep-deps-firefox + - build: + requires: + - prep-deps-npm - prep-scss: requires: - prep-deps-npm @@ -217,3 +220,17 @@ jobs: - run: name: test:integration:mascara command: npm run test:mascara + + build: + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: dependency-cache-{{ checksum "package-lock.json" }} + - run: + name: build:dist + command: npm run dist + - run: + name: build:debug + command: find dist/ -type f -exec md5sum {} \; | sort -k 2 From 62e1cbd33b440b8dcb98446b2fdee3f66ab5c1ad Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 14:16:58 -0700 Subject: [PATCH 047/246] ci - run e2e tests after build step --- .circleci/config.yml | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f812767ad..ed6dc7802 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ workflows: jobs: - prep-deps-npm - prep-deps-firefox - - build: + - prep-build: requires: - prep-deps-npm - prep-scss: @@ -17,6 +17,7 @@ workflows: - prep-deps-npm - test-e2e: requires: + - prep-build - prep-deps-npm - test-unit: requires: @@ -71,6 +72,23 @@ jobs: paths: - firefox + prep-build: + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: dependency-cache-{{ checksum "package-lock.json" }} + - run: + name: build:dist + command: npm run dist + - run: + name: build:debug + command: find dist/ -type f -exec md5sum {} \; | sort -k 2 + - save_cache: + key: build-cache-{{ .Revision }} + paths: + - dist prep-scss: docker: @@ -109,9 +127,8 @@ jobs: - checkout - restore_cache: key: dependency-cache-{{ checksum "package-lock.json" }} - - run: - name: Build - command: npm run dist + - restore_cache: + key: build-cache-{{ .Revision }} - run: name: Test command: npm run test:e2e @@ -220,17 +237,3 @@ jobs: - run: name: test:integration:mascara command: npm run test:mascara - - build: - docker: - - image: circleci/node:8-browsers - steps: - - checkout - - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} - - run: - name: build:dist - command: npm run dist - - run: - name: build:debug - command: find dist/ -type f -exec md5sum {} \; | sort -k 2 From 4ee48acf5672f00d59c49ec68452cd1dd57afa31 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 14:30:50 -0700 Subject: [PATCH 048/246] deps - update package-lock --- package-lock.json | 66 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d6ada40b0..015828549 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5352,6 +5352,11 @@ "json-rpc-error": "2.0.0", "promise-to-callback": "1.0.0" } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } }, @@ -5665,6 +5670,13 @@ "ethjs-util": "0.1.4", "pify": "2.3.0", "tape": "4.8.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } } }, "ethjs-format": { @@ -7053,6 +7065,13 @@ "pify": "2.3.0", "pinkie-promise": "2.0.1", "rimraf": "2.6.2" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } } } } @@ -8357,6 +8376,13 @@ "object-assign": "4.1.1", "pify": "2.3.0", "pinkie-promise": "2.0.1" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } } }, "globjoin": { @@ -11917,6 +11943,13 @@ "pify": "2.3.0", "pinkie-promise": "2.0.1", "strip-bom": "2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } } }, "loader-runner": { @@ -16461,6 +16494,13 @@ "graceful-fs": "4.1.11", "pify": "2.3.0", "pinkie-promise": "2.0.1" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } } }, "pathval": { @@ -16507,9 +16547,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, "ping-pong-stream": { "version": "1.0.0", @@ -19786,6 +19826,14 @@ "object-assign": "4.1.1", "pify": "2.3.0", "pinkie-promise": "2.0.1" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } } }, "has-flag": { @@ -20050,6 +20098,12 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", @@ -21654,6 +21708,12 @@ "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", "dev": true }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, "replace-ext": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", From 1dea4124f5e5b5eb37c234321808e9d414865f30 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 14:40:04 -0700 Subject: [PATCH 049/246] ci - end by flowing all required tests into a single job --- .circleci/config.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index ed6dc7802..dadbf4885 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -40,6 +40,15 @@ workflows: - prep-deps-npm - prep-deps-firefox - prep-scss + - all-tests-passed: + requires: + - test-lint + - test-unit + - test-e2e + - test-integration-mascara-chrome + - test-integration-mascara-firefox + - test-integration-flat-chrome + - test-integration-flat-firefox jobs: prep-deps-npm: @@ -237,3 +246,10 @@ jobs: - run: name: test:integration:mascara command: npm run test:mascara + +all-tests-pass: + docker: + - image: circleci/node:8-browsers + - run: + name: All Tests Passed + command: echo 'weew - everything passed!' From 3ec3b09c12618c40a0769605893626e059c64fc1 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 16:09:11 -0700 Subject: [PATCH 050/246] ci - end by flowing all required tests into a single job --- .circleci/config.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dadbf4885..a8e18116c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -40,7 +40,7 @@ workflows: - prep-deps-npm - prep-deps-firefox - prep-scss - - all-tests-passed: + - all-tests-pass: requires: - test-lint - test-unit @@ -247,9 +247,10 @@ jobs: name: test:integration:mascara command: npm run test:mascara -all-tests-pass: - docker: - - image: circleci/node:8-browsers - - run: - name: All Tests Passed - command: echo 'weew - everything passed!' + all-tests-pass: + docker: + - image: circleci/node:8-browsers + steps: + - run: + name: All Tests Passed + command: echo 'weew - everything passed!' From fe8472ab22fbff8d679943f0c65efd5d66c2a9c7 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 16:10:27 -0700 Subject: [PATCH 051/246] ci - end by flowing all required tests into a single job --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a8e18116c..75819fc6e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -252,5 +252,5 @@ jobs: - image: circleci/node:8-browsers steps: - run: - name: All Tests Passed - command: echo 'weew - everything passed!' + name: All Tests Passed + command: echo 'weew - everything passed!' From f0f45e6fe19fec01f7fff9df0e9e04015f82f3d2 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Mon, 26 Mar 2018 18:09:28 -0700 Subject: [PATCH 052/246] migration for removing unnecessary transactions from state --- app/scripts/migrations/023.js | 50 +++++++++++++++ app/scripts/migrations/index.js | 2 + test/unit/migrations/023-test.js | 99 ++++++++++++++++++++++++++++++ test/unit/tx-state-manager-test.js | 6 +- 4 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 app/scripts/migrations/023.js create mode 100644 test/unit/migrations/023-test.js diff --git a/app/scripts/migrations/023.js b/app/scripts/migrations/023.js new file mode 100644 index 000000000..bce0a5bea --- /dev/null +++ b/app/scripts/migrations/023.js @@ -0,0 +1,50 @@ + +const version = 23 + +/* + +This migration removes transactions that are no longer usefull down to 40 total + +*/ + +const clone = require('clone') + +module.exports = { + version, + + migrate: function (originalVersionedData) { + const versionedData = clone(originalVersionedData) + versionedData.meta.version = version + try { + const state = versionedData.data + const newState = transformState(state) + versionedData.data = newState + } catch (err) { + console.warn(`MetaMask Migration #${version}` + err.stack) + } + return Promise.resolve(versionedData) + }, +} + +function transformState (state) { + const newState = state + const transactions = newState.TransactionController.transactions + + if (transactions.length <= 40) return newState + + let reverseTxList = transactions.reverse() + let stripping = true + while (reverseTxList.length > 40 && stripping) { + let txIndex = reverseTxList.findIndex((txMeta) => { + return (txMeta.status === 'failed' || + txMeta.status === 'rejected' || + txMeta.status === 'confirmed' || + txMeta.status === 'dropped') + }) + if (txIndex < 0) stripping = false + else reverseTxList.splice(txIndex, 1) + } + + newState.TransactionController.transactions = reverseTxList.reverse() + return newState +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index a0cf5f4d4..811e06b6b 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -32,4 +32,6 @@ module.exports = [ require('./019'), require('./020'), require('./021'), + require('./022'), + require('./023'), ] diff --git a/test/unit/migrations/023-test.js b/test/unit/migrations/023-test.js new file mode 100644 index 000000000..be432d9fa --- /dev/null +++ b/test/unit/migrations/023-test.js @@ -0,0 +1,99 @@ +const assert = require('assert') +const migration23 = require('../../../app/scripts/migrations/023') +const properTime = (new Date()).getTime() +const storage = { + "meta": {}, + "data": { + "TransactionController": { + "transactions": [ + ] + }, + }, +} + +const transactions = [] +const transactions40 = [] +const transactions20 = [] + +const txStates = [ + 'unapproved', + 'approved', + 'signed', + 'submitted', + 'confirmed', + 'rejected', + 'failed', + 'dropped', +] + +const deletableTxStates = [ + 'confirmed', + 'rejected', + 'failed', + 'dropped', +] + +let nonDeletableCount = 0 + +let status +while (transactions.length <= 100) { + status = txStates[Math.floor(Math.random() * Math.floor(txStates.length - 1))] + if (!deletableTxStates.find((s) => s === status)) nonDeletableCount++ + transactions.push({status}) +} + +while (transactions40.length < 40) { + status = txStates[Math.floor(Math.random() * Math.floor(txStates.length - 1))] + transactions40.push({status}) +} + +while (transactions20.length < 20) { + status = txStates[Math.floor(Math.random() * Math.floor(txStates.length - 1))] + transactions20.push({status}) +} + + + +storage.data.TransactionController.transactions = transactions + +describe('storage is migrated successfully and the proper transactions are remove from state', () => { + it('should remove transactions that are unneeded', (done) => { + migration23.migrate(storage) + .then((migratedData) => { + let leftoverNonDeletableTxCount = 0 + const migratedTransactions = migratedData.data.TransactionController.transactions + migratedTransactions.forEach((tx) => { + if (!deletableTxStates.find((s) => s === tx.status)) { + leftoverNonDeletableTxCount++ + } + }) + assert.equal(leftoverNonDeletableTxCount, nonDeletableCount, 'migration shouldnt delete transactions we want to keep') + assert((migratedTransactions.length >= 40), `should be equal or greater to 40 if they are non deletable states got ${migratedTransactions.length} transactions`) + done() + }).catch(done) + }) + + it('should not remove any transactions because 40 is the expectable limit', (done) => { + storage.meta.version = 22 + storage.data.TransactionController.transactions = transactions40 + migration23.migrate(storage) + .then((migratedData) => { + const migratedTransactions = migratedData.data.TransactionController.transactions + + assert.equal(migratedTransactions.length, 40, 'migration shouldnt delete when at limit') + done() + }).catch(done) + }) + + it('should not remove any transactions because 20 txs is under the expectable limit', (done) => { + storage.meta.version = 22 + storage.data.TransactionController.transactions = transactions20 + migration23.migrate(storage) + .then((migratedData) => { + const migratedTransactions = migratedData.data.TransactionController.transactions + assert.equal(migratedTransactions.length, 20, 'migration shouldnt delete when under limit') + done() + }).catch(done) + }) + +}) diff --git a/test/unit/tx-state-manager-test.js b/test/unit/tx-state-manager-test.js index 220bf501f..a5ac13664 100644 --- a/test/unit/tx-state-manager-test.js +++ b/test/unit/tx-state-manager-test.js @@ -240,12 +240,12 @@ describe('TransactionStateManager', function () { }) describe('#wipeTransactions', function () { - + const specificAddress = '0xaa' const otherAddress = '0xbb' it('should remove only the transactions from a specific address', function () { - + const txMetas = [ { id: 0, status: 'unapproved', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: currentNetworkId }, { id: 1, status: 'confirmed', txParams: { from: otherAddress, to: specificAddress }, metamaskNetworkId: currentNetworkId }, @@ -268,7 +268,7 @@ describe('TransactionStateManager', function () { { id: 1, status: 'confirmed', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: otherNetworkId }, { id: 2, status: 'confirmed', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: otherNetworkId }, ] - + txMetas.forEach((txMeta) => txStateManager.addTx(txMeta, noop)) txStateManager.wipeTransactions(specificAddress) From 2053cac69129a436d20d1392e0361554d7b16959 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Mar 2018 21:35:12 -0230 Subject: [PATCH 053/246] Don't query for undefined. --- ui/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/index.js b/ui/index.js index fe57f791a..1e0e9f1cc 100644 --- a/ui/index.js +++ b/ui/index.js @@ -30,7 +30,9 @@ async function startApp (metamaskState, accountManager, opts) { // parse opts if (!metamaskState.featureFlags) metamaskState.featureFlags = {} - const currentLocaleMessages = await fetchLocale(metamaskState.currentLocale) + const currentLocaleMessages = metamaskState.currentLocale + ? await fetchLocale(metamaskState.currentLocale) + : {} const enLocaleMessages = await fetchLocale('en') const store = configureStore({ From 9e1bdcb09d811e125d8603b4cdaeb94ab04d0d9a Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 17:16:23 -0700 Subject: [PATCH 054/246] test - integration - add locale build step --- package.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c1ba6e761..f4900c77e 100644 --- a/package.json +++ b/package.json @@ -21,13 +21,15 @@ "test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload", "test:coveralls-upload": "if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi", "test:flat": "npm run test:flat:build && karma start test/flat.conf.js", - "test:flat:build": "npm run test:flat:build:ui && npm run test:flat:build:tests", + "test:flat:build": "npm run test:flat:build:ui && npm run test:flat:build:tests && npm run test:flat:build:locales", "test:flat:build:tests": "node test/integration/index.js", "test:flat:build:states": "node development/genStates.js", + "test:flat:build:locales": "mkdirp dist/chrome && cp -R app/_locales dist/chrome/_locales", "test:flat:build:ui": "npm run test:flat:build:states && browserify ./development/mock-dev.js -o ./development/bundle.js", "test:mascara": "npm run test:mascara:build && karma start test/mascara.conf.js", - "test:mascara:build": "mkdirp dist/mascara && npm run test:mascara:build:ui && npm run test:mascara:build:background && npm run test:mascara:build:tests", + "test:mascara:build": "mkdirp dist/mascara && npm run test:mascara:build:ui && npm run test:mascara:build:background && npm run test:mascara:build:tests && npm run test:mascara:build:locales", "test:mascara:build:ui": "browserify mascara/test/test-ui.js -o dist/mascara/ui.js", + "test:mascara:build:locales": "mkdirp dist/chrome && cp -R app/_locales dist/chrome/_locales", "test:mascara:build:background": "browserify mascara/src/background.js -o dist/mascara/background.js", "test:mascara:build:tests": "browserify test/integration/lib/first-time.js -o dist/mascara/tests.js", "sentry": "export RELEASE=`cat app/manifest.json| jq -r .version` && npm run sentry:release && npm run sentry:upload", From 9482af61576972c29b35eb9a542724005d8fd47a Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 17:52:26 -0700 Subject: [PATCH 055/246] i18n - add locales index json --- app/_locales/index.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 app/_locales/index.json diff --git a/app/_locales/index.json b/app/_locales/index.json new file mode 100644 index 000000000..4f3662fa4 --- /dev/null +++ b/app/_locales/index.json @@ -0,0 +1,19 @@ +[ + { "code": "de", "name": "German" }, + { "code": "en", "name": "English" }, + { "code": "es", "name": "Spanish" }, + { "code": "fr", "name": "French" }, + { "code": "hn", "name": "Hindi" }, + { "code": "it", "name": "Italian" }, + { "code": "ja", "name": "Japanese" }, + { "code": "ko", "name": "Korean" }, + { "code": "nl", "name": "Dutch" }, + { "code": "ph", "name": "Tagalog" }, + { "code": "pt", "name": "Portuguese" }, + { "code": "ru", "name": "Russian" }, + { "code": "sl", "name": "Slovenian" }, + { "code": "th", "name": "Thai" }, + { "code": "vi", "name": "Vietnamese" }, + { "code": "zh_CN", "name": "Mandarin" }, + { "code": "zh_TW", "name": "Taiwanese" }, +] From 5c521775f6426556664f114ecbc07e13b8272cb9 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 18:02:25 -0700 Subject: [PATCH 056/246] development - genStates - simplify locale importing --- development/genStates.js | 4 ++-- development/get-locale-messages.js | 12 ------------ 2 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 development/get-locale-messages.js diff --git a/development/genStates.js b/development/genStates.js index 1b21a42e5..0ac1059be 100644 --- a/development/genStates.js +++ b/development/genStates.js @@ -1,7 +1,8 @@ const fs = require('fs') const path = require('path') const promisify = require('pify') -const getLocaleMessages = require('./get-locale-messages') +const enLocaleMessages = require('../app/_locales/en/messages.json') + start().catch(console.error) @@ -14,7 +15,6 @@ async function start () { const stateFileContent = await promisify(fs.readFile)(stateFilePath, 'utf8') const state = JSON.parse(stateFileContent) - const enLocaleMessages = await getLocaleMessages() state.localeMessages = { en: enLocaleMessages, current: {} } const stateName = stateFileName.split('.')[0].replace(/-/g, ' ', 'g') diff --git a/development/get-locale-messages.js b/development/get-locale-messages.js deleted file mode 100644 index 3b76a851d..000000000 --- a/development/get-locale-messages.js +++ /dev/null @@ -1,12 +0,0 @@ -const fs = require('fs') -const path = require('path') -const promisify = require('pify') - -async function getLocaleMessages () { - const localeMessagesPath = path.join(process.cwd(), 'app', '_locales', 'en', 'messages.json') - const enLocaleMessagesJSON = await promisify(fs.readFile)(localeMessagesPath) - const enLocaleMessages = JSON.parse(enLocaleMessagesJSON) - return enLocaleMessages -} - -module.exports = getLocaleMessages From 165ae7d193ba2d5f29e0a6472bb26fa13efd1625 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 18:07:24 -0700 Subject: [PATCH 057/246] i18n - derrive locale codes from index --- app/scripts/lib/get-first-preferred-lang-code.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/scripts/lib/get-first-preferred-lang-code.js b/app/scripts/lib/get-first-preferred-lang-code.js index 849018f26..28612f763 100644 --- a/app/scripts/lib/get-first-preferred-lang-code.js +++ b/app/scripts/lib/get-first-preferred-lang-code.js @@ -1,9 +1,8 @@ -const fs = require('fs') -const path = require('path') const extension = require('extensionizer') const promisify = require('pify') +const allLocales = require('../../_locales/index.json') -const existingLocaleCodes = fs.readdirSync(path.join(__dirname, '..', '..', '_locales')) +const existingLocaleCodes = allLocales.map(locale => locale.code) async function getFirstPreferredLangCode () { const userPreferredLocaleCodes = await promisify( From 729a4732108ef387fc9d671cbd4b45789540d632 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 27 Mar 2018 18:07:51 -0700 Subject: [PATCH 058/246] Fix bug where resetAccount does not clear network cache Fixes #3439 --- CHANGELOG.md | 2 + app/scripts/metamask-controller.js | 73 ++++++++++++++++-------------- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa4493278..06cf51c14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Fix bug where the "Reset account" feature would not clear the network cache. + ## 4.4.0 Mon Mar 26 2018 - Internationalization: Taiwanese, Thai, Slovenian diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 18d71874a..31590d9ff 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -49,7 +49,7 @@ module.exports = class MetamaskController extends EventEmitter { /** * @constructor - * @param {Object} opts + * @param {Object} opts */ constructor (opts) { super() @@ -296,8 +296,8 @@ module.exports = class MetamaskController extends EventEmitter { /** * The metamask-state of the various controllers, made available to the UI - * - * @returns {Object} status + * + * @returns {Object} status */ getState () { const wallet = this.configManager.getWallet() @@ -335,8 +335,8 @@ module.exports = class MetamaskController extends EventEmitter { /** * Returns an api-object which is consumed by the UI - * - * @returns {Object} + * + * @returns {Object} */ getApi () { const keyringController = this.keyringController @@ -365,7 +365,7 @@ module.exports = class MetamaskController extends EventEmitter { placeSeedWords: this.placeSeedWords.bind(this), verifySeedPhrase: nodeify(this.verifySeedPhrase, this), clearSeedWordCache: this.clearSeedWordCache.bind(this), - resetAccount: this.resetAccount.bind(this), + resetAccount: nodeify(this.resetAccount, this), importAccountWithStrategy: this.importAccountWithStrategy.bind(this), // vault management @@ -426,14 +426,14 @@ module.exports = class MetamaskController extends EventEmitter { /** * Creates a new Vault(?) and create a new keychain(?) - * + * * A vault is ... - * + * * A keychain is ... - * + * * * @param {} password - * + * * @returns {} vault */ async createNewVaultAndKeychain (password) { @@ -479,9 +479,9 @@ module.exports = class MetamaskController extends EventEmitter { /** * Retrieves the first Identiy from the passed Vault and selects the related address - * + * * An Identity is ... - * + * * @param {} vault */ selectFirstIdentity (vault) { @@ -495,8 +495,8 @@ module.exports = class MetamaskController extends EventEmitter { // /** - * Adds a new account to ... - * + * Adds a new account to ... + * * @returns {} keyState */ async addNewAccount () { @@ -522,10 +522,10 @@ module.exports = class MetamaskController extends EventEmitter { /** * Adds the current vault's seed words to the UI's state tree. - * + * * Used when creating a first vault, to allow confirmation. * Also used when revealing the seed words in the confirmation view. - */ + */ placeSeedWords (cb) { this.verifySeedPhrase() @@ -540,7 +540,7 @@ module.exports = class MetamaskController extends EventEmitter { /** * Verifies the validity of the current vault's seed phrase. - * + * * Validity: seed phrase restores the accounts belonging to the current vault. * * Called when the first account is created and on unlocking the vault. @@ -571,27 +571,32 @@ module.exports = class MetamaskController extends EventEmitter { /** * Remove the primary account seed phrase from the UI's state tree. - * + * * The seed phrase remains available in the background process. - * + * */ clearSeedWordCache (cb) { this.configManager.setSeedWords(null) cb(null, this.preferencesController.getSelectedAddress()) } - + /** * ? */ - resetAccount (cb) { + async resetAccount (cb) { const selectedAddress = this.preferencesController.getSelectedAddress() this.txController.wipeTransactions(selectedAddress) - cb(null, selectedAddress) + + const networkController = this.networkController + const oldType = networkController.getProvoderConfig().type + await networkController.setProviderType(oldType, true) + + return selectedAddress } /** * Imports an account ... ? - * + * * @param {} strategy * @param {} args * @param {} cb @@ -634,9 +639,9 @@ module.exports = class MetamaskController extends EventEmitter { } // Prefixed Style Message Signing Methods: - + /** - * + * * @param {} msgParams * @param {} cb */ @@ -655,7 +660,7 @@ module.exports = class MetamaskController extends EventEmitter { } }) } - + /** * @param {} msgParams */ @@ -676,7 +681,7 @@ module.exports = class MetamaskController extends EventEmitter { return this.getState() }) } - + /** * @param {} msgParams */ @@ -697,13 +702,13 @@ module.exports = class MetamaskController extends EventEmitter { return this.getState() }) } - + // --------------------------------------------------------------------------- // Account Restauration /** * ? - * + * * @param {} migratorOutput */ restoreOldVaultAccounts (migratorOutput) { @@ -714,7 +719,7 @@ module.exports = class MetamaskController extends EventEmitter { /** * ? - * + * * @param {} migratorOutput */ restoreOldLostAccounts (migratorOutput) { @@ -728,9 +733,9 @@ module.exports = class MetamaskController extends EventEmitter { /** * Import (lost) Accounts - * + * * @param {Object} {lostAccounts} @Array accounts <{ address, privateKey }> - * + * * Uses the array's private keys to create a new Simple Key Pair keychain * and add it to the keyring controller. */ @@ -823,7 +828,7 @@ module.exports = class MetamaskController extends EventEmitter { if (cb && typeof cb === 'function') { cb(null, this.getState()) } - } + } cancelPersonalMessage (msgId, cb) { const messageManager = this.personalMessageManager @@ -978,7 +983,7 @@ module.exports = class MetamaskController extends EventEmitter { const percentileNum = percentile(50, lowestPrices) const percentileNumBn = new BN(percentileNum) return '0x' + percentileNumBn.mul(GWEI_BN).toString(16) - } + } //============================================================================= // CONFIG From 8e6ab7df052a5ca43b15edc9c308c626bb23e64c Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Mar 2018 22:38:04 -0230 Subject: [PATCH 059/246] Checking for sufficient balance in confirm ether screen; includes error messages for user. --- .../pending-tx/confirm-send-ether.js | 62 +++++++++++++++++-- ui/app/components/send/send-utils.js | 12 +++- ui/app/css/itcss/components/confirm.scss | 25 ++++++++ ui/app/send-v2.js | 13 +--- 4 files changed, 97 insertions(+), 15 deletions(-) diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index d1ce25cbf..14077b5e8 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -7,11 +7,16 @@ const clone = require('clone') const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const hexToBn = require('../../../../app/scripts/lib/hex-to-bn') +const classnames = require('classnames') const { conversionUtil, addCurrencies, multiplyCurrencies, } = require('../../conversion-util') +const { + getGasTotal, + isBalanceSufficient, +} = require('../send/send-utils') const GasFeeDisplay = require('../send/gas-fee-display-v2') const t = require('../../../i18n') const SenderToRecipient = require('../sender-to-recipient') @@ -30,12 +35,14 @@ function mapStateToProps (state) { } = state.metamask const accounts = state.metamask.accounts const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0] + const { balance } = accounts[selectedAddress] return { conversionRate, identities, selectedAddress, currentCurrency, send, + balance, } } @@ -86,6 +93,7 @@ function mapDispatchToProps (dispatch) { })) dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' })) }, + updateSendErrors: error => dispatch(actions.updateSendErrors(error)), } } @@ -218,7 +226,12 @@ ConfirmSendEther.prototype.render = function () { conversionRate, currentCurrency: convertedCurrency, showCustomizeGasModal, - send: { gasTotal, gasLimit: sendGasLimit, gasPrice: sendGasPrice }, + send: { + gasTotal, + gasLimit: sendGasLimit, + gasPrice: sendGasPrice, + errors, + }, } = this.props const txMeta = this.gatherTxMeta() const txParams = txMeta.txParams || {} @@ -326,7 +339,12 @@ ConfirmSendEther.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ - h('div.confirm-screen-section-column', [ + h('div', { + className: classnames({ + 'confirm-screen-section-column--with-error': errors['insufficientFunds'], + 'confirm-screen-section-column': !errors['insufficientFunds'], + }) + }, [ h('span.confirm-screen-label', [ t('total') + ' ' ]), h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), ]), @@ -335,6 +353,8 @@ ConfirmSendEther.prototype.render = function () { h('div.confirm-screen-row-info', `${totalInFIAT} ${currentCurrency.toUpperCase()}`), h('div.confirm-screen-row-detail', `${totalInETH} ETH`), ]), + + this.renderErrorMessage('insufficientFunds'), ]), ]), @@ -439,16 +459,28 @@ ConfirmSendEther.prototype.render = function () { ) } +ConfirmSendEther.prototype.renderErrorMessage = function (message) { + const { send: { errors } } = this.props + + return errors[message] + ? h('div.confirm-screen-error', [ errors[message] ]) + : null +} + ConfirmSendEther.prototype.onSubmit = function (event) { event.preventDefault() + const { updateSendErrors } = this.props const txMeta = this.gatherTxMeta() const valid = this.checkValidity() + const balanceIsSufficient = this.isBalanceSufficient(txMeta) this.setState({ valid, submitting: true }) - if (valid && this.verifyGasParams()) { + if (valid && this.verifyGasParams() && balanceIsSufficient) { this.props.sendTransaction(txMeta, event) + } else if (!balanceIsSufficient) { + updateSendErrors({ insufficientFunds: t('insufficientFunds') }) } else { - this.props.dispatch(actions.displayWarning(t('invalidGasParams'))) + updateSendErrors({ invalidGasParams: t('invalidGasParams') }) this.setState({ submitting: false }) } } @@ -460,6 +492,28 @@ ConfirmSendEther.prototype.cancel = function (event, txMeta) { cancelTransaction(txMeta) } +ConfirmSendEther.prototype.isBalanceSufficient = function (txMeta) { + const { + balance, + conversionRate, + } = this.props + const { + txParams: { + gas, + gasPrice, + value: amount, + }, + } = txMeta + const gasTotal = getGasTotal(gas, gasPrice) + + return isBalanceSufficient({ + amount, + gasTotal, + balance, + conversionRate, + }) +} + ConfirmSendEther.prototype.checkValidity = function () { const form = this.getFormEl() const valid = form.checkValidity() diff --git a/ui/app/components/send/send-utils.js b/ui/app/components/send/send-utils.js index d8211930d..71bfb2668 100644 --- a/ui/app/components/send/send-utils.js +++ b/ui/app/components/send/send-utils.js @@ -2,6 +2,7 @@ const { addCurrencies, conversionUtil, conversionGTE, + multiplyCurrencies, } = require('../../conversion-util') const { calcTokenAmount, @@ -31,7 +32,7 @@ function isBalanceSufficient ({ { value: totalAmount, fromNumericBase: 'hex', - conversionRate: amountConversionRate, + conversionRate: amountConversionRate || conversionRate, fromCurrency: primaryCurrency, }, ) @@ -62,7 +63,16 @@ function isTokenBalanceSufficient ({ return tokenBalanceIsSufficient } +function getGasTotal (gasLimit, gasPrice) { + return multiplyCurrencies(gasLimit, gasPrice, { + toNumericBase: 'hex', + multiplicandBase: 16, + multiplierBase: 16, + }) +} + module.exports = { + getGasTotal, isBalanceSufficient, isTokenBalanceSufficient, } diff --git a/ui/app/css/itcss/components/confirm.scss b/ui/app/css/itcss/components/confirm.scss index abe138f54..85ff14e6e 100644 --- a/ui/app/css/itcss/components/confirm.scss +++ b/ui/app/css/itcss/components/confirm.scss @@ -266,6 +266,7 @@ section .confirm-screen-account-number, .confirm-screen-total-box { background-color: $wild-sand; + position: relative; .confirm-screen-label { line-height: 21px; @@ -287,6 +288,30 @@ section .confirm-screen-account-number, } } +.confirm-screen-error { + font-size: 12px; + line-height: 12px; + color: #f00; + position: absolute; + right: 12px; + width: 80px; + text-align: right; +} + +.confirm-screen-row.confirm-screen-total-box { + .confirm-screen-section-column--with-error { + flex: 0.6; + } +} + +@media screen and (max-width: 379px) { + .confirm-screen-row.confirm-screen-total-box { + .confirm-screen-section-column--with-error { + flex: 0.4; + } + } +} + .confirm-screen-confirm-button { height: 50px; border-radius: 4px; diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index 620da73f8..497d0b147 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -27,6 +27,7 @@ const { const { isBalanceSufficient, isTokenBalanceSufficient, + getGasTotal, } = require('./components/send/send-utils') const { isValidAddress } = require('./util') @@ -128,7 +129,7 @@ SendTransactionScreen.prototype.updateGas = function () { estimateGas(estimateGasParams), ]) .then(([gasPrice, gas]) => { - const newGasTotal = this.getGasTotal(gas, gasPrice) + const newGasTotal = getGasTotal(gas, gasPrice) updateGasTotal(newGasTotal) this.setState({ gasLoadingError: false }) }) @@ -136,19 +137,11 @@ SendTransactionScreen.prototype.updateGas = function () { this.setState({ gasLoadingError: true }) }) } else { - const newGasTotal = this.getGasTotal(gasLimit, gasPrice) + const newGasTotal = getGasTotal(gasLimit, gasPrice) updateGasTotal(newGasTotal) } } -SendTransactionScreen.prototype.getGasTotal = function (gasLimit, gasPrice) { - return multiplyCurrencies(gasLimit, gasPrice, { - toNumericBase: 'hex', - multiplicandBase: 16, - multiplierBase: 16, - }) -} - SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) { const { from: { balance }, From e3881143cb010c47464bf9af01014fe5bb045621 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 18:10:13 -0700 Subject: [PATCH 060/246] ui - settings - derrive locales from index --- ui/app/settings.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/ui/app/settings.js b/ui/app/settings.js index 7443f2bd4..e855d6324 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -9,6 +9,7 @@ const { exportAsFile } = require('./util') const TabBar = require('./components/tab-bar') const SimpleDropdown = require('./components/dropdowns/simple-dropdown') const ToggleButton = require('react-toggle-button') +const locales = require('../../app/_locales/index.json') const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums const getInfuraCurrencyOptions = () => { @@ -25,13 +26,6 @@ const getInfuraCurrencyOptions = () => { }) } -const locales = [ - { name: 'English', code: 'en' }, - { name: 'Japanese', code: 'ja' }, - { name: 'French', code: 'fr' }, - { name: 'Spanish', code: 'es' }, -] - const getLocaleOptions = () => { return locales.map((locale) => { return { @@ -491,4 +485,3 @@ const mapDispatchToProps = dispatch => { } module.exports = connect(mapStateToProps, mapDispatchToProps)(Settings) - From 1a5eccdfc0610133a552fbcdc9353f66603af920 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 18:21:22 -0700 Subject: [PATCH 061/246] ui - settings - fix for currentLocale --- ui/app/settings.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/app/settings.js b/ui/app/settings.js index e855d6324..8764dcafe 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -107,11 +107,12 @@ class Settings extends Component { renderCurrentLocale () { const { updateCurrentLocale, currentLocale } = this.props + const currentLocaleMeta = locales.find(locale => locale.code === currentLocale) return h('div.settings__content-row', [ h('div.settings__content-item', [ h('span', 'Current Language'), - h('span.settings__content-description', `${currentLocale.name}`), + h('span.settings__content-description', `${currentLocaleMeta.name}`), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ @@ -452,7 +453,7 @@ Settings.propTypes = { goHome: PropTypes.func, isMascara: PropTypes.bool, updateCurrentLocale: PropTypes.func, - currentLocale: PropTypes.object, + currentLocale: PropTypes.string, t: PropTypes.func, } From ff26042b0c5456711210f5fd4e086e9f41bcb475 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 18:21:46 -0700 Subject: [PATCH 062/246] ui - actions - fix log for background call --- ui/app/actions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/actions.js b/ui/app/actions.js index 0c0b97a98..58240054d 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -1803,9 +1803,9 @@ function setUseBlockie (val) { function updateCurrentLocale (key) { return (dispatch) => { dispatch(actions.showLoadingIndication()) - log.debug(`background.updateCurrentLocale`) fetchLocale(key) .then((localeMessages) => { + log.debug(`background.setCurrentLocale`) background.setCurrentLocale(key, (err) => { dispatch(actions.hideLoadingIndication()) if (err) { From b4ec68b2d4b6713e0a203df88eb4a8982c2cf2c6 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 18:29:54 -0700 Subject: [PATCH 063/246] i18n - fix locales inde --- app/_locales/index.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/_locales/index.json b/app/_locales/index.json index 4f3662fa4..c085deb72 100644 --- a/app/_locales/index.json +++ b/app/_locales/index.json @@ -15,5 +15,5 @@ { "code": "th", "name": "Thai" }, { "code": "vi", "name": "Vietnamese" }, { "code": "zh_CN", "name": "Mandarin" }, - { "code": "zh_TW", "name": "Taiwanese" }, + { "code": "zh_TW", "name": "Taiwanese" } ] From d8357413aca53ea3aef45525f5c37daa0e354ba7 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 19:04:28 -0700 Subject: [PATCH 064/246] metamask-controller - fix typo --- app/scripts/metamask-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 31590d9ff..400e68d9e 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -588,7 +588,7 @@ module.exports = class MetamaskController extends EventEmitter { this.txController.wipeTransactions(selectedAddress) const networkController = this.networkController - const oldType = networkController.getProvoderConfig().type + const oldType = networkController.getProviderConfig().type await networkController.setProviderType(oldType, true) return selectedAddress From 74ac3bb2a7130675a10e1701d569b2c35a948f8f Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Mar 2018 23:23:57 -0230 Subject: [PATCH 065/246] Confirm send token detects if balance is sufficient for gas. --- .../pending-tx/confirm-send-ether.js | 4 +- .../pending-tx/confirm-send-token.js | 59 +++++++++++++++++-- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index 14077b5e8..b775e0ad0 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -16,7 +16,7 @@ const { const { getGasTotal, isBalanceSufficient, -} = require('../send/send-utils') +} = require('../send/send-utils') const GasFeeDisplay = require('../send/gas-fee-display-v2') const t = require('../../../i18n') const SenderToRecipient = require('../sender-to-recipient') @@ -343,7 +343,7 @@ ConfirmSendEther.prototype.render = function () { className: classnames({ 'confirm-screen-section-column--with-error': errors['insufficientFunds'], 'confirm-screen-section-column': !errors['insufficientFunds'], - }) + }), }, [ h('span.confirm-screen-label', [ t('total') + ' ' ]), h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index f9276e8a5..5cc2585f7 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -17,9 +17,14 @@ const { multiplyCurrencies, addCurrencies, } = require('../../conversion-util') +const { + getGasTotal, + isBalanceSufficient, +} = require('../send/send-utils') const { calcTokenAmount, } = require('../../token-util') +const classnames = require('classnames') const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') @@ -41,9 +46,10 @@ function mapStateToProps (state, ownProps) { identities, currentCurrency, } = state.metamask + const accounts = state.metamask.accounts const selectedAddress = getSelectedAddress(state) const tokenExchangeRate = getTokenExchangeRate(state, symbol) - + const { balance } = accounts[selectedAddress] return { conversionRate, identities, @@ -53,6 +59,7 @@ function mapStateToProps (state, ownProps) { currentCurrency: currentCurrency.toUpperCase(), send: state.metamask.send, tokenContract: getSelectedTokenContract(state), + balance, } } @@ -124,6 +131,7 @@ function mapDispatchToProps (dispatch, ownProps) { })) dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' })) }, + updateSendErrors: error => dispatch(actions.updateSendErrors(error)), } } @@ -301,7 +309,7 @@ ConfirmSendToken.prototype.renderGasFee = function () { } ConfirmSendToken.prototype.renderTotalPlusGas = function () { - const { token: { symbol }, currentCurrency } = this.props + const { token: { symbol }, currentCurrency, send: { errors } } = this.props const { fiat: fiatAmount, token: tokenAmount } = this.getAmount() const { fiat: fiatGas, token: tokenGas } = this.getGasFee() @@ -321,7 +329,12 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { ) : ( h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ - h('div.confirm-screen-section-column', [ + h('div', { + className: classnames({ + 'confirm-screen-section-column--with-error': errors['insufficientFunds'], + 'confirm-screen-section-column': !errors['insufficientFunds'], + }), + }, [ h('span.confirm-screen-label', [ t('total') + ' ' ]), h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), ]), @@ -330,10 +343,20 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { h('div.confirm-screen-row-info', `${tokenAmount} ${symbol}`), h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} ${t('gas')}`), ]), + + this.renderErrorMessage('insufficientFunds'), ]) ) } +ConfirmSendToken.prototype.renderErrorMessage = function (message) { + const { send: { errors } } = this.props + + return errors[message] + ? h('div.confirm-screen-error', [ errors[message] ]) + : null +} + ConfirmSendToken.prototype.render = function () { const { editTransaction } = this.props const txMeta = this.gatherTxMeta() @@ -448,18 +471,44 @@ ConfirmSendToken.prototype.render = function () { ConfirmSendToken.prototype.onSubmit = function (event) { event.preventDefault() + const { updateSendErrors } = this.props const txMeta = this.gatherTxMeta() const valid = this.checkValidity() + const balanceIsSufficient = this.isBalanceSufficient(txMeta) this.setState({ valid, submitting: true }) - if (valid && this.verifyGasParams()) { + if (valid && this.verifyGasParams() && balanceIsSufficient) { this.props.sendTransaction(txMeta, event) + } else if (!balanceIsSufficient) { + updateSendErrors({ insufficientFunds: t('insufficientFunds') }) } else { - this.props.dispatch(actions.displayWarning(t('invalidGasParams'))) + updateSendErrors({ invalidGasParams: t('invalidGasParams') }) this.setState({ submitting: false }) } } +ConfirmSendToken.prototype.isBalanceSufficient = function (txMeta) { + const { + balance, + conversionRate, + } = this.props + const { + txParams: { + gas, + gasPrice, + }, + } = txMeta + const gasTotal = getGasTotal(gas, gasPrice) + + return isBalanceSufficient({ + amount: '0', + gasTotal, + balance, + conversionRate, + }) +} + + ConfirmSendToken.prototype.cancel = function (event, txMeta) { event.preventDefault() const { cancelTransaction } = this.props From 8421cf1954fb017dc5311368cc3ee335b34ca446 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 19:59:45 -0700 Subject: [PATCH 066/246] i18n - fix casing for key 'downloadStateLogs' --- app/_locales/de/messages.json | 2 +- app/_locales/es/messages.json | 2 +- app/_locales/hn/messages.json | 2 +- app/_locales/nl/messages.json | 2 +- app/_locales/ru/messages.json | 2 +- app/_locales/sl/messages.json | 2 +- app/_locales/th/messages.json | 2 +- app/_locales/zh_TW/messages.json | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 0bdce516c..822991512 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -217,7 +217,7 @@ "done": { "message": "Fertig" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Statelogs herunterladen" }, "dropped": { diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index fa28b09da..f287674f1 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -247,7 +247,7 @@ "done": { "message": "Completo" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Descargar logs de estado" }, "dropped": { diff --git a/app/_locales/hn/messages.json b/app/_locales/hn/messages.json index 3703faa13..323f4b4b3 100644 --- a/app/_locales/hn/messages.json +++ b/app/_locales/hn/messages.json @@ -223,7 +223,7 @@ "done": { "message": "संपन्न" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "राज्य लॉग डाउनलोड करें" }, "edit": { diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json index aacb81fee..c2f955123 100644 --- a/app/_locales/nl/messages.json +++ b/app/_locales/nl/messages.json @@ -223,7 +223,7 @@ "done": { "message": "Gedaan" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Staatslogboeken downloaden" }, "edit": { diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index e3a1935f5..01debddc2 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -223,7 +223,7 @@ "done": { "message": "Готово" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Загрузить логи статус" }, "edit": { diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index 0532f11b2..b089f3476 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -223,7 +223,7 @@ "done": { "message": "Končano" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Prenesi state dnevnike" }, "edit": { diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json index 887714f3f..3d7dec226 100644 --- a/app/_locales/th/messages.json +++ b/app/_locales/th/messages.json @@ -223,7 +223,7 @@ "done": { "message": "เสร็จสิ้น" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "ดาวน์โหลดล็อกสถานะ" }, "edit": { diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index e39793430..9aaee0e16 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -235,7 +235,7 @@ "done": { "message": "完成" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "下載狀態紀錄" }, "dropped": { From 3e7d7205b8b841f619a77da6c2d28da88fef66a7 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 20:09:15 -0700 Subject: [PATCH 067/246] i18n - cleanup verify locales util --- development/verify-locale-strings.js | 146 +++++++++++++++------------ 1 file changed, 80 insertions(+), 66 deletions(-) diff --git a/development/verify-locale-strings.js b/development/verify-locale-strings.js index b8fe5a7dc..c0214d672 100644 --- a/development/verify-locale-strings.js +++ b/development/verify-locale-strings.js @@ -10,87 +10,101 @@ // //////////////////////////////////////////////////////////////////////////////// -var fs = require('fs') -var path = require('path') +const fs = require('fs') +const path = require('path') +const locales = require('../app/_locales/index.json') console.log('Locale Verification') -var locale = process.argv[2] -if (!locale || locale == '') { - console.log('Must enter a locale as argument. exitting') - process.exit(1) +const specifiedLocale = process.argv[2] +if (specifiedLocale) { + console.log(`Verifying selected locale "${specifiedLocale}":\n\n`) + const locale = locales.find(locale => locale.code === specifiedLocale) + verifyLocale({ locale }) +} else { + console.log('Verifying all locales:\n\n') + locales.forEach(locale => { + verifyLocale({ locale }) + console.log('\n') + }) } -console.log("verifying for locale " + locale) -localeFilePath = path.join(process.cwd(), 'app', '_locales', locale, 'messages.json') -try { - localeObj = JSON.parse(fs.readFileSync(localeFilePath, 'utf8')); -} catch (e) { - if(e.code == 'ENOENT') { - console.log('Locale file not found') - } else { - console.log('Error opening your locale file: ', e) + +function verifyLocale({ locale }) { + const localeCode = locale.code + const localeName = locale.name + console.log(`Status of "${localeName}" (${localeCode})`) + + try { + const localeFilePath = path.join(process.cwd(), 'app', '_locales', localeCode, 'messages.json') + localeObj = JSON.parse(fs.readFileSync(localeFilePath, 'utf8')); + } catch (e) { + if (e.code == 'ENOENT') { + console.log('Locale file not found') + } else { + console.log(`Error opening your locale ("${localeCode}") file: `, e) + } + process.exit(1) } - process.exit(1) -} -englishFilePath = path.join(process.cwd(), 'app', '_locales', 'en', 'messages.json') -try { - englishObj = JSON.parse(fs.readFileSync(englishFilePath, 'utf8')); -} catch (e) { - if(e.code == 'ENOENT') { - console.log("English File not found") - } else { - console.log("Error opening english locale file: ", e) + try { + const englishFilePath = path.join(process.cwd(), 'app', '_locales', 'en', 'messages.json') + englishObj = JSON.parse(fs.readFileSync(englishFilePath, 'utf8')); + } catch (e) { + if(e.code == 'ENOENT') { + console.log('English File not found') + } else { + console.log('Error opening english locale file: ', e) + } + process.exit(1) } - process.exit(1) -} -console.log('\tverifying whether all your locale strings are contained in the english one') + // console.log(' verifying whether all your locale ("${localeCode}") strings are contained in the english one') + + var counter = 0 + var foundErrorA = false + var notFound = []; + Object.keys(localeObj).forEach(function(key){ + if (!englishObj[key]) { + foundErrorA = true + notFound.push(key) + } + counter++ + }) -var counter = 0 -var foundErrorA = false -var notFound = []; -Object.keys(localeObj).forEach(function(key){ - if (!englishObj[key]) { - foundErrorA = true - notFound.push(key) + if (foundErrorA) { + console.log('\nMissing from english locale:') + notFound.forEach(function(key) { + console.log(` - [ ] ${key}`) + }) + } else { + // console.log(` all ${counter} strings declared in your locale ("${localeCode}") were found in the english one`) } - counter++ -}) -if (foundErrorA) { - console.log('\nThe following string(s) is(are) not found in the english locale:') - notFound.forEach(function(key) { - console.log(key) - }) -} else { - console.log('\tall ' + counter +' strings declared in your locale were found in the english one') -} + // console.log('\n verifying whether your locale ("${localeCode}") contains all english strings') -console.log('\n\tverifying whether your locale contains all english strings') + var counter = 0 + var foundErrorB = false + var notFound = []; + Object.keys(englishObj).forEach(function(key){ + if (!localeObj[key]) { + foundErrorB = true + notFound.push(key) + } + counter++ + }) -var counter = 0 -var foundErrorB = false -var notFound = []; -Object.keys(englishObj).forEach(function(key){ - if (!localeObj[key]) { - foundErrorB = true - notFound.push(key) + if (foundErrorB) { + console.log(`\nMissing from "${localeCode}":`) + notFound.forEach(function(key) { + console.log(` - [ ] ${key}`) + }) + } else { + // console.log(` all ${counter} english strings were found in your locale ("${localeCode}")!`) } - counter++ -}) -if (foundErrorB) { - console.log('\nThe following string(s) is(are) not found in the your locale:') - notFound.forEach(function(key) { - console.log(key) - }) -} else { - console.log('\tall ' + counter +' english strings were found in your locale!') + if (!foundErrorA && !foundErrorB) { + console.log('You are good to go') + } } - -if (!foundErrorA && !foundErrorB) { - console.log('You are good to go') -} \ No newline at end of file From 812a06ffcd9cea39453e8a59563bf1d12e17c065 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 20:29:29 -0700 Subject: [PATCH 068/246] i18n - further improve locale verifier --- development/verify-locale-strings.js | 69 +++++++++++----------------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/development/verify-locale-strings.js b/development/verify-locale-strings.js index c0214d672..8dc0a30f1 100644 --- a/development/verify-locale-strings.js +++ b/development/verify-locale-strings.js @@ -12,33 +12,32 @@ const fs = require('fs') const path = require('path') -const locales = require('../app/_locales/index.json') +const localeIndex = require('../app/_locales/index.json') console.log('Locale Verification') const specifiedLocale = process.argv[2] if (specifiedLocale) { console.log(`Verifying selected locale "${specifiedLocale}":\n\n`) - const locale = locales.find(locale => locale.code === specifiedLocale) - verifyLocale({ locale }) + const locale = localeIndex.find(localeMeta => localeMeta.code === specifiedLocale) + verifyLocale({ localeMeta }) } else { console.log('Verifying all locales:\n\n') - locales.forEach(locale => { - verifyLocale({ locale }) + localeIndex.forEach(localeMeta => { + verifyLocale({ localeMeta }) console.log('\n') }) } -function verifyLocale({ locale }) { - const localeCode = locale.code - const localeName = locale.name - console.log(`Status of "${localeName}" (${localeCode})`) +function verifyLocale({ localeMeta }) { + const localeCode = localeMeta.code + const localeName = localeMeta.name try { const localeFilePath = path.join(process.cwd(), 'app', '_locales', localeCode, 'messages.json') - localeObj = JSON.parse(fs.readFileSync(localeFilePath, 'utf8')); + targetLocale = JSON.parse(fs.readFileSync(localeFilePath, 'utf8')); } catch (e) { if (e.code == 'ENOENT') { console.log('Locale file not found') @@ -50,7 +49,7 @@ function verifyLocale({ locale }) { try { const englishFilePath = path.join(process.cwd(), 'app', '_locales', 'en', 'messages.json') - englishObj = JSON.parse(fs.readFileSync(englishFilePath, 'utf8')); + englishLocale = JSON.parse(fs.readFileSync(englishFilePath, 'utf8')); } catch (e) { if(e.code == 'ENOENT') { console.log('English File not found') @@ -61,50 +60,38 @@ function verifyLocale({ locale }) { } // console.log(' verifying whether all your locale ("${localeCode}") strings are contained in the english one') + const extraItems = compareLocalesForMissingItems({ base: targetLocale, subject: englishLocale }) + // console.log('\n verifying whether your locale ("${localeCode}") contains all english strings') + const missingItems = compareLocalesForMissingItems({ base: englishLocale, subject: targetLocale }) - var counter = 0 - var foundErrorA = false - var notFound = []; - Object.keys(localeObj).forEach(function(key){ - if (!englishObj[key]) { - foundErrorA = true - notFound.push(key) - } - counter++ - }) + const englishEntryCount = Object.keys(englishLocale).length + const coveragePercent = 100 * (englishEntryCount - missingItems.length) / englishEntryCount - if (foundErrorA) { + console.log(`Status of **${localeName} (${localeCode})** ${coveragePercent.toFixed(2)}% coverage:`) + + if (extraItems.length) { console.log('\nMissing from english locale:') - notFound.forEach(function(key) { + extraItems.forEach(function(key) { console.log(` - [ ] ${key}`) }) } else { // console.log(` all ${counter} strings declared in your locale ("${localeCode}") were found in the english one`) } - // console.log('\n verifying whether your locale ("${localeCode}") contains all english strings') - - var counter = 0 - var foundErrorB = false - var notFound = []; - Object.keys(englishObj).forEach(function(key){ - if (!localeObj[key]) { - foundErrorB = true - notFound.push(key) - } - counter++ - }) - - if (foundErrorB) { - console.log(`\nMissing from "${localeCode}":`) - notFound.forEach(function(key) { + if (missingItems.length) { + console.log(`\nMissing:`) + missingItems.forEach(function(key) { console.log(` - [ ] ${key}`) }) } else { // console.log(` all ${counter} english strings were found in your locale ("${localeCode}")!`) } - if (!foundErrorA && !foundErrorB) { - console.log('You are good to go') + if (!extraItems.length && !missingItems.length) { + console.log('Full coverage : )') } } + +function compareLocalesForMissingItems({ base, subject }) { + return Object.keys(base).filter((key) => !subject[key]) +} From 97e1fcd331e9f71cfd7e2958b2b92d1914a89b07 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 20:41:10 -0700 Subject: [PATCH 069/246] sentry - simplify error message 'Transaction Failed: known transaction' --- app/scripts/lib/setupRaven.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js index a869588d0..b93591e65 100644 --- a/app/scripts/lib/setupRaven.js +++ b/app/scripts/lib/setupRaven.js @@ -23,10 +23,20 @@ function setupRaven(opts) { release, transport: function(opts) { const report = opts.data - // simplify ethjs error messages + // simplify certain complex error messages report.exception.values.forEach(item => { - item.value = extractEthjsErrorMessage(item.value) + let errorMessage = item.value + // simplify ethjs error messages + errorMessage = extractEthjsErrorMessage(errorMessage) + // simplify 'Transaction Failed: known transaction' + if (errorMessage.indexOf('Transaction Failed: known transaction') === 0) { + // cut the hash from the error message + errorMessage = 'Transaction Failed: known transaction' + } + // finalize + item.value = errorMessage }) + // modify report urls rewriteReportUrls(report) // make request normally From 21fbaed97c84e75968cff1810999d0ec1aa5ef26 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 27 Mar 2018 23:55:18 -0700 Subject: [PATCH 070/246] tx controller - explode on non-hex txParams + dont add chainId to txParams + sign with chainId as number --- app/scripts/controllers/transactions.js | 10 ++++++---- app/scripts/lib/tx-state-manager.js | 16 +++++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 3e3909361..7e2cc15da 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -250,7 +250,7 @@ module.exports = class TransactionController extends EventEmitter { // wait for a nonce nonceLock = await this.nonceTracker.getNonceLock(fromAddress) // add nonce to txParams - // if txMeta has lastGasPrice then it is a retry at same nonce with higher + // if txMeta has lastGasPrice then it is a retry at same nonce with higher // gas price transaction and their for the nonce should not be calculated const nonce = txMeta.lastGasPrice ? txMeta.txParams.nonce : nonceLock.nextNonce txMeta.txParams.nonce = ethUtil.addHexPrefix(nonce.toString(16)) @@ -273,12 +273,14 @@ module.exports = class TransactionController extends EventEmitter { async signTransaction (txId) { const txMeta = this.txStateManager.getTx(txId) - const txParams = txMeta.txParams - const fromAddress = txParams.from // add network/chain id - txParams.chainId = ethUtil.addHexPrefix(this.getChainId().toString(16)) + const chainId = this.getChainId() + const txParams = Object.assign({}, txMeta.txParams, { chainId }) + // sign tx + const fromAddress = txParams.from const ethTx = new Transaction(txParams) await this.signEthTx(ethTx, fromAddress) + // set state to signed this.txStateManager.setTxStatusSigned(txMeta.id) const rawTx = ethUtil.bufferToHex(ethTx.serialize()) return rawTx diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js index ab344ae9b..23c915a61 100644 --- a/app/scripts/lib/tx-state-manager.js +++ b/app/scripts/lib/tx-state-manager.js @@ -106,12 +106,9 @@ module.exports = class TransactionStateManager extends EventEmitter { } updateTx (txMeta, note) { + // validate txParams if (txMeta.txParams) { - Object.keys(txMeta.txParams).forEach((key) => { - const value = txMeta.txParams[key] - if (typeof value !== 'string') console.error(`${key}: ${value} in txParams is not a string`) - if (!ethUtil.isHexPrefixed(value)) console.error('is not hex prefixed, anything on txParams must be hex prefixed') - }) + this.validateTxParams(txMeta.txParams) } // create txMeta snapshot for history @@ -139,6 +136,15 @@ module.exports = class TransactionStateManager extends EventEmitter { this.updateTx(txMeta, `txStateManager#updateTxParams`) } + // validates txParams members by type + validateTxParams(txParams) { + Object.keys(txParams).forEach((key) => { + const value = txParams[key] + if (typeof value !== 'string') throw new Error(`${key}: ${value} in txParams is not a string`) + if (!ethUtil.isHexPrefixed(value)) throw new Error('is not hex prefixed, everything on txParams must be hex prefixed') + }) + } + /* Takes an object of fields to search for eg: let thingsToLookFor = { From 21b6a3442d8cae8c95a3d7e0b9e216d91bc8bd19 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 28 Mar 2018 10:51:16 -0230 Subject: [PATCH 071/246] Fix display of unapprovedMessages in txList (old and new ui); includes fix of undefined txParams. --- .../app/components/transaction-list-item.js | 5 +++++ ui/app/components/tx-list-item.js | 20 ++++++++++++------- ui/app/components/tx-list.js | 5 +++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/old-ui/app/components/transaction-list-item.js b/old-ui/app/components/transaction-list-item.js index 7ab3414e5..f7d59005a 100644 --- a/old-ui/app/components/transaction-list-item.js +++ b/old-ui/app/components/transaction-list-item.js @@ -31,6 +31,11 @@ function TransactionListItem () { TransactionListItem.prototype.showRetryButton = function () { const { transaction = {}, transactions } = this.props const { status, submittedTime, txParams } = transaction + + if (!txParams) { + return false + } + const currentNonce = txParams.nonce const currentNonceTxs = transactions.filter(tx => tx.txParams.nonce === currentNonce) const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted') diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index 5e88d38d3..a411edd89 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -62,20 +62,23 @@ TxListItem.prototype.getAddressText = function () { const { address, txParams = {}, + isMsg, } = this.props const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data) const { name: txDataName, params = [] } = decodedData || {} const { value } = params[0] || {} - switch (txDataName) { - case 'transfer': - return `${value.slice(0, 10)}...${value.slice(-4)}` - default: - return address - ? `${address.slice(0, 10)}...${address.slice(-4)}` - : this.props.t('contractDeployment') + let addressText + if (txDataName === 'transfer' || address) { + addressText = `${value.slice(0, 10)}...${value.slice(-4)}` + } else if (isMsg) { + addressText = this.props.t('sigRequest') + } else { + addressText = this.props.t('contractDeployment') } + + return addressText } TxListItem.prototype.getSendEtherTotal = function () { @@ -185,6 +188,9 @@ TxListItem.prototype.showRetryButton = function () { transactionId, txParams, } = this.props + if (!txParams) { + return false + } const currentNonce = txParams.nonce const currentNonceTxs = selectedAddressTxList.filter(tx => tx.txParams.nonce === currentNonce) const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted') diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js index 5f09d887e..b8619fbf1 100644 --- a/ui/app/components/tx-list.js +++ b/ui/app/components/tx-list.js @@ -71,9 +71,9 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa const props = { dateString: formatDate(transaction.time), - address: transaction.txParams.to, + address: transaction.txParams && transaction.txParams.to, transactionStatus: transaction.status, - transactionAmount: transaction.txParams.value, + transactionAmount: transaction.txParams && transaction.txParams.value, transactionId: transaction.id, transactionHash: transaction.hash, transactionNetworkId: transaction.metamaskNetworkId, @@ -95,6 +95,7 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa const opts = { key: transactionId || transactionHash, txParams: transaction.txParams, + isMsg: Boolean(transaction.msgParams), transactionStatus, transactionId, dateString, From d6ebf5d94e374adbd2c2a66e8e5fb7f35fe5b6b2 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 27 Mar 2018 23:23:57 -0230 Subject: [PATCH 072/246] Confirm send token detects if balance is sufficient for gas. --- ui/app/components/customize-gas-modal/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index 8234f8d19..3f5e2064d 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -64,6 +64,7 @@ function mapDispatchToProps (dispatch) { updateGasLimit: newGasLimit => dispatch(actions.updateGasLimit(newGasLimit)), updateGasTotal: newGasTotal => dispatch(actions.updateGasTotal(newGasTotal)), updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)), + updateSendErrors: error => dispatch(actions.updateSendErrors(error)), } } @@ -106,6 +107,7 @@ CustomizeGasModal.prototype.save = function (gasPrice, gasLimit, gasTotal) { selectedToken, balance, updateSendAmount, + updateSendErrors, } = this.props if (maxModeOn && !selectedToken) { @@ -120,6 +122,7 @@ CustomizeGasModal.prototype.save = function (gasPrice, gasLimit, gasTotal) { updateGasPrice(ethUtil.addHexPrefix(gasPrice)) updateGasLimit(ethUtil.addHexPrefix(gasLimit)) updateGasTotal(ethUtil.addHexPrefix(gasTotal)) + updateSendErrors({ insufficientFunds: false }) hideModal() } From f2927121d44150ee2fd155136e12093f842e9b3a Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 09:38:38 -0700 Subject: [PATCH 073/246] deps - update package-lock (maybe greenkeeper forgot?) --- package-lock.json | 57 ++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 015828549..5e702a53f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -224,6 +224,15 @@ } } }, + "@sinonjs/formatio": { + "version": "2.0.0", + "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", + "dev": true, + "requires": { + "samsam": "1.3.0" + } + }, "@types/node": { "version": "8.5.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.5.tgz", @@ -5202,12 +5211,20 @@ "dev": true }, "eslint-plugin-mocha": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-4.11.0.tgz", - "integrity": "sha1-kRk6L1XiCl41l0BUoAidMBmO5Xg=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-5.0.0.tgz", + "integrity": "sha512-mpRWWsjxRco2bY4qE5DL8SmGoVF0Onb6DZrbgOjFoNo1YNN299K2voIozd8Kce3qC/neWNr2XF27E1ZDMl1yZg==", "dev": true, "requires": { - "ramda": "0.24.1" + "ramda": "0.25.0" + }, + "dependencies": { + "ramda": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz", + "integrity": "sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==", + "dev": true + } } }, "eslint-plugin-react": { @@ -12459,9 +12476,9 @@ "integrity": "sha1-rgyqVhERSYxboTcj1vtjHSQAOTQ=" }, "lolex": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.1.tgz", - "integrity": "sha512-mQuW55GhduF3ppo+ZRUTz1PRjEh1hS5BbqU7d8D0ez2OKxHDod7StPPeAVKisZR5aLkHZjdGWSL42LSONUJsZw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz", + "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==", "dev": true }, "longest": { @@ -13646,14 +13663,14 @@ "dev": true }, "nise": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.2.0.tgz", - "integrity": "sha512-q9jXh3UNsMV28KeqI43ILz5+c3l+RiNW8mhurEwCKckuHQbL+hTJIKKTiUlCPKlgQ/OukFvSnKB/Jk3+sFbkGA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.3.2.tgz", + "integrity": "sha512-KPKb+wvETBiwb4eTwtR/OsA2+iijXP+VnlSFYJo3EHjm2yjek1NWxHOUQat3i7xNLm1Bm18UA5j5Wor0yO2GtA==", "dev": true, "requires": { - "formatio": "1.2.0", + "@sinonjs/formatio": "2.0.0", "just-extend": "1.1.27", - "lolex": "1.6.0", + "lolex": "2.3.2", "path-to-regexp": "1.7.0", "text-encoding": "0.6.4" }, @@ -13664,12 +13681,6 @@ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, - "lolex": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", - "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", - "dev": true - }, "path-to-regexp": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", @@ -18695,16 +18706,16 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "sinon": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.1.3.tgz", - "integrity": "sha512-c7u0ZuvBRX1eXuB4jN3BRCAOGiUTlM8SE3TxbJHrNiHUKL7wonujMOB6Fi1gQc00U91IscFORQHDga/eccqpbw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-5.0.0.tgz", + "integrity": "sha512-dMX7ZB2E1iQ5DOEOePoNJQp03uyhdMfb+kLXlNPbquv2FwfezD+0GbbHSgCw4MFhpSSS9NMoYJfOPMjCMJtXWA==", "dev": true, "requires": { "diff": "3.3.1", "formatio": "1.2.0", "lodash.get": "4.4.2", - "lolex": "2.3.1", - "nise": "1.2.0", + "lolex": "2.3.2", + "nise": "1.3.2", "supports-color": "4.5.0", "type-detect": "4.0.5" }, From c171ea0632c2f4685b563ef4ef655cfee81a5c2d Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 09:40:11 -0700 Subject: [PATCH 074/246] deps - bump ethjs-query to fix unhandled promise rejections --- package-lock.json | 29 +++++++++++++++++------------ package.json | 4 ++-- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5e702a53f..f0f76919a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6107,12 +6107,12 @@ } }, "ethjs-query": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.3.2.tgz", - "integrity": "sha1-9IikjOGZTNTHfsy3tSkCxvKc/YU=", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.3.4.tgz", + "integrity": "sha512-RkeLtBwuXJkBIf/U+Az0GOT203UiBLmN7WA6WZIwSTbmhH2yNicggwaWKvN3TOtpErOsXnzYTZp82mElHdORUQ==", "requires": { - "ethjs-format": "0.2.4", - "ethjs-rpc": "0.1.8" + "ethjs-format": "0.2.5", + "ethjs-rpc": "0.1.9" }, "dependencies": { "bn.js": { @@ -6121,12 +6121,12 @@ "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" }, "ethjs-format": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/ethjs-format/-/ethjs-format-0.2.4.tgz", - "integrity": "sha1-W7vESlrSTmirOTMS/5A5pztlv4E=", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/ethjs-format/-/ethjs-format-0.2.5.tgz", + "integrity": "sha1-RPMKvuF7B01xYtLIhqv/0GWCiSU=", "requires": { "bn.js": "4.11.6", - "ethjs-schema": "0.1.9", + "ethjs-schema": "0.2.0", "ethjs-util": "0.1.3", "is-hex-prefixed": "1.0.0", "number-to-bn": "1.7.0", @@ -6134,9 +6134,14 @@ } }, "ethjs-rpc": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/ethjs-rpc/-/ethjs-rpc-0.1.8.tgz", - "integrity": "sha1-FnZ0DkHHIoGWpxGJ0z8VychbWZ0=" + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/ethjs-rpc/-/ethjs-rpc-0.1.9.tgz", + "integrity": "sha512-KJqT7cgTeCJQ2RY1AlVmTZVnKIUXMPg+niPN5VJKwRSzpjgfr3LTVHlGbkRCqZtOMDi0ogB2vHZaRQiZBXZTUg==" + }, + "ethjs-schema": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ethjs-schema/-/ethjs-schema-0.2.0.tgz", + "integrity": "sha1-B7RtT1W3kqhGyQp58zDTHREsyjg=" }, "ethjs-util": { "version": "0.1.3", diff --git a/package.json b/package.json index b53daeb83..6cd8f7f4e 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "ethjs": "^0.2.8", "ethjs-contract": "^0.1.9", "ethjs-ens": "^2.0.0", - "ethjs-query": "^0.3.1", + "ethjs-query": "^0.3.4", "express": "^4.15.5", "extension-link-enabler": "^1.0.0", "extensionizer": "^1.0.0", @@ -144,6 +144,7 @@ "obs-store": "^3.0.0", "once": "^1.3.3", "percentile": "^1.2.0", + "pify": "^3.0.0", "ping-pong-stream": "^1.0.0", "pojo-migrator": "^2.1.0", "polyfill-crypto.getrandomvalues": "^1.0.0", @@ -151,7 +152,6 @@ "promise-filter": "^1.1.0", "promise-to-callback": "^1.0.0", "pump": "^3.0.0", - "pify": "^3.0.0", "pumpify": "^1.3.4", "qrcode-npm": "0.0.3", "ramda": "^0.24.1", From c4c459c8d785c9169dd5bc4d1209ebbec6429f33 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 09:41:25 -0700 Subject: [PATCH 075/246] controllers - currency - warn currency and encountered error --- app/scripts/controllers/currency.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js index 25a7a942e..930fc52e8 100644 --- a/app/scripts/controllers/currency.js +++ b/app/scripts/controllers/currency.js @@ -52,7 +52,7 @@ class CurrencyController { this.setConversionDate(Number(parsedResponse.timestamp)) }).catch((err) => { if (err) { - console.warn('MetaMask - Failed to query currency conversion.') + console.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err) this.setConversionRate(0) this.setConversionDate('N/A') } From 16c36cc51bef563964ba583191df92a336916d5a Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 09:58:07 -0700 Subject: [PATCH 076/246] ci - publish dist as artifact --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 75819fc6e..a983f77c0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -98,6 +98,9 @@ jobs: key: build-cache-{{ .Revision }} paths: - dist + - store_artifacts: + path: dist/chrome + # destination: build prep-scss: docker: From 5834c13769a4c84fc89f2c4bd2480f3fe58b5100 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 13:37:02 -0700 Subject: [PATCH 077/246] ui - change window title 'MetaMask Plugin' to 'MetaMask' --- app/home.html | 2 +- app/popup.html | 2 +- test/e2e/metamask.spec.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/home.html b/app/home.html index cfb4b00a0..730215d1a 100644 --- a/app/home.html +++ b/app/home.html @@ -3,7 +3,7 @@ - MetaMask Plugin + MetaMask
diff --git a/app/popup.html b/app/popup.html index bf09b97ca..148d266d3 100644 --- a/app/popup.html +++ b/app/popup.html @@ -3,7 +3,7 @@ - MetaMask Plugin + MetaMask
diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index c73ba2b41..e81e0a8df 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -33,7 +33,7 @@ describe('Metamask popup page', function () { it('should match title', async () => { const title = await driver.getTitle() - assert.equal(title, 'MetaMask Plugin', 'title matches MetaMask Plugin') + assert.equal(title, 'MetaMask', 'title matches MetaMask') }) it('should show privacy notice', async () => { From 5815de33fbef617625d8350ec8e88aa4dbff6156 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 14:04:33 -0700 Subject: [PATCH 078/246] build - rename 'popup.js' to 'ui.js' --- app/home.html | 2 +- app/notification.html | 2 +- app/popup.html | 2 +- app/scripts/{popup.js => ui.js} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename app/scripts/{popup.js => ui.js} (100%) diff --git a/app/home.html b/app/home.html index 730215d1a..bb8e936a3 100644 --- a/app/home.html +++ b/app/home.html @@ -7,6 +7,6 @@
- + diff --git a/app/notification.html b/app/notification.html index f10cbbf41..2255ca2c1 100644 --- a/app/notification.html +++ b/app/notification.html @@ -11,6 +11,6 @@
- + diff --git a/app/popup.html b/app/popup.html index 148d266d3..109487d3e 100644 --- a/app/popup.html +++ b/app/popup.html @@ -7,6 +7,6 @@
- + diff --git a/app/scripts/popup.js b/app/scripts/ui.js similarity index 100% rename from app/scripts/popup.js rename to app/scripts/ui.js From 53895f19e01146e23702eec52172b4f29cd6f20a Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 14:05:54 -0700 Subject: [PATCH 079/246] ci - upload mascara build as artifact --- .circleci/config.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a983f77c0..2c75aada9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -99,8 +99,7 @@ jobs: paths: - dist - store_artifacts: - path: dist/chrome - # destination: build + path: dist/mascara prep-scss: docker: From bdf99269e275590b31347322961e773ad980b812 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 14:06:59 -0700 Subject: [PATCH 080/246] mascara - move file locations to match extension structure --- mascara/server/index.js | 8 ++++---- mascara/src/proxy.js | 2 +- mascara/src/ui.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mascara/server/index.js b/mascara/server/index.js index 6fb1287cc..0f9b047a7 100644 --- a/mascara/server/index.js +++ b/mascara/server/index.js @@ -20,16 +20,16 @@ function createMetamascaraServer () { server.use(compression()) // ui window - serveBundle(server, '/ui.js', uiBundle) + serveBundle(server, '/scripts/ui.js', uiBundle) server.use(express.static(path.join(__dirname, '/../ui/'), { setHeaders: (res) => res.set('X-Frame-Options', 'DENY') })) server.use(express.static(path.join(__dirname, '/../../dist/chrome'))) // metamascara serveBundle(server, '/metamascara.js', metamascaraBundle) // proxy - serveBundle(server, '/proxy/proxy.js', proxyBundle) - server.use('/proxy/', express.static(path.join(__dirname, '/../proxy'))) + serveBundle(server, '/scripts/proxy.js', proxyBundle) + server.use('/', express.static(path.join(__dirname, '/../proxy'))) // background - serveBundle(server, '/background.js', backgroundBuild) + serveBundle(server, '/scripts/background.js', backgroundBuild) return server diff --git a/mascara/src/proxy.js b/mascara/src/proxy.js index 54c5d5cf4..3958f7d50 100644 --- a/mascara/src/proxy.js +++ b/mascara/src/proxy.js @@ -4,7 +4,7 @@ const SwStream = require('sw-stream/lib/sw-stream.js') const intervalDelay = Math.floor(Math.random() * (30000 - 1000)) + 1000 const background = new SWcontroller({ - fileName: '/background.js', + fileName: './scripts/background.js', letBeIdle: false, wakeUpInterval: 30000, intervalDelay, diff --git a/mascara/src/ui.js b/mascara/src/ui.js index b272a2e06..21e5f32a9 100644 --- a/mascara/src/ui.js +++ b/mascara/src/ui.js @@ -20,7 +20,7 @@ window.METAMASK_PLATFORM_TYPE = 'mascara' const intervalDelay = Math.floor(Math.random() * (30000 - 1000)) + 1000 const background = new SWcontroller({ - fileName: '/background.js', + fileName: './scripts/background.js', letBeIdle: false, intervalDelay, wakeUpInterval: 20000, From 4f915cf2d817cf4dadea581c90a98841b81c156d Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 14:07:32 -0700 Subject: [PATCH 081/246] build - refactor build task generators + add mascara to standard build phase --- gulpfile.js | 202 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 116 insertions(+), 86 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index f57ea6206..2c000f576 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -32,6 +32,15 @@ var babel = require('gulp-babel') var disableDebugTools = gutil.env.disableDebugTools var debug = gutil.env.debug +const commonPlatforms = [ + // browser extensions + 'firefox', + 'chrome', + 'edge', + 'opera', + // browser webapp + 'mascara', +] // browser reload @@ -46,58 +55,28 @@ gulp.task('dev:reload', function() { gulp.task('copy:locales', copyTask({ source: './app/_locales/', - destinations: [ - './dist/firefox/_locales', - './dist/chrome/_locales', - './dist/edge/_locales', - './dist/opera/_locales', - ] + destinations: commonPlatforms.map(platform => `./dist/${platform}/_locales`), })) gulp.task('copy:images', copyTask({ source: './app/images/', - destinations: [ - './dist/firefox/images', - './dist/chrome/images', - './dist/edge/images', - './dist/opera/images', - ], + destinations: commonPlatforms.map(platform => `./dist/${platform}/images`), })) gulp.task('copy:contractImages', copyTask({ source: './node_modules/eth-contract-metadata/images/', - destinations: [ - './dist/firefox/images/contract', - './dist/chrome/images/contract', - './dist/edge/images/contract', - './dist/opera/images/contract', - ], + destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contract`), })) gulp.task('copy:fonts', copyTask({ source: './app/fonts/', - destinations: [ - './dist/firefox/fonts', - './dist/chrome/fonts', - './dist/edge/fonts', - './dist/opera/fonts', - ], + destinations: commonPlatforms.map(platform => `./dist/${platform}/fonts`), })) gulp.task('copy:reload', copyTask({ source: './app/scripts/', - destinations: [ - './dist/firefox/scripts', - './dist/chrome/scripts', - './dist/edge/scripts', - './dist/opera/scripts', - ], + destinations: commonPlatforms.map(platform => `./dist/${platform}/scripts`), pattern: '/chromereload.js', })) gulp.task('copy:root', copyTask({ source: './app/', - destinations: [ - './dist/firefox', - './dist/chrome', - './dist/edge', - './dist/opera', - ], + destinations: commonPlatforms.map(platform => `./dist/${platform}`), pattern: '/*', })) @@ -208,7 +187,7 @@ const jsFiles = [ 'inpage', 'contentscript', 'background', - 'popup', + 'ui', ] // scss compilation and autoprefixing tasks @@ -230,7 +209,7 @@ gulp.task('lint-scss', function() { .src('ui/app/css/itcss/**/*.scss') .pipe(gulpStylelint({ reporters: [ - {formatter: 'string', console: true} + { formatter: 'string', console: true } ], fix: true, })); @@ -243,32 +222,51 @@ gulp.task('fmt-scss', function () { }); // bundle tasks +createTasksForBuildJsExtension({ jsFiles, taskPrefix: 'dev:js', bundleTaskOpts: { isBuild: false } }) +createTasksForBuildJsExtension({ jsFiles, taskPrefix: 'build:js:extension', bundleTaskOpts: { isBuild: true } }) +createTasksForBuildJsMascara({ taskPrefix: 'build:js:mascara' }) + +function createTasksForBuildJsExtension({ jsFiles, taskPrefix, bundleTaskOpts }) { + // inpage must be built before all other scripts: + const rootDir = './app/scripts' + const nonInpageFiles = jsFiles.filter(file => file !== 'inpage') + const buildPhase1 = ['inpage'] + const buildPhase2 = nonInpageFiles + const destinations = [ + './dist/firefox/scripts', + './dist/chrome/scripts', + './dist/edge/scripts', + './dist/opera/scripts', + ] + createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, buildPhase1, buildPhase2 }) +} -var jsDevStrings = jsFiles.map(jsFile => `dev:js:${jsFile}`) -var jsBuildStrings = jsFiles.map(jsFile => `build:js:${jsFile}`) - -jsFiles.forEach((jsFile) => { - gulp.task(`dev:js:${jsFile}`, bundleTask({ - watch: true, - label: jsFile, - filename: `${jsFile}.js`, - isBuild: false - })) - gulp.task(`build:js:${jsFile}`, bundleTask({ - watch: false, - label: jsFile, - filename: `${jsFile}.js`, - isBuild: true - })) -}) +function createTasksForBuildJsMascara({ taskPrefix, bundleTaskOpts }) { + // inpage must be built before all other scripts: + const rootDir = './mascara/src/' + const jsFiles = ['ui', 'proxy', 'background'] + const destinations = ['./dist/mascara/scripts'] + createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, buildPhase1: jsFiles }) +} -// inpage must be built before all other scripts: -const firstDevString = jsDevStrings.shift() -gulp.task('dev:js', gulp.series(firstDevString, gulp.parallel(...jsDevStrings))) +function createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, buildPhase1 = [], buildPhase2 = [] }) { + // bundle task for each file + jsFiles.forEach((jsFile) => { + gulp.task(`${taskPrefix}:${jsFile}`, bundleTask(Object.assign({ + watch: false, + label: jsFile, + filename: `${jsFile}.js`, + filepath: `${rootDir}/${jsFile}.js`, + destinations, + }, bundleTaskOpts))) + }) + // compose into larger task + const subtasks = [] + subtasks.push(gulp.parallel(buildPhase1.map(file => `${taskPrefix}:${file}`))) + if (buildPhase2.length) subtasks.push(gulp.parallel(buildPhase2.map(file => `${taskPrefix}:${file}`))) -// inpage must be built before all other scripts: -const firstBuildString = jsBuildStrings.shift() -gulp.task('build:js', gulp.series(firstBuildString, gulp.parallel(...jsBuildStrings))) + gulp.task(taskPrefix, gulp.series(subtasks)) +} // disc bundle analyzer tasks @@ -278,7 +276,6 @@ jsFiles.forEach((jsFile) => { gulp.task('disc', gulp.parallel(jsFiles.map(jsFile => `disc:${jsFile}`))) - // clean dist @@ -295,16 +292,44 @@ gulp.task('zip', gulp.parallel('zip:chrome', 'zip:firefox', 'zip:edge', 'zip:ope // set env var for production gulp.task('apply-prod-environment', function(done) { - process.env.NODE_ENV = 'production' - done() + process.env.NODE_ENV = 'production' + done() }); // high level tasks -gulp.task('dev', gulp.series('build:scss', 'dev:js', 'copy', gulp.parallel('watch:scss', 'copy:watch', 'dev:reload'))) +gulp.task('dev', + gulp.series( + 'build:scss', + 'dev:js', + 'copy', + gulp.parallel( + 'watch:scss', + 'copy:watch', + 'dev:reload' + ) + ) +) + +gulp.task('build', + gulp.series( + 'clean', + 'build:scss', + gulp.parallel( + 'build:js:extension', + 'build:js:mascara', + 'copy' + ) + ) +) -gulp.task('build', gulp.series('clean', 'build:scss', gulp.parallel('build:js', 'copy'))) -gulp.task('dist', gulp.series('apply-prod-environment', 'build', 'zip')) +gulp.task('dist', + gulp.series( + 'apply-prod-environment', + 'build', + 'zip' + ) +) // task generators @@ -337,7 +362,7 @@ function zipTask(target) { function generateBundler(opts, performBundle) { const browserifyOpts = assign({}, watchify.args, { - entries: ['./app/scripts/'+opts.filename], + entries: [opts.filepath], plugin: 'browserify-derequire', debug: true, fullPaths: debug, @@ -384,19 +409,21 @@ function bundleTask(opts) { return performBundle function performBundle(){ - return ( - bundler.bundle() + let buildStream = bundler.bundle() + + // handle errors + buildStream.on('error', (err) => { + beep() + if (opts.watch) { + console.warn(err.stack) + } else { + throw err + } + }) - // handle errors - .on('error', (err) => { - beep() - if (opts.watch) { - console.warn(err.stack) - } else { - throw err - } - }) + // process bundles + buildStream = buildStream // convert bundle stream to gulp vinyl stream .pipe(source(opts.filename)) // inject variables into bundle @@ -412,15 +439,18 @@ function bundleTask(opts) { }))) // writes .map file .pipe(sourcemaps.write(debug ? './' : '../../sourcemaps')) - // write completed bundles - .pipe(gulp.dest('./dist/firefox/scripts')) - .pipe(gulp.dest('./dist/chrome/scripts')) - .pipe(gulp.dest('./dist/edge/scripts')) - .pipe(gulp.dest('./dist/opera/scripts')) - // finally, trigger live reload + + // write completed bundles + opts.destinations.forEach((dest) => { + buildStream = buildStream.pipe(gulp.dest(dest)) + }) + + // finally, trigger live reload + buildStream = buildStream .pipe(gulpif(debug, livereload())) - ) + return buildStream + } } From 47039cc3a94ece44b109d3002b03508f97b82a36 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 28 Mar 2018 14:07:56 -0700 Subject: [PATCH 082/246] Add test to reproduce issue behavior --- test/unit/nonce-tracker-test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/unit/nonce-tracker-test.js b/test/unit/nonce-tracker-test.js index 8970cf84d..e17d491f1 100644 --- a/test/unit/nonce-tracker-test.js +++ b/test/unit/nonce-tracker-test.js @@ -33,6 +33,25 @@ describe('Nonce Tracker', function () { }) }) + describe.only('issue 3670', function () { + beforeEach(function () { + const txGen = new MockTxGen() + pendingTxs = txGen.generate({ status: 'submitted' }, { + fromNonce: 6, + count: 3, + }) + nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x6') + }) + + it('should return 9', async function () { + this.timeout(15000) + const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') + console.log(JSON.stringify(nonceLock, null, 2)) + assert.equal(nonceLock.nextNonce, '9', `nonce should be 9 got ${nonceLock.nextNonce}`) + await nonceLock.releaseLock() + }) + }) + describe('with no previous txs', function () { beforeEach(function () { nonceTracker = generateNonceTrackerWith([], []) From f50a7a8fe891a803e50cc256200e8ce8c903ea2e Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 28 Mar 2018 14:09:45 -0700 Subject: [PATCH 083/246] Rename variable to be more understandable --- app/scripts/lib/nonce-tracker.js | 5 ++--- test/unit/nonce-tracker-test.js | 21 +++++++++++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/lib/nonce-tracker.js index ed9dd3f11..5b1cd7f43 100644 --- a/app/scripts/lib/nonce-tracker.js +++ b/app/scripts/lib/nonce-tracker.js @@ -31,14 +31,13 @@ class NonceTracker { const networkNonceResult = await this._getNetworkNextNonce(address) const highestLocallyConfirmed = this._getHighestLocallyConfirmed(address) const nextNetworkNonce = networkNonceResult.nonce - const highestLocalNonce = highestLocallyConfirmed - const highestSuggested = Math.max(nextNetworkNonce, highestLocalNonce) + const highestSuggested = Math.max(nextNetworkNonce, highestLocallyConfirmed) const pendingTxs = this.getPendingTransactions(address) const localNonceResult = this._getHighestContinuousFrom(pendingTxs, highestSuggested) || 0 nonceDetails.params = { - highestLocalNonce, + highestLocallyConfirmed, highestSuggested, nextNetworkNonce, } diff --git a/test/unit/nonce-tracker-test.js b/test/unit/nonce-tracker-test.js index e17d491f1..5a27882ef 100644 --- a/test/unit/nonce-tracker-test.js +++ b/test/unit/nonce-tracker-test.js @@ -33,7 +33,25 @@ describe('Nonce Tracker', function () { }) }) - describe.only('issue 3670', function () { + describe('sentry issue 476304902', function () { + beforeEach(function () { + const txGen = new MockTxGen() + pendingTxs = txGen.generate({ status: 'submitted' }, { + fromNonce: 3, + count: 29, + }) + nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x3') + }) + + it('should return 9', async function () { + this.timeout(15000) + const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') + assert.equal(nonceLock.nextNonce, '32', `nonce should be 32 got ${nonceLock.nextNonce}`) + await nonceLock.releaseLock() + }) + }) + + describe('issue 3670', function () { beforeEach(function () { const txGen = new MockTxGen() pendingTxs = txGen.generate({ status: 'submitted' }, { @@ -46,7 +64,6 @@ describe('Nonce Tracker', function () { it('should return 9', async function () { this.timeout(15000) const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - console.log(JSON.stringify(nonceLock, null, 2)) assert.equal(nonceLock.nextNonce, '9', `nonce should be 9 got ${nonceLock.nextNonce}`) await nonceLock.releaseLock() }) From f7b4c9621fde7840fcdc0583c3cfde97b5e81cd8 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 14:42:58 -0700 Subject: [PATCH 084/246] ui - css - use relative path for fonts --- ui/app/css/itcss/settings/typography.scss | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ui/app/css/itcss/settings/typography.scss b/ui/app/css/itcss/settings/typography.scss index 8a56d9c6c..18c444c8a 100644 --- a/ui/app/css/itcss/settings/typography.scss +++ b/ui/app/css/itcss/settings/typography.scss @@ -1,4 +1,4 @@ -@import url('/fonts/Font_Awesome/font-awesome.min.css'); +@import url('./fonts/Font_Awesome/font-awesome.min.css'); @font-face { font-family: 'Roboto'; @@ -338,8 +338,8 @@ @font-face { font-family: 'Montserrat Regular'; - src: url('/fonts/Montserrat/Montserrat-Regular.woff') format('woff'); - src: url('/fonts/Montserrat/Montserrat-Regular.ttf') format('truetype'); + src: url('./fonts/Montserrat/Montserrat-Regular.woff') format('woff'); + src: url('./fonts/Montserrat/Montserrat-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; font-size: 'small'; @@ -347,59 +347,59 @@ @font-face { font-family: 'Montserrat Bold'; - src: url('/fonts/Montserrat/Montserrat-Bold.woff') format('woff'); - src: url('/fonts/Montserrat/Montserrat-Bold.ttf') format('truetype'); + src: url('./fonts/Montserrat/Montserrat-Bold.woff') format('woff'); + src: url('./fonts/Montserrat/Montserrat-Bold.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Montserrat Light'; - src: url('/fonts/Montserrat/Montserrat-Light.woff') format('woff'); - src: url('/fonts/Montserrat/Montserrat-Light.ttf') format('truetype'); + src: url('./fonts/Montserrat/Montserrat-Light.woff') format('woff'); + src: url('./fonts/Montserrat/Montserrat-Light.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Montserrat UltraLight'; - src: url('/fonts/Montserrat/Montserrat-UltraLight.woff') format('woff'); - src: url('/fonts/Montserrat/Montserrat-UltraLight.ttf') format('truetype'); + src: url('./fonts/Montserrat/Montserrat-UltraLight.woff') format('woff'); + src: url('./fonts/Montserrat/Montserrat-UltraLight.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'DIN OT'; - src: url('/fonts/DIN_OT/DINOT-2.otf') format('opentype'); + src: url('./fonts/DIN_OT/DINOT-2.otf') format('opentype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'DIN OT Light'; - src: url('/fonts/DIN_OT/DINOT-2.otf') format('opentype'); + src: url('./fonts/DIN_OT/DINOT-2.otf') format('opentype'); font-weight: 200; font-style: normal; } @font-face { font-family: 'DIN NEXT'; - src: url('/fonts/DIN Next/DIN Next W01 Regular.otf') format('opentype'); + src: url('./fonts/DIN Next/DIN Next W01 Regular.otf') format('opentype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'DIN NEXT Light'; - src: url('/fonts/DIN Next/DIN Next W10 Light.otf') format('opentype'); + src: url('./fonts/DIN Next/DIN Next W10 Light.otf') format('opentype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Lato'; - src: url('/fonts/Lato/Lato-Regular.ttf') format('truetype'); + src: url('./fonts/Lato/Lato-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; } From 55e15ee7c6fbaee3b52c21f86e4d6e82b9116528 Mon Sep 17 00:00:00 2001 From: Gornov Dmitry Date: Thu, 29 Mar 2018 02:18:18 +0200 Subject: [PATCH 085/246] Modified Russian localization. resolves #3534, #3644 --- app/_locales/ru/messages.json | 422 ++++++++++++++++++++-------------- 1 file changed, 250 insertions(+), 172 deletions(-) diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index e3a1935f5..8903e0a66 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -3,13 +3,13 @@ "message": "Принять" }, "account": { - "message": "Аккаунт" + "message": "Счет" }, "accountDetails": { - "message": "Детали Аккаунта" + "message": "Детали счета" }, "accountName": { - "message": "Имя Пользователя" + "message": "Название счета" }, "address": { "message": "Адрес" @@ -21,13 +21,13 @@ "message": "Добавить токен" }, "addTokens": { - "message": "Добавить Токены" + "message": "Добавить токены" }, "amount": { - "message": "Количество" + "message": "Сумма" }, "amountPlusGas": { - "message": "Количество + газ" + "message": "Сумма + газ" }, "appDescription": { "message": "Расширение браузера для Ethereum", @@ -37,11 +37,14 @@ "message": "MetaMask", "description": "The name of the application" }, + "approved": { + "message": "Одобрена" + }, "attemptingConnect": { "message": "Попытка подключиться к блокчейн сети." }, "attributions": { - "message": "Опознания" + "message": "Атрибуция" }, "available": { "message": "Доступный" @@ -53,13 +56,13 @@ "message": "Баланс:" }, "balances": { - "message": "Ваши балансы" + "message": "Ваш баланс" }, "balanceIsInsufficientGas": { "message": "Недостаточный баланс для текущего объема газа" }, "beta": { - "message": "БЕТА" + "message": "BETA" }, "betweenMinAndMax": { "message": "должно быть больше или равно $1 и меньше или равно $2.", @@ -69,10 +72,10 @@ "message": "Использовать Blockies Identicon" }, "borrowDharma": { - "message": "Заимствовать с Dharma (бета)" + "message": "Взять в долг на Dharma (Beta)" }, "builtInCalifornia": { - "message": "MetaMask спроектирован и построен в Калифорнии." + "message": "MetaMask спроектирован и разработан в Калифорнии." }, "buy": { "message": "Купить" @@ -81,7 +84,10 @@ "message": "Купить на Coinbase" }, "buyCoinbaseExplainer": { - "message": "Coinbase - самый популярный в мире способ купить и продать биткойн, ethereum и litecoin." + "message": "Биржа Coinbase – это наиболее популярный способ купить или продать bitcoin, ethereum и litecoin." + }, + "ok": { + "message": "ОК" }, "cancel": { "message": "Отмена" @@ -95,14 +101,17 @@ "confirm": { "message": "Подтвердить" }, + "confirmed": { + "message": "Подтверждена" + }, "confirmContract": { - "message": "Подтвердить Контракт" + "message": "Подтвердить контракт" }, "confirmPassword": { - "message": "Подтвердите Пароль" + "message": "Подтвердите пароль" }, "confirmTransaction": { - "message": "Подтвердить Транзакцию" + "message": "Подтвердить транзакцию" }, "continue": { "message": "Продолжить" @@ -114,7 +123,7 @@ "message": "Развертывание контракта" }, "conversionProgress": { - "message": "Выполняется конверсия" + "message": "Выполняется конвертация" }, "copiedButton": { "message": "Скопировано" @@ -126,7 +135,7 @@ "message": "Скопировано!" }, "copiedSafe": { - "message": "Я скопировал его где-то в безопасности" + "message": "Я скопировал это в безопасное место" }, "copy": { "message": "Скопировать" @@ -138,29 +147,32 @@ "message": " Скопировать " }, "copyPrivateKey": { - "message": "Это ваш личный ключ (нажмите, чтобы скопировать)" + "message": "Это ваш закрытый ключ (нажмите, чтобы скопировать)" }, "create": { "message": "Создать" }, "createAccount": { - "message": "Регистрация" + "message": "Создать счет" }, "createDen": { "message": "Создать" }, "crypto": { - "message": "Крипто", + "message": "Криптовалюта", "description": "Exchange type (cryptocurrencies)" }, "currentConversion": { - "message": "Текущая конверсия" + "message": "Текущая конвертация" }, "currentNetwork": { "message": "Текущая сеть" }, "customGas": { - "message": "Настроить Газ" + "message": "Настроить газ" + }, + "customToken": { + "message": "Пользовательский токен" }, "customize": { "message": "Настроить" @@ -169,112 +181,115 @@ "message": "Пользовательский RPC" }, "decimalsMustZerotoTen": { - "message": "Десятичные числа должны быть не менее 0, и не более 36." + "message": "Количество десятичных разрядов должно быть минимум 0 и максимум 36." }, "decimal": { - "message": "Десятичные значения точности" + "message": "Количество десятичных разрядов" }, "defaultNetwork": { - "message": "Сеть по умолчанию для транзакций Ether - это Main Net." + "message": "Основная сеть Ethereum – это сеть по умолчанию для Ether транзакций." }, "denExplainer": { - "message": "Ваш DEN - это ваше зашифрованное паролем хранилище в MetaMask." + "message": "DEN – это зашифрованное паролем хранилище внутри MetaMask." }, "deposit": { - "message": "Депозит" + "message": "Пополнить" }, "depositBTC": { - "message": "Депозит BTC по адресу:" + "message": "Отправьте ваш BTC на адрес ниже:" }, "depositCoin": { - "message": "Депозит $1 по указанному ниже адресу", + "message": "Отправьте ваш $1 на адрес ниже", "description": "Tells the user what coin they have selected to deposit with shapeshift" }, "depositEth": { - "message": "Депозит Eth" + "message": "Пополнить Eth" }, "depositEther": { - "message": "Депозит Эфир" + "message": "Пополнить Ether" }, "depositFiat": { - "message": "Депозит с деньгами" + "message": "Пополнить деньгами" }, "depositFromAccount": { - "message": "Депозит с другого счета" + "message": "Пополнить с другого счета" }, "depositShapeShift": { - "message": "Депозит с ShapeShift" + "message": "Пополнить через ShapeShift" }, "depositShapeShiftExplainer": { - "message": "Если у вас есть другие крипторесурсы, вы можете торговать и вносить Эфир непосредственно в кошелек MetaMask. Нет необходимости в аккаунте." + "message": "Если у вас есть другие криптовалюты, вы можете торговать и пополнять Ether напрямую в ваш MetaMask кошелек. Нет необходимости в счете." }, "details": { "message": "Детали" }, "directDeposit": { - "message": "Прямой Депозит" + "message": "Прямое пополнение" }, "directDepositEther": { - "message": "Прямой Депозит Эфира" + "message": "Прямое пополнение Ether" }, "directDepositEtherExplainer": { - "message": "Если у вас уже есть Эфир, самый быстрый способ получить Эфир в вашем новом кошельке это прямым депозитом." + "message": "Если у вас уже есть Ether, то самый быстрый способ получить Ether в ваш новый кошелек – это прямое пополнение." }, "done": { "message": "Готово" }, "downloadStatelogs": { - "message": "Загрузить логи статус" + "message": "Скачать журнал состояния" + }, + "dropped": { + "message": "Отброшена" }, "edit": { "message": "Редактировать" }, "editAccountName": { - "message": "Изменить Имя Аккаунта" + "message": "Редактировать название счета" }, "emailUs": { "message": "Свяжитесь с нами по электронной почте!" }, "encryptNewDen": { - "message": "Шифруйте новый DEN" + "message": "Зашифровать ваш новый DEN" }, "enterPassword": { "message": "Введите пароль" }, "enterPasswordConfirm": { - "message": "Введите свой пароль для подтверждения" + "message": "Введите ваш пароль для подтверждения" }, "etherscanView": { - "message": "Просмотреть аккаунт на Etherscan" + "message": "Просмотреть счет на Etherscan" }, "exchangeRate": { - "message": "Обменный Курс" + "message": "Обменный курс" }, "exportPrivateKey": { - "message": "Экспорт закрытого ключа" + "message": "Экспортировать закрытый ключ" }, "exportPrivateKeyWarning": { - "message": "Экспорт секретных ключей на свой страх и риск." + "message": "Вы экспортируете закрытые ключи на свой страх и риск." }, "failed": { - "message": "Не смогли" + "message": "Неудачна" }, "fiat": { - "message": "Бумажные деньги", + "message": "Валюта", "description": "Exchange type" }, "fileImportFail": { - "message": "Ошибка импорта файлов? Кликните сюда!", + "message": "Не работает импорт файла? Нажмите тут!", "description": "Helps user import their account from a JSON file" }, "followTwitter": { - "message": "Следуйте за нами на Twitter" + "message": "Читайте нас в Twitter" }, "from": { - "message": "Из" + "message": "Отправитель" }, "fromToSame": { - "message": "От и до адреса не могут быть одинаковым" + "message": "Адрес отправителя и получателя не могут быть одинаковыми" }, "fromShapeShift": { "message": "Из ShapeShift" @@ -284,37 +299,37 @@ "description": "Short indication of gas cost" }, "gasFee": { - "message": "Плата за Газ" + "message": "Комиссия за газ" }, "gasLimit": { - "message": "Газовый Предел" + "message": "Лимит газа" }, "gasLimitCalculation": { - "message": "Мы рассчитываем предполагаемый предел газа на основе коэффициентов успешности сети." + "message": "Мы расчитываем предлагаемый лимит газа на основании успешных ставок в сети." }, "gasLimitRequired": { - "message": "Требуется ограничение на Газ" + "message": "Установите лимит газа" }, "gasLimitTooLow": { - "message": "Предел газа должен быть не менее 21000" + "message": "Лимит газа должен быть как минимум 21000" }, "generatingSeed": { - "message": "Создание Семян ..." + "message": "Генерируем фразу..." }, "gasPrice": { - "message": "Цена на Газ (GWEI)" + "message": "Цена за газ (GWEI)" }, "gasPriceCalculation": { - "message": "Мы вычисляем предлагаемые цены на газ на основе коэффициентов успеха сети." + "message": "Мы расчитываем предлагаемые цены за газ на основании успешных ставок в сети." }, "gasPriceRequired": { - "message": "Требуется цена на Газ" + "message": "Установите стоимость газа" }, "getEther": { - "message": "Получить Эфир" + "message": "Получить Ether" }, "getEtherFromFaucet": { - "message": "Получите Эфир из крана $1", + "message": "Получить Ether из крана для $1", "description": "Displays network name for Ether faucet" }, "greaterThanMin": { @@ -322,14 +337,14 @@ "description": "helper for inputting hex as decimal input" }, "here": { - "message": "здесь", + "message": "тут", "description": "as in -click here- for more information (goes with troubleTokenBalances)" }, "hereList": { - "message": "Вот список !!!!" + "message": "Вот список!!!!" }, "hide": { - "message": "Спрятать" + "message": "Скрыть" }, "hideToken": { "message": "Скрыть токен" @@ -338,33 +353,33 @@ "message": "Скрыть токен?" }, "howToDeposit": { - "message": "Как бы вы хотели поместить Эфир?" + "message": "Как бы вы хотели пополнить Ether?" }, "holdEther": { - "message": "Это позволяет вам использовать эфир и токены и служит мостом для децентрализованных приложений." + "message": "Позволяет вам хранить ether и токены и служит в качестве моста в децентрализированные приложения." }, "import": { "message": "Импортировать", "description": "Button to import an account from a selected file" }, "importAccount": { - "message": "Импорт Аккаунта" + "message": "Импортировать счет" }, "importAccountMsg": { - "message": " Импортированные аккаунты не будут связаны с вашей первоначально созданным аккаунтом MetaMask. Подробнее о импортированных аккаунтах " + "message":" Импортированные счета не будут ассоциированы с вашей ключевой фразой, созданной MetaMask. Узнать больше про импорт счетов " }, "importAnAccount": { "message": "Импортировать аккаунт" }, "importDen": { - "message": "Импорт существующих DEN" + "message": "Импортировать существующий DEN" }, "imported": { "message": "Импортирован", "description": "status showing that an account has been fully loaded into the keyring" }, "infoHelp": { - "message": "Информация и Помощь" + "message": "Информация и помощь" }, "insufficientFunds": { "message": "Недостаточно средств." @@ -373,35 +388,44 @@ "message": "Недостаточно токенов." }, "invalidAddress": { - "message": "Недействительный адрес" + "message": "Неверный адрес" }, "invalidAddressRecipient": { - "message": "Недопустимый адрес получателя." + "message": "Неверный адрес получателя" }, "invalidGasParams": { - "message": "Недопустимые параметры Газа" + "message": "Неверные параметры газа" }, "invalidInput": { - "message": "Неправильный ввод." + "message": "Неверный ввод." }, "invalidRequest": { - "message": "Неверный Запрос" + "message": "Неверный запрос" }, "invalidRPC": { - "message": "Недопустимый URI RPC" + "message": "Неверный RPC URI" }, "jsonFail": { - "message": "Что-то пошло не так. Убедитесь, что ваш файл JSON правильно отформатирован." + "message": "Что-то пошло не так. Убедитесь, что ваш JSON файл правильно отформатирован." }, "jsonFile": { - "message": "Файл JSON", + "message": "JSON файл", "description": "format for importing an account" }, + "keepTrackTokens": { + "message": "Следите за купленными вами токенами с помощью аккаунта MetaMask." + }, "kovan": { - "message": "Kovan тестовая сеть" + "message": "Тестовая сеть Kovan" }, "knowledgeDataBase": { - "message": "Посетите нашу базу знаний" + "message": "Посмотрите нашу Базу Знаний" + }, + "max": { + "message": "Максимум" + }, + "learnMore": { + "message": "Узнать больше." }, "lessThanMax": { "message": "должно быть меньше или равно $1.", @@ -410,29 +434,32 @@ "likeToAddTokens": { "message": "Вы хотите добавить эти токены?" }, + "links": { + "message": "Ссылки" + }, "limit": { - "message": "Предел" + "message": "Лимит" }, "loading": { "message": "Загрузка..." }, "loadingTokens": { - "message": "Загрузка токенов ..." + "message": "Загрузка токенов..." }, "localhost": { - "message": "Локальный адрес 8545" + "message": "Localhost 8545" }, "login": { - "message": "Авторизоваться" + "message": "Вход" }, "logout": { - "message": "Выйти" + "message": "Выход" }, "loose": { - "message": "Рыхлый" + "message": "Несвязанный" }, "loweCaseWords": { - "message": "семенные слова имеют только символы нижнего регистра" + "message": "ключевая фраза может содержать только символы нижнего регистра" }, "mainnet": { "message": "Основная сеть Ethereum" @@ -441,19 +468,19 @@ "message": "Сообщение" }, "metamaskDescription": { - "message": "MetaMask - это безопасное хранилище для Ethereum." + "message": "MetaMask – безопасный кошелек для Ethereum." }, "min": { "message": "Минимум" }, "myAccounts": { - "message": "Мои Аккаунты" + "message": "Мои счета" }, "mustSelectOne": { - "message": "Необходимо выбрать не менее 1 токена." + "message": "Необходимо выбрать как минимум 1 токен." }, "needEtherInWallet": { - "message": "Чтобы взаимодействовать с децентрализованными приложениями с помощью MetaMask, вам понадобится Эфир в вашем кошельке." + "message": "Для взаимодействия с децентрализованными приложениями с помощью MetaMask нужен Ether в вашем кошельке." }, "needImportFile": { "message": "Вы должны выбрать файл для импорта.", @@ -464,60 +491,60 @@ "description": "Password and file needed to import an account" }, "negativeETH": { - "message": "Невозможно отправить отрицательные количества ETH." + "message": "Невозможно отправить отрицательную сумму ETH." }, "networks": { "message": "Сети" }, "newAccount": { - "message": "Новый Аккаунт" + "message": "Новый счет" }, "newAccountNumberName": { - "message": "Аккаунт $1", + "message": "Счет $1", "description": "Default name of next account to be created on create account screen" }, "newContract": { - "message": "Новый Контракт" + "message": "Новый контракт" }, "newPassword": { "message": "Новый пароль (мин. 8 символов)" }, "newRecipient": { - "message": "Новый Получатель" + "message": "Новый получатель" }, "newRPC": { - "message": "Новый URL-адрес RPC" + "message": "Новый RPC URL" }, "next": { "message": "Далее" }, "noAddressForName": { - "message": "Для этого имени не задан адрес." + "message": "Дла этого названия не установлен адрес." }, "noDeposits": { - "message": "Не было получено никаких депозитов" + "message": "Пополнения не получены" }, "noTransactionHistory": { "message": "Нет истории транзакций." }, "noTransactions": { - "message": "Нет Транзакций" + "message": "Нет транзакций" }, "notStarted": { - "message": "Не Начался" + "message": "Не запущен" }, "oldUI": { - "message": "Старый Интерфейс" + "message": "Старая версия интерфейса" }, "oldUIMessage": { - "message": "Вы вернулись к старому интерфейсу. Вы можете вернуться к новому с помощью опции в раскрывающемся меню в правом верхнем углу." + "message": "Вы вернулись к старой версии интерфейса пользователя. Вы можете переключиться на новую с помощью опции выпадающего меню в правом верхнем углу." }, "or": { "message": "или", "description": "choice between creating or importing a new account" }, "passwordCorrect": { - "message": "Убедитесь, что ваш пароль правильный." + "message": "Убедитесь, что ваш пароль верный." }, "passwordMismatch": { "message": "пароли не совпадают", @@ -528,27 +555,30 @@ "description": "in password creation process, the password is not long enough to be secure" }, "pastePrivateKey": { - "message": "Вставьте свою личную строку:", + "message": "Вставьте ваш закрытый ключ тут:", "description": "For importing an account from a private key" }, "pasteSeed": { - "message": "Вставьте здесь свою семенную фразу!" + "message": "Вставьте вашу ключевую фразу!" }, "personalAddressDetected": { - "message": "Персональный адрес обнаружен. Введите адрес контракта токена." + "message": "Обнаружен персональный адрес. Введите адрес контракта токена." }, "pleaseReviewTransaction": { "message": "Проверьте транзакцию." }, + "popularTokens": { + "message": "Популярные токены" + }, "privacyMsg": { - "message": "Политика Конфиденциальности" + "message": "Политика конфиденциальности" }, "privateKey": { "message": "Закрытый ключ", "description": "select this type of file to use to import an account" }, "privateKeyWarning": { - "message": "Предупреждение: никогда не раскрывайте этот ключ. Любой, у кого есть ваши личные ключи, может украсть любые активы, хранящиеся в вашем аккаунте." + "message": "Предупреждение: Никогда не раскрывайте этот ключ. Любой, у кого есть ваши закрытые ключи, может украсть любые активы, хранящиеся на счету." }, "privateNetwork": { "message": "Частная сеть" @@ -557,126 +587,165 @@ "message": "Показать QR-код" }, "readdToken": { - "message": "Вы можете добавить этот токен в будущем, перейдя в “Добавить токен” в меню параметров вашего аккаунта." + "message": "Вы можете в будущем добавить обратно этот токен, выбрав пункт меню “Добавить токен”." }, "readMore": { - "message": "Подробнее читайте здесь." + "message": "Узнать больше тут." }, "readMore2": { - "message": "Прочитайте больше." + "message": "Узнать больше." }, "receive": { "message": "Получить" }, "recipientAddress": { - "message": "Адрес Получателя" + "message": "Адрес получателя" }, "refundAddress": { - "message": "Ваш Адрес Возврата" + "message": "Ваш адрес для возврата средств" }, "rejected": { - "message": "Отклонено" + "message": "Отклонена" }, "resetAccount": { "message": "Сбросить аккаунт" }, "restoreFromSeed": { - "message": "Восстановить от семенной фразы" + "message": "Восстановить из ключевой фразы" + }, + "restoreVault": { + "message": "Восстановить кошелек" }, "required": { - "message": "Необходимо" + "message": "Обязательное поле" }, "retryWithMoreGas": { - "message": "Повторите попытку с более высокой ценой на газ здесь" + "message": "Повторите попытку с большей ценой за газRetry with a higher gas price here" + }, + "walletSeed": { + "message": "Ключевая фраза кошелька" }, "revealSeedWords": { - "message": "Раскрыть семенные слова" + "message": "Показать ключевую фразу" }, "revealSeedWordsWarning": { - "message": "Не восстанавливайте семенные слова в общественном месте! Эти слова могут использоваться для кражи всех ваших аккаунтах." + "message": "Не восстанавливайте ключевую фразу в общественном месте! Она может быть использована для кражи всех ваших счетов." }, "revert": { - "message": "Откат" + "message": "Восстановить" }, "rinkeby": { - "message": "Rinkeby тестовая сеть" + "message": "Тестовая сеть Rinkeby" }, "ropsten": { - "message": "Ropsten тестовая сеть" + "message": "Тестовая сеть Ropsten" + }, + "currentRpc": { + "message": "Current RPC" + }, + "connectingToMainnet": { + "message": "Соединение с основной сетью Ethereum" + }, + "connectingToRopsten": { + "message": "Соединение с тестовой сетью Ropsten" + }, + "connectingToKovan": { + "message": "Соединение с тестовой сетью Kovan" + }, + "connectingToRinkeby": { + "message": "Соединение с тестовой сетью Rinkeby" + }, + "connectingToUnknown": { + "message": "Соединение с неизвестной сетью" }, "sampleAccountName": { - "message": "Например, Мой новый аккаунт", + "message": "Например, Мой новый счет", "description": "Help user understand concept of adding a human-readable name to their account" }, "save": { "message": "Сохранить" }, "saveAsFile": { - "message": "Сохранить как Файл", + "message": "Сохранить в виде файла", "description": "Account export process" }, "saveSeedAsFile": { - "message": "Сохранить Семенные Слова Как Файл" + "message": "Сохранить ключевую фразу в виде файла" }, "search": { "message": "Поиск" }, "secretPhrase": { - "message": "Введите свою секретную двенадцатисловную фразу здесь, чтобы восстановить хранилище." + "message": "Введите вашу ключевую фразу из 12 слов, чтобы восстановить кошелек." + }, + "newPassword8Chars": { + "message": "Новый пароль (мин. 8 символов)" }, "seedPhraseReq": { - "message": "семенные фразы длиной 12 слов" + "message": "ключевые фразы имеют длину 12 слов" }, "select": { "message": "Выбрать" }, "selectCurrency": { - "message": "Выберите Валюту" + "message": "Выберите валюту" }, "selectService": { - "message": "Выберите Сервис" + "message": "Выберите сервис" }, "selectType": { - "message": "Выберите Тип" + "message": "Выберите тип" }, "send": { - "message": "Послать" + "message": "Отправить" }, "sendETH": { "message": "Отправить ETH" }, "sendTokens": { - "message": "Отправить Токены" + "message": "Отправить токены" + }, + "onlySendToEtherAddress": { + "message": "Отправляйте ETH только на Ethereum адреса." + }, + "searchTokens": { + "message": "Поиск токенов" }, "sendTokensAnywhere": { - "message": "Отправить Токены кому-либо с аккаунтом Ethereum" + "message": "Отправить токены любому, у кого есть счет Ethereum" }, "settings": { "message": "Настройки" }, + "info": { + "message": "Информация" + }, "shapeshiftBuy": { - "message": "Купить с помощью Shapeshift" + "message": "Купить через Shapeshift" }, "showPrivateKeys": { - "message": "Показать приватные ключи" + "message": "Показать закрытые ключи" }, "showQRCode": { "message": "Показать QR-код" }, "sign": { - "message": "Знак" + "message": "Подпись" + }, + "signed": { + "message": "Подписана" }, "signMessage": { - "message": "Нодписать сообщение" + "message": "Подписать сообщение" }, "signNotice": { - "message": "Подписание этого сообщения может иметь \nопасные побочные эффекты. Только подписывайте сообщения \nс сайтов, которым вы полностью доверяете своим аккаунтом. Этот опасный метод будет удален в будущей версии." + "message": "Подпись этого сообщения может иметь \nопасные побочные эффекты. Подписывайте только сообщения \nс сайтов, которым вы полностью доверяете свой аккаунт. Этот опасный метод будет удален в будущей версии." }, "sigRequest": { - "message": "Запрос на подпись" + "message": "Запрос подписи" }, "sigRequested": { - "message": "Подпись Запрошена" + "message": "Подпись запрошена" }, "spaceBetween": { "message": "между словами может быть только пробел" @@ -685,53 +754,59 @@ "message": "Статус" }, "stateLogs": { - "message": "Логи Статуса" + "message": "Журнал состояния" }, "stateLogsDescription": { - "message": "Логи статуса содержат ваши общедоступные адреса и отправленные транзакции." + "message": "Журнал состояния содержит ваши публичные адреса счетов и совершенные транзакции." + }, + "stateLogError": { + "message": "Ошибка при получении журнала состояния." }, "submit": { "message": "Отправить" }, + "submitted": { + "message": "Отправлена" + }, "supportCenter": { - "message": "Посетите наш Центр поддержки" + "message": "Перейти в наш Центр поддержки" }, "symbolBetweenZeroTen": { "message": "Символ должен быть от 0 до 10 символов." }, "takesTooLong": { - "message": "Занимает слишком долго?" + "message": "Слишком долго?" }, "terms": { - "message": "Условия Эксплуатации" + "message": "Условия пользования" }, "testFaucet": { - "message": "Тестовый Кран" + "message": "Тестовый кран" }, "to": { - "message": "К" + "message": "Получатель: " }, "toETHviaShapeShift": { "message": "$1 в ETH через ShapeShift", "description": "system will fill in deposit type in start of message" }, "tokenAddress": { - "message": "Адрес Токена" + "message": "Адрес токена" }, "tokenAlreadyAdded": { - "message": "Токен уже добавлен." + "message": "Токен уже был добавлен." }, "tokenBalance": { - "message": "Баланс Вашых Tокенов:" + "message": "Баланс ваших токенов:" }, "tokenSelection": { - "message": "Поиск токенов или выбор из нашего списка популярных токенов." + "message": "Поищите токен или выберите из нашего списка популярных токенов." }, "tokenSymbol": { - "message": "Символ Токена" + "message": "Символ токена" }, "tokenWarning1": { - "message": "Следите за токенами, которые вы купили с помощью аккаунта MetaMask. Если вы купили токены, используя другой аккаунт, эти токены здесь не появятся." + "message": "Отслеживаются токены, купленные на счет в MetaMask. Если вы купили токены, используя другой счет, такие токены не будут тут отображены." }, "total": { "message": "Всего" @@ -740,35 +815,38 @@ "message": "транзакции" }, "transactionMemo": { - "message": "Транзакционная записка (необязательно)" + "message": "Транзакционные данные (необязательный)" }, "transactionNumber": { - "message": "Номер Транзакции" + "message": "Номер транзакции" }, "transfers": { "message": "Переводы" }, "troubleTokenBalances": { - "message": "У нас были проблемы с загрузкой ваших токенов. Вы можете просмотреть их ", + "message": "Возникли проблемы при загрузке балансов токенов. Вы можете посмотреть их ", "description": "Followed by a link (here) to view token balances" }, "twelveWords": { - "message": "Эти 12 слов - единственный способ восстановить ваши учетные записи MetaMask.\nСохраните их где-нибудь в безопасности и в тайне." + "message": "Эти 12 слов являются единственной возможностью восстановить ваши счета в MetaMask.\nСохраните из в надежном секретном месте." }, "typePassword": { - "message": "Введите Пароль" + "message": "Введите пароль" }, "uiWelcome": { - "message": "Добро пожаловать в новый интерфейс (бета-версия)" + "message": "Новый интерфейс (Beta)" }, "uiWelcomeMessage": { - "message": "Теперь вы используете новый интерфейс Metamask. Осмотритесь, попробуйте новые функции, такие как отправку токенов, и сообщите нам, есть ли у вас какие-либо проблемы." + "message": "Теперь вы используете новый интерфейс пользователя MetaMask. Осмотритесь, попробуйте новые функции, например, отправить токены и, если возникнут проблемы, сообщите нам." + }, + "unapproved": { + "message": "Не одобрена" }, "unavailable": { - "message": "Недоступен" + "message": "Недоступный" }, "unknown": { - "message": "Неизвестный" + "message": "Неизвестно" }, "unknownNetwork": { "message": "Неизвестная частная сеть" @@ -777,7 +855,7 @@ "message": "Неизвестный идентификатор сети" }, "uriErrorMsg": { - "message": "Для URI требуется соответствующий префикс HTTP / HTTPS." + "message": "Для URI требуется соответствующий префикс HTTP/HTTPS." }, "usaOnly": { "message": "Только США", @@ -787,19 +865,19 @@ "message": "Используется различными клиентами" }, "useOldUI": { - "message": "Использовать старый интерфейс" + "message": "Использовать старый интерфейс пользователя" }, "validFileImport": { - "message": "Вы должны выбрать действительный файл для импорта." + "message": "Вам нужно выбрать правильный файл для импорта." }, "vaultCreated": { - "message": "Создано хранилище" + "message": "Кошелек был создан" }, "viewAccount": { - "message": "Посмотреть аккаунт" + "message": "Посмотреть счет" }, "visitWebSite": { - "message": "Посетите наш сайт" + "message": "Перейти на наш сайт" }, "warning": { "message": "Предупреждение" @@ -811,7 +889,7 @@ "message": "Что это?" }, "yourSigRequested": { - "message": "Ваша подпись запрашивается" + "message": "Запрашивается ваша подпись" }, "youSign": { "message": "Вы подписываете" From d06c6bb4cac9a616067e294c8ddefac572b66441 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 17:38:28 -0700 Subject: [PATCH 086/246] ci - announce QA build to GitHub pull request --- .circleci/config.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2c75aada9..ac05e747c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -100,6 +100,18 @@ jobs: - dist - store_artifacts: path: dist/mascara + - run: + name: build:announce + command: | + CIRCLE_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}" + SHORT_SHA1=$(echo $CIRCLE_SHA1 | cut -c 1-7) + QA_BUILD_URL="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0/home/circleci/project/dist/mascara/home.html" + COMMENT_BODY="[Try QA Build for $SHORT_SHA1]($QA_BUILD_URL)" + JSON_PAYLOAD="{\"body\":\"$COMMENT_BODY\"}" + POST_COMMENT_URI="https://api.github.com/repos/metamask/metamask-extension/issues/$CIRCLE_PR_NUMBER/comments" + echo "Announcement:\n$COMMENT_BODY" + echo "Posting to $POST_COMMENT_URI" + curl -d "$JSON_PAYLOAD" -H "Authorization: token $GITHUB_COMMENT_TOKEN" $POST_COMMENT_URI prep-scss: docker: From f35356a89a0f2b0eb670394667e9650ab92f03ed Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 18:07:02 -0700 Subject: [PATCH 087/246] mascara - html - fix script locations --- mascara/proxy/index.html | 4 ++-- mascara/ui/index.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mascara/proxy/index.html b/mascara/proxy/index.html index b83fc41af..0dff83f18 100644 --- a/mascara/proxy/index.html +++ b/mascara/proxy/index.html @@ -15,6 +15,6 @@ Hello! I am the MetaMask iframe. - + - \ No newline at end of file + diff --git a/mascara/ui/index.html b/mascara/ui/index.html index eac8e4898..dbc445891 100644 --- a/mascara/ui/index.html +++ b/mascara/ui/index.html @@ -7,6 +7,6 @@
- + - \ No newline at end of file + From cbfee0ac7e9ac705ba1a8b5bffa2c5ed4511b70d Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 18:07:38 -0700 Subject: [PATCH 088/246] mascara - server - server bundles before static assets + serve dist/mascara instead of chrome --- mascara/server/index.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/mascara/server/index.js b/mascara/server/index.js index 0f9b047a7..2ad8af242 100644 --- a/mascara/server/index.js +++ b/mascara/server/index.js @@ -15,22 +15,21 @@ function createMetamascaraServer () { const uiBundle = createBundle(path.join(__dirname, '/../src/ui.js')) const backgroundBuild = createBundle(path.join(__dirname, '/../src/background.js')) - // serve bundles + // setup server const server = express() server.use(compression()) - // ui window - serveBundle(server, '/scripts/ui.js', uiBundle) - server.use(express.static(path.join(__dirname, '/../ui/'), { setHeaders: (res) => res.set('X-Frame-Options', 'DENY') })) - server.use(express.static(path.join(__dirname, '/../../dist/chrome'))) - // metamascara + // serve bundles serveBundle(server, '/metamascara.js', metamascaraBundle) - // proxy + serveBundle(server, '/scripts/ui.js', uiBundle) serveBundle(server, '/scripts/proxy.js', proxyBundle) - server.use('/', express.static(path.join(__dirname, '/../proxy'))) - // background serveBundle(server, '/scripts/background.js', backgroundBuild) + // serve assets + server.use(express.static(path.join(__dirname, '/../ui/'), { setHeaders: (res) => res.set('X-Frame-Options', 'DENY') })) + server.use(express.static(path.join(__dirname, '/../../dist/mascara'))) + server.use(express.static(path.join(__dirname, '/../proxy'))) + return server } From 98f240064902f69b063b022eada56deacc9f1b35 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 19:56:44 -0700 Subject: [PATCH 089/246] build - refactor copy tasks --- gulpfile.js | 72 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 2c000f576..2b8627f14 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -27,19 +27,23 @@ var gulpStylelint = require('gulp-stylelint') var stylefmt = require('gulp-stylefmt') var uglify = require('gulp-uglify-es').default var babel = require('gulp-babel') +var debug = require('gulp-debug') var disableDebugTools = gutil.env.disableDebugTools -var debug = gutil.env.debug +var debugMode = gutil.env.debug -const commonPlatforms = [ - // browser extensions +const browserPlatforms = [ 'firefox', 'chrome', 'edge', 'opera', +] +const commonPlatforms = [ // browser webapp 'mascara', + // browser extensions + ...browserPlatforms ] // browser reload @@ -51,7 +55,7 @@ gulp.task('dev:reload', function() { }) -// copy static +// copy universal gulp.task('copy:locales', copyTask({ source: './app/_locales/', @@ -74,12 +78,22 @@ gulp.task('copy:reload', copyTask({ destinations: commonPlatforms.map(platform => `./dist/${platform}/scripts`), pattern: '/chromereload.js', })) -gulp.task('copy:root', copyTask({ + +// copy extension + +gulp.task('copy:manifest', copyTask({ + source: './app/', + destinations: browserPlatforms.map(platform => `./dist/${platform}`), + pattern: '/*.json', +})) +gulp.task('copy:html', copyTask({ source: './app/', - destinations: commonPlatforms.map(platform => `./dist/${platform}`), - pattern: '/*', + destinations: browserPlatforms.map(platform => `./dist/${platform}`), + pattern: '/*.html', })) +// manifest tinkering + gulp.task('manifest:chrome', function() { return gulp.src('./dist/chrome/manifest.json') .pipe(jsoneditor(function(json) { @@ -113,7 +127,7 @@ gulp.task('manifest:production', function() { ],{base: './dist/'}) // Exclude chromereload script in production: - .pipe(gulpif(!debug,jsoneditor(function(json) { + .pipe(gulpif(!debugMode,jsoneditor(function(json) { json.background.scripts = json.background.scripts.filter((script) => { return !script.includes('chromereload') }) @@ -123,21 +137,27 @@ gulp.task('manifest:production', function() { .pipe(gulp.dest('./dist/', { overwrite: true })) }) -const staticFiles = [ - 'locales', - 'images', - 'fonts', - 'root' +const copyTaskNames = [ + 'copy:locales', + 'copy:images', + 'copy:fonts', + 'copy:manifest', + 'copy:html', + 'copy:contractImages', ] -var copyStrings = staticFiles.map(staticFile => `copy:${staticFile}`) -copyStrings.push('copy:contractImages') - -if (debug) { - copyStrings.push('copy:reload') +if (debugMode) { + copyTaskNames.push('copy:reload') } -gulp.task('copy', gulp.series(gulp.parallel(...copyStrings), 'manifest:production', 'manifest:chrome', 'manifest:opera')) +gulp.task('copy', + gulp.series( + gulp.parallel(...copyTaskNames), + 'manifest:production', + 'manifest:chrome', + 'manifest:opera' + ) +) gulp.task('copy:watch', function(){ gulp.watch(['./app/{_locales,images}/*', './app/scripts/chromereload.js', './app/*.{html,json}'], gulp.series('copy')) }) @@ -245,7 +265,7 @@ function createTasksForBuildJsMascara({ taskPrefix, bundleTaskOpts }) { // inpage must be built before all other scripts: const rootDir = './mascara/src/' const jsFiles = ['ui', 'proxy', 'background'] - const destinations = ['./dist/mascara/scripts'] + const destinations = ['./dist/mascara'] createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, buildPhase1: jsFiles }) } @@ -342,11 +362,11 @@ function copyTask(opts){ return performCopy function performCopy(){ - let stream = gulp.src(source + pattern, { base: source }) + let stream = gulp.src(source + pattern, { base: source }).pipe(debug({ title: source })) destinations.forEach(function(destination) { stream = stream.pipe(gulp.dest(destination)) }) - stream.pipe(gulpif(debug,livereload())) + stream.pipe(gulpif(debugMode,livereload())) return stream } @@ -365,7 +385,7 @@ function generateBundler(opts, performBundle) { entries: [opts.filepath], plugin: 'browserify-derequire', debug: true, - fullPaths: debug, + fullPaths: debugMode, }) let bundler = browserify(browserifyOpts) @@ -427,7 +447,7 @@ function bundleTask(opts) { // convert bundle stream to gulp vinyl stream .pipe(source(opts.filename)) // inject variables into bundle - .pipe(replace('\'GULP_METAMASK_DEBUG\'', debug)) + .pipe(replace('\'GULP_METAMASK_DEBUG\'', debugMode)) // buffer file contents (?) .pipe(buffer()) // sourcemaps @@ -438,7 +458,7 @@ function bundleTask(opts) { mangle: { reserved: [ 'MetamaskInpageProvider' ] }, }))) // writes .map file - .pipe(sourcemaps.write(debug ? './' : '../../sourcemaps')) + .pipe(sourcemaps.write(debugMode ? './' : '../../sourcemaps')) // write completed bundles opts.destinations.forEach((dest) => { @@ -447,7 +467,7 @@ function bundleTask(opts) { // finally, trigger live reload buildStream = buildStream - .pipe(gulpif(debug, livereload())) + .pipe(gulpif(debugMode, livereload())) return buildStream From 91e8ea205e1902dbefecaf2d764e7bb40847e5b5 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 19:58:06 -0700 Subject: [PATCH 090/246] build - remove deprecated deps task --- gulpfile.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 2b8627f14..a094356ac 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -162,18 +162,6 @@ gulp.task('copy:watch', function(){ gulp.watch(['./app/{_locales,images}/*', './app/scripts/chromereload.js', './app/*.{html,json}'], gulp.series('copy')) }) -// record deps - -gulp.task('deps', function (cb) { - exec('npm ls', (err, stdoutOutput, stderrOutput) => { - if (err) return cb(err) - const browsers = ['firefox','chrome','edge','opera'] - asyncEach(browsers, (target, done) => { - fs.writeFile(`./dist/${target}/deps.txt`, stdoutOutput, done) - }, cb) - }) -}) - // lint js gulp.task('lint', function () { From 909cbca7a63d2f328121c55d5eb032f4c0778605 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 19:59:24 -0700 Subject: [PATCH 091/246] build - remove copy debug --- gulpfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gulpfile.js b/gulpfile.js index a094356ac..739da162e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -350,7 +350,7 @@ function copyTask(opts){ return performCopy function performCopy(){ - let stream = gulp.src(source + pattern, { base: source }).pipe(debug({ title: source })) + let stream = gulp.src(source + pattern, { base: source }) destinations.forEach(function(destination) { stream = stream.pipe(gulp.dest(destination)) }) From e5c6c93c29f1747fa20d7d9fbace97c634442185 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 20:13:47 -0700 Subject: [PATCH 092/246] build - fix mascara sourcemaps dest --- gulpfile.js | 95 ++++++++++++++++++++++++++--------------------------- 1 file changed, 46 insertions(+), 49 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 739da162e..719a5c339 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,37 +1,37 @@ -var watchify = require('watchify') -var browserify = require('browserify') -var disc = require('disc') -var gulp = require('gulp') -var source = require('vinyl-source-stream') -var buffer = require('vinyl-buffer') -var gutil = require('gulp-util') -var watch = require('gulp-watch') -var sourcemaps = require('gulp-sourcemaps') -var jsoneditor = require('gulp-json-editor') -var zip = require('gulp-zip') -var assign = require('lodash.assign') -var livereload = require('gulp-livereload') -var del = require('del') -var eslint = require('gulp-eslint') -var fs = require('fs') -var path = require('path') -var manifest = require('./app/manifest.json') -var gulpif = require('gulp-if') -var replace = require('gulp-replace') -var mkdirp = require('mkdirp') -var asyncEach = require('async/each') -var exec = require('child_process').exec -var sass = require('gulp-sass') -var autoprefixer = require('gulp-autoprefixer') -var gulpStylelint = require('gulp-stylelint') -var stylefmt = require('gulp-stylefmt') -var uglify = require('gulp-uglify-es').default -var babel = require('gulp-babel') -var debug = require('gulp-debug') - - -var disableDebugTools = gutil.env.disableDebugTools -var debugMode = gutil.env.debug +const watchify = require('watchify') +const browserify = require('browserify') +const disc = require('disc') +const gulp = require('gulp') +const source = require('vinyl-source-stream') +const buffer = require('vinyl-buffer') +const gutil = require('gulp-util') +const watch = require('gulp-watch') +const sourcemaps = require('gulp-sourcemaps') +const jsoneditor = require('gulp-json-editor') +const zip = require('gulp-zip') +const assign = require('lodash.assign') +const livereload = require('gulp-livereload') +const del = require('del') +const eslint = require('gulp-eslint') +const fs = require('fs') +const path = require('path') +const manifest = require('./app/manifest.json') +const gulpif = require('gulp-if') +const replace = require('gulp-replace') +const mkdirp = require('mkdirp') +const asyncEach = require('async/each') +const exec = require('child_process').exec +const sass = require('gulp-sass') +const autoprefixer = require('gulp-autoprefixer') +const gulpStylelint = require('gulp-stylelint') +const stylefmt = require('gulp-stylefmt') +const uglify = require('gulp-uglify-es').default +const babel = require('gulp-babel') +const debug = require('gulp-debug') + + +const disableDebugTools = gutil.env.disableDebugTools +const debugMode = gutil.env.debug const browserPlatforms = [ 'firefox', @@ -240,13 +240,9 @@ function createTasksForBuildJsExtension({ jsFiles, taskPrefix, bundleTaskOpts }) const nonInpageFiles = jsFiles.filter(file => file !== 'inpage') const buildPhase1 = ['inpage'] const buildPhase2 = nonInpageFiles - const destinations = [ - './dist/firefox/scripts', - './dist/chrome/scripts', - './dist/edge/scripts', - './dist/opera/scripts', - ] - createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, buildPhase1, buildPhase2 }) + const destinations = browserPlatforms.map(platform => `./dist/${platform}/scripts`) + bundleTaskOpts.sourceMapDir = bundleTaskOpts.sourceMapDir || (debugMode ? './' : '../../sourcemaps') + createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, sourceMapDir, buildPhase1, buildPhase2 }) } function createTasksForBuildJsMascara({ taskPrefix, bundleTaskOpts }) { @@ -254,10 +250,11 @@ function createTasksForBuildJsMascara({ taskPrefix, bundleTaskOpts }) { const rootDir = './mascara/src/' const jsFiles = ['ui', 'proxy', 'background'] const destinations = ['./dist/mascara'] - createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, buildPhase1: jsFiles }) + bundleTaskOpts.sourceMapDir = bundleTaskOpts.sourceMapDir || (debugMode ? './' : '../sourcemaps') + createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, sourceMapDir, buildPhase1: jsFiles }) } -function createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, buildPhase1 = [], buildPhase2 = [] }) { +function createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, sourceMapDir, buildPhase1 = [], buildPhase2 = [] }) { // bundle task for each file jsFiles.forEach((jsFile) => { gulp.task(`${taskPrefix}:${jsFile}`, bundleTask(Object.assign({ @@ -298,7 +295,7 @@ gulp.task('zip:edge', zipTask('edge')) gulp.task('zip:opera', zipTask('opera')) gulp.task('zip', gulp.parallel('zip:chrome', 'zip:firefox', 'zip:edge', 'zip:opera')) -// set env var for production +// set env for production gulp.task('apply-prod-environment', function(done) { process.env.NODE_ENV = 'production' done() @@ -342,10 +339,10 @@ gulp.task('dist', // task generators function copyTask(opts){ - var source = opts.source - var destination = opts.destination - var destinations = opts.destinations || [ destination ] - var pattern = opts.pattern || '/**/*' + const source = opts.source + const destination = opts.destination + const destinations = opts.destinations || [ destination ] + const pattern = opts.pattern || '/**/*' return performCopy @@ -446,7 +443,7 @@ function bundleTask(opts) { mangle: { reserved: [ 'MetamaskInpageProvider' ] }, }))) // writes .map file - .pipe(sourcemaps.write(debugMode ? './' : '../../sourcemaps')) + .pipe(sourcemaps.write(opts.sourceMapDir)) // write completed bundles opts.destinations.forEach((dest) => { From 18acdfe6b3fecf5e681d584898ef8399c62b0fa5 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 20:41:56 -0700 Subject: [PATCH 093/246] build - refactor js build process --- gulpfile.js | 109 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 43 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 719a5c339..740b1a296 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -183,21 +183,6 @@ gulp.task('lint:fix', function () { .pipe(eslint.failAfterError()) }); -/* -gulp.task('default', ['lint'], function () { - // This will only run if the lint task is successful... -}); -*/ - -// build js - -const jsFiles = [ - 'inpage', - 'contentscript', - 'background', - 'ui', -] - // scss compilation and autoprefixing tasks gulp.task('build:scss', function () { @@ -229,33 +214,53 @@ gulp.task('fmt-scss', function () { .pipe(gulp.dest('ui/app/css/itcss')); }); +// build js + +const buildJsFiles = [ + 'inpage', + 'contentscript', + 'background', + 'ui', +] + // bundle tasks -createTasksForBuildJsExtension({ jsFiles, taskPrefix: 'dev:js', bundleTaskOpts: { isBuild: false } }) -createTasksForBuildJsExtension({ jsFiles, taskPrefix: 'build:js:extension', bundleTaskOpts: { isBuild: true } }) +createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'dev:js', devMode: true }) +createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'build:js:extension' }) createTasksForBuildJsMascara({ taskPrefix: 'build:js:mascara' }) -function createTasksForBuildJsExtension({ jsFiles, taskPrefix, bundleTaskOpts }) { +function createTasksForBuildJsExtension({ buildJsFiles, taskPrefix, devMode, bundleTaskOpts = {} }) { // inpage must be built before all other scripts: const rootDir = './app/scripts' - const nonInpageFiles = jsFiles.filter(file => file !== 'inpage') + const nonInpageFiles = buildJsFiles.filter(file => file !== 'inpage') const buildPhase1 = ['inpage'] const buildPhase2 = nonInpageFiles const destinations = browserPlatforms.map(platform => `./dist/${platform}/scripts`) - bundleTaskOpts.sourceMapDir = bundleTaskOpts.sourceMapDir || (debugMode ? './' : '../../sourcemaps') - createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, sourceMapDir, buildPhase1, buildPhase2 }) + bundleTaskOpts = Object.assign({ + buildSourceMaps: true, + sourceMapDir: devMode ? './' : '../../sourcemaps', + minifyBuild: !devMode, + buildWithFullPaths: devMode, + }, bundleTaskOpts) + createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1, buildPhase2 }) } -function createTasksForBuildJsMascara({ taskPrefix, bundleTaskOpts }) { +function createTasksForBuildJsMascara({ taskPrefix, devMode, bundleTaskOpts = {} }) { // inpage must be built before all other scripts: const rootDir = './mascara/src/' - const jsFiles = ['ui', 'proxy', 'background'] + const buildPhase1 = ['ui', 'proxy', 'background'] const destinations = ['./dist/mascara'] - bundleTaskOpts.sourceMapDir = bundleTaskOpts.sourceMapDir || (debugMode ? './' : '../sourcemaps') - createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, sourceMapDir, buildPhase1: jsFiles }) + bundleTaskOpts = Object.assign({ + buildSourceMaps: true, + sourceMapDir: './', + minifyBuild: !devMode, + buildWithFullPaths: devMode, + }, bundleTaskOpts) + createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1 }) } -function createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, destinations, sourceMapDir, buildPhase1 = [], buildPhase2 = [] }) { +function createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1 = [], buildPhase2 = [] }) { // bundle task for each file + const jsFiles = [].concat(buildPhase1, buildPhase2) jsFiles.forEach((jsFile) => { gulp.task(`${taskPrefix}:${jsFile}`, bundleTask(Object.assign({ watch: false, @@ -275,15 +280,14 @@ function createTasksForBuildJs({ rootDir, jsFiles, taskPrefix, bundleTaskOpts, d // disc bundle analyzer tasks -jsFiles.forEach((jsFile) => { - gulp.task(`disc:${jsFile}`, discTask({ label: jsFile, filename: `${jsFile}.js` })) +buildJsFiles.forEach((jsFile) => { + gulp.task(`disc:${jsFile}`, discTask({ label: jsFile, filename: `${jsFile}.js` })) }) -gulp.task('disc', gulp.parallel(jsFiles.map(jsFile => `disc:${jsFile}`))) +gulp.task('disc', gulp.parallel(buildJsFiles.map(jsFile => `disc:${jsFile}`))) // clean dist - gulp.task('clean', function clean() { return del(['./dist/*']) }) @@ -369,8 +373,8 @@ function generateBundler(opts, performBundle) { const browserifyOpts = assign({}, watchify.args, { entries: [opts.filepath], plugin: 'browserify-derequire', - debug: true, - fullPaths: debugMode, + debug: opts.buildSourceMaps, + fullPaths: opts.buildWithFullPaths, }) let bundler = browserify(browserifyOpts) @@ -385,6 +389,10 @@ function generateBundler(opts, performBundle) { } function discTask(opts) { + opts = Object.assign({ + buildWithFullPaths: true, + }, opts) + const bundler = generateBundler(opts, performBundle) // output build logs to terminal bundler.on('log', gutil.log) @@ -393,9 +401,9 @@ function discTask(opts) { function performBundle(){ // start "disc" build - let discDir = path.join(__dirname, 'disc') + const discDir = path.join(__dirname, 'disc') mkdirp.sync(discDir) - let discPath = path.join(discDir, `${opts.label}.html`) + const discPath = path.join(discDir, `${opts.label}.html`) return ( bundler.bundle() @@ -435,15 +443,30 @@ function bundleTask(opts) { .pipe(replace('\'GULP_METAMASK_DEBUG\'', debugMode)) // buffer file contents (?) .pipe(buffer()) - // sourcemaps - // loads map from browserify file - .pipe(sourcemaps.init({ loadMaps: true })) - // Minification - .pipe(gulpif(opts.isBuild, uglify({ - mangle: { reserved: [ 'MetamaskInpageProvider' ] }, - }))) - // writes .map file - .pipe(sourcemaps.write(opts.sourceMapDir)) + + + // Initialize Source Maps + if (opts.buildSourceMaps) { + buildStream = buildStream + // loads map from browserify file + .pipe(sourcemaps.init({ loadMaps: true })) + } + + // Minification + if (opts.minifyBuild) { + buildStream = buildStream + .pipe(uglify({ + mangle: { + reserved: [ 'MetamaskInpageProvider' ] + }, + })) + } + + // Finalize Source Maps (writes .map file) + if (opts.buildSourceMaps) { + buildStream = buildStream + .pipe(sourcemaps.write(opts.sourceMapDir)) + } // write completed bundles opts.destinations.forEach((dest) => { From b88119c23851144448771e8a6de97e48fb96b2b0 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 20:54:59 -0700 Subject: [PATCH 094/246] build - mascara - copy proxy html --- gulpfile.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 740b1a296..68618dfb4 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -78,6 +78,11 @@ gulp.task('copy:reload', copyTask({ destinations: commonPlatforms.map(platform => `./dist/${platform}/scripts`), pattern: '/chromereload.js', })) +gulp.task('copy:html', copyTask({ + source: './app/', + destinations: commonPlatforms.map(platform => `./dist/${platform}`), + pattern: '/*.html', +})) // copy extension @@ -86,10 +91,13 @@ gulp.task('copy:manifest', copyTask({ destinations: browserPlatforms.map(platform => `./dist/${platform}`), pattern: '/*.json', })) -gulp.task('copy:html', copyTask({ - source: './app/', - destinations: browserPlatforms.map(platform => `./dist/${platform}`), - pattern: '/*.html', + +// copy mascara + +gulp.task('copy:html:mascara', copyTask({ + source: './mascara/', + destinations: [`./dist/mascara/`], + pattern: 'proxy/index.html', })) // manifest tinkering @@ -143,6 +151,7 @@ const copyTaskNames = [ 'copy:fonts', 'copy:manifest', 'copy:html', + 'copy:html:mascara', 'copy:contractImages', ] From 253abd60fca5a6efb1a2e0ecbe305989a852ec32 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 21:29:57 -0700 Subject: [PATCH 095/246] build - extension - move js files to toplevel --- app/home.html | 2 +- app/manifest.json | 10 +++++----- app/notification.html | 2 +- app/popup.html | 2 +- app/scripts/contentscript.js | 6 +++--- gulpfile.js | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app/home.html b/app/home.html index bb8e936a3..4fad0f993 100644 --- a/app/home.html +++ b/app/home.html @@ -7,6 +7,6 @@
- + diff --git a/app/manifest.json b/app/manifest.json index a20f9b976..1982b4820 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -27,8 +27,8 @@ "default_locale": "en", "background": { "scripts": [ - "scripts/chromereload.js", - "scripts/background.js" + "chromereload.js", + "background.js" ], "persistent": true }, @@ -48,7 +48,7 @@ "https://*/*" ], "js": [ - "scripts/contentscript.js" + "contentscript.js" ], "run_at": "document_start", "all_frames": true @@ -62,11 +62,11 @@ "https://*.infura.io/" ], "web_accessible_resources": [ - "scripts/inpage.js" + "inpage.js" ], "externally_connectable": { "matches": [ "https://metamask.io/*" ] } -} \ No newline at end of file +} diff --git a/app/notification.html b/app/notification.html index 2255ca2c1..457ba7137 100644 --- a/app/notification.html +++ b/app/notification.html @@ -11,6 +11,6 @@
- + diff --git a/app/popup.html b/app/popup.html index 109487d3e..3acfd8c55 100644 --- a/app/popup.html +++ b/app/popup.html @@ -7,6 +7,6 @@
- + diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 7abbc60e7..2098fae27 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -7,8 +7,8 @@ const ObjectMultiplex = require('obj-multiplex') const extension = require('extensionizer') const PortStream = require('./lib/port-stream.js') -const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'scripts', 'inpage.js')).toString() -const inpageSuffix = '//# sourceURL=' + extension.extension.getURL('scripts/inpage.js') + '\n' +const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js')).toString() +const inpageSuffix = '//# sourceURL=' + extension.extension.getURL('inpage.js') + '\n' const inpageBundle = inpageContent + inpageSuffix // Eventually this streaming injection could be replaced with: @@ -96,7 +96,7 @@ function logStreamDisconnectWarning (remoteLabel, err) { } function shouldInjectWeb3 () { - return doctypeCheck() && suffixCheck() + return doctypeCheck() && suffixCheck() && documentElementCheck() && !blacklistedDomainCheck() } diff --git a/gulpfile.js b/gulpfile.js index 68618dfb4..cd523a107 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -75,7 +75,7 @@ gulp.task('copy:fonts', copyTask({ })) gulp.task('copy:reload', copyTask({ source: './app/scripts/', - destinations: commonPlatforms.map(platform => `./dist/${platform}/scripts`), + destinations: commonPlatforms.map(platform => `./dist/${platform}`), pattern: '/chromereload.js', })) gulp.task('copy:html', copyTask({ @@ -243,10 +243,10 @@ function createTasksForBuildJsExtension({ buildJsFiles, taskPrefix, devMode, bun const nonInpageFiles = buildJsFiles.filter(file => file !== 'inpage') const buildPhase1 = ['inpage'] const buildPhase2 = nonInpageFiles - const destinations = browserPlatforms.map(platform => `./dist/${platform}/scripts`) + const destinations = browserPlatforms.map(platform => `./dist/${platform}`) bundleTaskOpts = Object.assign({ buildSourceMaps: true, - sourceMapDir: devMode ? './' : '../../sourcemaps', + sourceMapDir: devMode ? './' : '../sourcemaps', minifyBuild: !devMode, buildWithFullPaths: devMode, }, bundleTaskOpts) From c9a47923042ca01c1968cf72e6d43d19890f4cd5 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 21:33:04 -0700 Subject: [PATCH 096/246] mascara - use sw-controller and other cleanups --- mascara/server/index.js | 3 ++- mascara/src/background.js | 16 +++++++----- mascara/src/proxy.js | 12 ++++----- mascara/src/ui.js | 54 +++++++++++++++++++++------------------ package.json | 5 ++-- 5 files changed, 50 insertions(+), 40 deletions(-) diff --git a/mascara/server/index.js b/mascara/server/index.js index 2ad8af242..2bc2441d0 100644 --- a/mascara/server/index.js +++ b/mascara/server/index.js @@ -23,7 +23,8 @@ function createMetamascaraServer () { serveBundle(server, '/metamascara.js', metamascaraBundle) serveBundle(server, '/scripts/ui.js', uiBundle) serveBundle(server, '/scripts/proxy.js', proxyBundle) - serveBundle(server, '/scripts/background.js', backgroundBuild) + // the serviceworker must be served from the root of the app + serveBundle(server, '/background.js', backgroundBuild) // serve assets server.use(express.static(path.join(__dirname, '/../ui/'), { setHeaders: (res) => res.set('X-Frame-Options', 'DENY') })) diff --git a/mascara/src/background.js b/mascara/src/background.js index 8aa1d8fe2..40a684f3d 100644 --- a/mascara/src/background.js +++ b/mascara/src/background.js @@ -30,15 +30,19 @@ global.addEventListener('activate', function (event) { log.debug('inside:open') - -// // state persistence +// state persistence const dbController = new DbController({ key: STORAGE_KEY, }) -loadStateFromPersistence() -.then((initState) => setupController(initState)) -.then(() => log.debug('MetaMask initialization complete.')) -.catch((err) => console.error('WHILE SETTING UP:', err)) + +start().catch(log.error) + +async function start() { + log.debug('MetaMask initializing...') + const initState = await loadStateFromPersistence() + await setupController(initState) + log.debug('MetaMask initialization complete.') +} // // State and Persistence diff --git a/mascara/src/proxy.js b/mascara/src/proxy.js index 3958f7d50..80b4dc516 100644 --- a/mascara/src/proxy.js +++ b/mascara/src/proxy.js @@ -1,13 +1,13 @@ const createParentStream = require('iframe-stream').ParentStream -const SWcontroller = require('client-sw-ready-event/lib/sw-client.js') +const SwController = require('sw-controller') const SwStream = require('sw-stream/lib/sw-stream.js') -const intervalDelay = Math.floor(Math.random() * (30000 - 1000)) + 1000 -const background = new SWcontroller({ +const keepAliveDelay = Math.floor(Math.random() * (30000 - 1000)) + 1000 +const background = new SwController({ fileName: './scripts/background.js', - letBeIdle: false, - wakeUpInterval: 30000, - intervalDelay, + keepAlive: true, + keepAliveInterval: 30000, + keepAliveDelay, }) const pageStream = createParentStream() diff --git a/mascara/src/ui.js b/mascara/src/ui.js index 21e5f32a9..f35a11fc4 100644 --- a/mascara/src/ui.js +++ b/mascara/src/ui.js @@ -1,6 +1,6 @@ const injectCss = require('inject-css') -const SWcontroller = require('client-sw-ready-event/lib/sw-client.js') -const SwStream = require('sw-stream/lib/sw-stream.js') +const SwController = require('sw-controller') +const SwStream = require('sw-stream') const MetaMaskUiCss = require('../../ui/css') const MetamascaraPlatform = require('../../app/scripts/platforms/window') const startPopup = require('../../app/scripts/popup-core') @@ -8,27 +8,44 @@ const startPopup = require('../../app/scripts/popup-core') // create platform global global.platform = new MetamascaraPlatform() - var css = MetaMaskUiCss() injectCss(css) const container = document.getElementById('app-content') -var name = 'popup' +const name = 'popup' window.METAMASK_UI_TYPE = name window.METAMASK_PLATFORM_TYPE = 'mascara' -const intervalDelay = Math.floor(Math.random() * (30000 - 1000)) + 1000 +const keepAliveDelay = Math.floor(Math.random() * (30000 - 1000)) + 1000 -const background = new SWcontroller({ - fileName: './scripts/background.js', - letBeIdle: false, - intervalDelay, - wakeUpInterval: 20000, +const swController = new SwController({ + fileName: './background.js', + keepAlive: true, + keepAliveDelay, + keepAliveInterval: 20000, }) + +swController.once('updatefound', windowReload) +swController.once('ready', async () => { + try { + swController.removeListener('updatefound', windowReload) + console.log('swController ready') + await timeout(1000) + console.log('connecting to app') + await connectApp() + console.log('app connected') + } catch (err) { + console.error(err) + } +}) + +console.log('starting service worker') +swController.startWorker() + // Setup listener for when the service worker is read -const connectApp = function (readSw) { +function connectApp() { const connectionStream = SwStream({ - serviceWorker: background.controller, + serviceWorker: swController.getWorker(), context: name, }) return new Promise((resolve, reject) => { @@ -43,19 +60,6 @@ const connectApp = function (readSw) { }) }) } -background.on('ready', async (sw) => { - try { - background.removeListener('updatefound', connectApp) - await timeout(1000) - await connectApp(sw) - console.log('hello from cb ready event!') - } catch (e) { - console.error(e) - } -}) -background.on('updatefound', windowReload) - -background.startWorker() function windowReload () { if (window.METAMASK_SKIP_RELOAD) return diff --git a/package.json b/package.json index 6cd8f7f4e..228f8b801 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,6 @@ "browserify-derequire": "^0.9.4", "browserify-unibabel": "^3.0.0", "classnames": "^2.2.5", - "client-sw-ready-event": "^3.3.0", "clone": "^2.1.1", "copy-to-clipboard": "^3.0.8", "debounce": "^1.0.0", @@ -118,6 +117,7 @@ "fuse.js": "^3.2.0", "gulp": "github:gulpjs/gulp#4.0", "gulp-autoprefixer": "^5.0.0", + "gulp-debug": "^3.2.0", "gulp-eslint": "^4.0.0", "gulp-sass": "^3.1.0", "hat": "0.0.3", @@ -180,7 +180,8 @@ "semaphore": "^1.0.5", "semver": "^5.4.1", "shallow-copy": "0.0.1", - "sw-stream": "^2.0.0", + "sw-controller": "^1.0.3", + "sw-stream": "^2.0.2", "textarea-caret": "^3.0.1", "through2": "^2.0.3", "valid-url": "^1.0.9", From 42d0b5f0ed7f3781d5551bc0b6af1e5f5c912ca5 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 21:35:59 -0700 Subject: [PATCH 097/246] deps - update pakage-lock --- package-lock.json | 107 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 97 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index f0f76919a..af80459af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3125,11 +3125,6 @@ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" }, - "client-sw-ready-event": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/client-sw-ready-event/-/client-sw-ready-event-3.4.0.tgz", - "integrity": "sha1-/0hkYXaQVed0hXDxrvECuGdbZtA=" - }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -8192,6 +8187,11 @@ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, + "get-own-enumerable-property-symbols": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz", + "integrity": "sha512-TtY/sbOemiMKPRUDDanGCSgBYe7Mf0vbRsWnBZ+9yghpZ1MvcpSpuZFjHdEeY/LZjZy0vdLjS77L6HosisFiug==" + }, "get-stdin": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-3.0.2.tgz", @@ -8628,6 +8628,52 @@ } } }, + "gulp-debug": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gulp-debug/-/gulp-debug-3.2.0.tgz", + "integrity": "sha512-2LZzP+ydczqz1rhqq/NYxvVvYTmOa0IgBl2B1sQTdkQgku9ayOUM/KHuGPjF4QA5aO1VcG+Sskw7iCcRUqHKkA==", + "requires": { + "chalk": "2.3.2", + "fancy-log": "1.3.2", + "plur": "2.1.2", + "stringify-object": "3.2.2", + "through2": "2.0.3", + "tildify": "1.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "requires": { + "has-flag": "3.0.0" + } + } + } + }, "gulp-eslint": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-4.0.0.tgz", @@ -10374,8 +10420,7 @@ "irregular-plurals": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.4.0.tgz", - "integrity": "sha1-LKmwM2UREYVUEvFr5dd8YqRYp2Y=", - "dev": true + "integrity": "sha1-LKmwM2UREYVUEvFr5dd8YqRYp2Y=" }, "is-absolute": { "version": "1.0.0", @@ -10603,6 +10648,11 @@ "integrity": "sha1-8mWrian0RQNO9q/xWo8AsA9VF5k=", "dev": true }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + }, "is-odd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-1.0.0.tgz", @@ -10695,8 +10745,7 @@ "is-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" }, "is-relative": { "version": "1.0.0", @@ -16675,7 +16724,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz", "integrity": "sha1-dIJFLBoPUI4+NE6uwxLJHCncZVo=", - "dev": true, "requires": { "irregular-plurals": "1.4.0" } @@ -19727,6 +19775,16 @@ "safe-buffer": "5.1.1" } }, + "stringify-object": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.2.2.tgz", + "integrity": "sha512-O696NF21oLiDy8PhpWu8AEqoZHw++QW6mUv0UvKZe8gWSdSvMXkiLufK7OmnP27Dro4GU5kb9U7JIO0mBuCRQg==", + "requires": { + "get-own-enumerable-property-symbols": "2.0.1", + "is-obj": "1.0.1", + "is-regexp": "1.0.0" + } + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", @@ -20333,6 +20391,27 @@ "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", "dev": true }, + "sw-controller": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sw-controller/-/sw-controller-1.0.3.tgz", + "integrity": "sha512-q+rS4v7kj1MPDxFRyl8GAICw/BbQzewd5HhVDNIPLnyvKtcpxi26fVXReUeUMRl4CRL/fX56PvKKqxtKhAaMpg==", + "requires": { + "babel-preset-es2015": "6.24.1", + "babel-runtime": "6.26.0", + "babelify": "7.3.0" + }, + "dependencies": { + "babelify": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "requires": { + "babel-core": "6.26.0", + "object-assign": "4.1.1" + } + } + } + }, "sw-stream": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/sw-stream/-/sw-stream-2.0.2.tgz", @@ -20797,6 +20876,14 @@ "dev": true, "optional": true }, + "tildify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", + "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", + "requires": { + "os-homedir": "1.0.2" + } + }, "time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", From fbdf497487e7d5b653d6eb36e92d917e935a6935 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 21:40:20 -0700 Subject: [PATCH 098/246] mascara - fix proxy html script link --- mascara/proxy/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mascara/proxy/index.html b/mascara/proxy/index.html index 0dff83f18..4e167db72 100644 --- a/mascara/proxy/index.html +++ b/mascara/proxy/index.html @@ -15,6 +15,6 @@ Hello! I am the MetaMask iframe. - + From 8760dc6bdac3e20a426853bc3f26b4b74a7bde95 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 21:53:08 -0700 Subject: [PATCH 099/246] ui - use relative url for i18n-helper fetching locales --- ui/i18n-helper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/i18n-helper.js b/ui/i18n-helper.js index 3ce24ddfb..db2fd2dc4 100644 --- a/ui/i18n-helper.js +++ b/ui/i18n-helper.js @@ -27,7 +27,7 @@ const getMessage = (locale, key, substitutions) => { function fetchLocale (localeName) { return new Promise((resolve, reject) => { - return fetch(`/_locales/${localeName}/messages.json`) + return fetch(`./_locales/${localeName}/messages.json`) .then(response => response.json()) .then( locale => resolve(locale), From cf82e766d4c08ee874e0c077d73186b5b134669f Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 22:21:49 -0700 Subject: [PATCH 100/246] ui - fix relative url for deposit-ether-modal --- ui/app/components/modals/deposit-ether-modal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index e38899d04..5af484af1 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -144,7 +144,7 @@ DepositEtherModal.prototype.render = function () { this.renderRow({ logo: h('img.deposit-ether-modal__logo', { - src: '../../../images/deposit-eth.svg', + src: './images/deposit-eth.svg', }), title: DIRECT_DEPOSIT_ROW_TITLE, text: DIRECT_DEPOSIT_ROW_TEXT, From 10609493c5a23a930dd8f7bda0435e576fd24815 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 22:30:35 -0700 Subject: [PATCH 101/246] ui - use relative location for images --- old-ui/app/app.js | 2 +- ui/app/app.js | 2 +- ui/app/components/modals/deposit-ether-modal.js | 4 ++-- ui/app/components/sender-to-recipient.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/old-ui/app/app.js b/old-ui/app/app.js index c79ac633a..e9ab185f3 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -171,7 +171,7 @@ App.prototype.renderAppBar = function () { h('img', { height: 24, width: 24, - src: '/images/icon-128.png', + src: './images/icon-128.png', }), h(NetworkIndicator, { diff --git a/ui/app/app.js b/ui/app/app.js index d23238bab..d658cf809 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -288,7 +288,7 @@ App.prototype.renderAppBar = function () { h('img.metafox-icon', { height: 42, width: 42, - src: '/images/metamask-fox.svg', + src: './images/metamask-fox.svg', }), // metamask name diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index 5af484af1..30be1d450 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -165,7 +165,7 @@ DepositEtherModal.prototype.render = function () { this.renderRow({ logo: h('div.deposit-ether-modal__logo', { style: { - backgroundImage: 'url(\'../../../images/coinbase logo.png\')', + backgroundImage: 'url(\'./images/coinbase logo.png\')', height: '40px', }, }), @@ -179,7 +179,7 @@ DepositEtherModal.prototype.render = function () { this.renderRow({ logo: h('div.deposit-ether-modal__logo', { style: { - backgroundImage: 'url(\'../../../images/shapeshift logo.png\')', + backgroundImage: 'url(\'./images/shapeshift logo.png\')', }, }), title: SHAPESHIFT_ROW_TITLE, diff --git a/ui/app/components/sender-to-recipient.js b/ui/app/components/sender-to-recipient.js index 4c3881668..299616612 100644 --- a/ui/app/components/sender-to-recipient.js +++ b/ui/app/components/sender-to-recipient.js @@ -46,7 +46,7 @@ class SenderToRecipient extends Component { h('img', { height: 15, width: 15, - src: '/images/arrow-right.svg', + src: './images/arrow-right.svg', }), ]), ]), From f9b680b09f3de33865371bb8430f1d62b5b19a1c Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 22:39:45 -0700 Subject: [PATCH 102/246] ui - identicon - use relative link for ether logo --- ui/app/components/identicon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index 6b2a1b428..96bb89f5f 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -47,7 +47,7 @@ IdenticonComponent.prototype.render = function () { ) : ( h('img.balance-icon', { - src: '../images/eth_logo.svg', + src: './images/eth_logo.svg', style: { height: diameter, width: diameter, From 86c7c6746d64e8c9a32010520d49fc34c5e2edba Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 23:11:07 -0700 Subject: [PATCH 103/246] build - refactor copy and copy:watch (renamed to copy:dev) --- gulpfile.js | 106 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 44 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index cd523a107..d6892cc7e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -54,51 +54,65 @@ gulp.task('dev:reload', function() { }) }) - // copy universal -gulp.task('copy:locales', copyTask({ +const copyTaskNames = [] +const copyDevTaskNames = [] + +createCopyTasks('locales', { source: './app/_locales/', destinations: commonPlatforms.map(platform => `./dist/${platform}/_locales`), -})) -gulp.task('copy:images', copyTask({ +}) +createCopyTasks('images', { source: './app/images/', destinations: commonPlatforms.map(platform => `./dist/${platform}/images`), -})) -gulp.task('copy:contractImages', copyTask({ - source: './node_modules/eth-contract-metadata/images/', +}) +createCopyTasks('contractImages', { + source: `${require.resolve('eth-contract-metadata')}/images/`, destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contract`), -})) -gulp.task('copy:fonts', copyTask({ +}) +createCopyTasks('fonts', { source: './app/fonts/', destinations: commonPlatforms.map(platform => `./dist/${platform}/fonts`), -})) -gulp.task('copy:reload', copyTask({ +}) +createCopyTasks('reload', { + devOnly: true, source: './app/scripts/', - destinations: commonPlatforms.map(platform => `./dist/${platform}`), pattern: '/chromereload.js', -})) -gulp.task('copy:html', copyTask({ - source: './app/', destinations: commonPlatforms.map(platform => `./dist/${platform}`), +}) +createCopyTasks('html', { + source: './app/', pattern: '/*.html', -})) + destinations: commonPlatforms.map(platform => `./dist/${platform}`), +}) // copy extension -gulp.task('copy:manifest', copyTask({ +createCopyTasks('manifest', { source: './app/', - destinations: browserPlatforms.map(platform => `./dist/${platform}`), pattern: '/*.json', -})) + destinations: browserPlatforms.map(platform => `./dist/${platform}`), +}) // copy mascara -gulp.task('copy:html:mascara', copyTask({ +createCopyTasks('html:mascara', { source: './mascara/', - destinations: [`./dist/mascara/`], pattern: 'proxy/index.html', -})) + destinations: [`./dist/mascara/`], +}) + +function createCopyTasks(label, opts) { + if (!opts.devOnly) { + const copyTaskName = `copy:${label}` + copyTask(copyTaskName, opts) + copyTaskNames.push(copyTaskName) + } + const copyDevTaskName = `copy:dev:${label}` + copyTask(copyDevTaskName, Object.assign({ devMode: true }, opts)) + copyDevTaskNames.push(copyDevTaskName) +} // manifest tinkering @@ -145,20 +159,6 @@ gulp.task('manifest:production', function() { .pipe(gulp.dest('./dist/', { overwrite: true })) }) -const copyTaskNames = [ - 'copy:locales', - 'copy:images', - 'copy:fonts', - 'copy:manifest', - 'copy:html', - 'copy:html:mascara', - 'copy:contractImages', -] - -if (debugMode) { - copyTaskNames.push('copy:reload') -} - gulp.task('copy', gulp.series( gulp.parallel(...copyTaskNames), @@ -167,9 +167,14 @@ gulp.task('copy', 'manifest:opera' ) ) -gulp.task('copy:watch', function(){ - gulp.watch(['./app/{_locales,images}/*', './app/scripts/chromereload.js', './app/*.{html,json}'], gulp.series('copy')) -}) + +gulp.task('copy:dev', + gulp.series( + gulp.parallel(...copyDevTaskNames), + 'manifest:chrome', + 'manifest:opera' + ) +) // lint js @@ -323,7 +328,7 @@ gulp.task('dev', 'copy', gulp.parallel( 'watch:scss', - 'copy:watch', + 'copy:dev', 'dev:reload' ) ) @@ -351,20 +356,33 @@ gulp.task('dist', // task generators -function copyTask(opts){ +function copyTask(taskName, opts){ const source = opts.source const destination = opts.destination const destinations = opts.destinations || [ destination ] const pattern = opts.pattern || '/**/*' + const devMode = opts.devMode - return performCopy + return gulp.task(taskName, performCopy) function performCopy(){ - let stream = gulp.src(source + pattern, { base: source }) + // stream from source + let stream + if (devMode) { + stream = watch(source + pattern, { base: source }) + } else { + stream = gulp.src(source + pattern, { base: source }) + } + + // copy to destinations destinations.forEach(function(destination) { stream = stream.pipe(gulp.dest(destination)) }) - stream.pipe(gulpif(debugMode,livereload())) + + // trigger reload + if (devMode) { + stream.pipe(livereload()) + } return stream } From ac4cb3444df5753da6e10f607466e232afa538a2 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 23:11:41 -0700 Subject: [PATCH 104/246] ui - add guard against unset locale --- ui/app/settings.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/app/settings.js b/ui/app/settings.js index 8764dcafe..171264ed4 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -108,11 +108,12 @@ class Settings extends Component { renderCurrentLocale () { const { updateCurrentLocale, currentLocale } = this.props const currentLocaleMeta = locales.find(locale => locale.code === currentLocale) + const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name || '' return h('div.settings__content-row', [ h('div.settings__content-item', [ h('span', 'Current Language'), - h('span.settings__content-description', `${currentLocaleMeta.name}`), + h('span.settings__content-description', `${currentLocaleName}`), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ From d2874cf89aa389b3b16f432781be731f88737f21 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 23:12:41 -0700 Subject: [PATCH 105/246] deps - update package-lock --- package-lock.json | 312 +++++++++++++++++++++++++++++++++------------- package.json | 2 +- 2 files changed, 226 insertions(+), 88 deletions(-) diff --git a/package-lock.json b/package-lock.json index af80459af..504f2f1d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9250,7 +9250,7 @@ "dev": true, "requires": { "anymatch": "1.3.2", - "chokidar": "2.0.1", + "chokidar": "2.0.3", "glob-parent": "3.1.0", "gulp-util": "3.0.8", "object-assign": "4.1.1", @@ -9274,9 +9274,9 @@ "dev": true }, "braces": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.0.tgz", - "integrity": "sha512-P4O8UQRdGiMLWSizsApmXVQDBS6KCt7dSexgLKBmH5Hr1CZq7vsnscFh8oR1sP1ab1Zj0uCHCEzZeV6SfUf3rA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.1.tgz", + "integrity": "sha512-SO5lYHA3vO6gz66erVvedSCkp7AKWdv6VcQ2N4ysXfPxdAlxAMMAdwegGGcv1Bqwm7naF1hNdk5d6AAIEHV2nQ==", "dev": true, "requires": { "arr-flatten": "1.1.0", @@ -9285,22 +9285,43 @@ "extend-shallow": "2.0.1", "fill-range": "4.0.0", "isobject": "3.0.1", + "kind-of": "6.0.2", "repeat-element": "1.1.2", "snapdragon": "0.8.1", "snapdragon-node": "2.1.1", "split-string": "3.1.0", - "to-regex": "3.0.1" + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } } }, "chokidar": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.1.tgz", - "integrity": "sha512-rv5iP8ENhpqvDWr677rAXcB+SMoPQ1urd4ch79+PhM4lQwbATdJUQK69t0lJIKNB+VXpqxt5V1gvqs59XEPKnw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz", + "integrity": "sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==", "dev": true, "requires": { "anymatch": "2.0.0", "async-each": "1.0.1", - "braces": "2.3.0", + "braces": "2.3.1", "fsevents": "1.1.3", "glob-parent": "3.1.0", "inherits": "2.0.3", @@ -9309,7 +9330,7 @@ "normalize-path": "2.1.1", "path-is-absolute": "1.0.1", "readdirp": "2.1.0", - "upath": "1.0.0" + "upath": "1.0.4" }, "dependencies": { "anymatch": { @@ -9318,12 +9339,22 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "micromatch": "3.1.5", + "micromatch": "3.1.10", "normalize-path": "2.1.1" } } } }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "1.0.2", + "isobject": "3.0.1" + } + }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -9336,7 +9367,7 @@ "posix-character-classes": "0.1.1", "regex-not": "1.0.0", "snapdragon": "0.8.1", - "to-regex": "3.0.1" + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -9347,6 +9378,53 @@ "requires": { "is-descriptor": "0.1.6" } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "2.0.4" + } } } }, @@ -9363,7 +9441,27 @@ "fragment-cache": "0.2.1", "regex-not": "1.0.0", "snapdragon": "0.8.1", - "to-regex": "3.0.1" + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } } }, "fill-range": { @@ -9376,6 +9474,17 @@ "is-number": "3.0.0", "repeat-string": "1.6.1", "to-regex-range": "2.1.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } } }, "glob-parent": { @@ -9439,25 +9548,6 @@ } } }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -9506,24 +9596,48 @@ "dev": true }, "micromatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.5.tgz", - "integrity": "sha512-ykttrLPQrz1PUJcXjwsTUjGoPJ64StIGNE2lGVD1c9CuguJ+L7/navsE8IcDNndOoCMvYV0qc/exfVbMHkUhvA==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { "arr-diff": "4.0.0", "array-unique": "0.3.2", - "braces": "2.3.0", - "define-property": "1.0.0", - "extend-shallow": "2.0.1", + "braces": "2.3.1", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", "extglob": "2.0.4", "fragment-cache": "0.2.1", "kind-of": "6.0.2", - "nanomatch": "1.2.7", + "nanomatch": "1.2.9", "object.pick": "1.3.0", "regex-not": "1.0.0", "snapdragon": "0.8.1", - "to-regex": "3.0.1" + "to-regex": "3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" + }, + "dependencies": { + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" + } + } } } } @@ -10654,22 +10768,19 @@ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" }, "is-odd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-1.0.0.tgz", - "integrity": "sha1-O4qTLrAos3dcObsJ6RdnrM22kIg=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", + "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", "dev": true, "requires": { - "is-number": "3.0.0" + "is-number": "4.0.0" }, "dependencies": { "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true } } }, @@ -13638,18 +13749,19 @@ "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=" }, "nanomatch": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.7.tgz", - "integrity": "sha512-/5ldsnyurvEw7wNpxLFgjVvBLMta43niEYOy0CJ4ntcYSbx6bugRUTQeFb4BR/WanEL1o3aQgHuVLHQaB6tOqg==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", + "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", "dev": true, "requires": { "arr-diff": "4.0.0", "array-unique": "0.3.2", - "define-property": "1.0.0", - "extend-shallow": "2.0.1", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", "fragment-cache": "0.2.1", - "is-odd": "1.0.0", - "kind-of": "5.1.0", + "is-odd": "2.0.0", + "is-windows": "1.0.2", + "kind-of": "6.0.2", "object.pick": "1.3.0", "regex-not": "1.0.0", "snapdragon": "0.8.1", @@ -13668,10 +13780,45 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "1.0.2", + "isobject": "3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "2.0.4" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } @@ -18382,6 +18529,15 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "0.1.15" + } + }, "samsam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", @@ -21331,12 +21487,6 @@ "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", "dev": true }, - "underscore.string": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", - "dev": true - }, "undertaker": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.0.tgz", @@ -21497,22 +21647,10 @@ } }, "upath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.0.tgz", - "integrity": "sha1-tHBrlGHKhHOt+JEz0jVonKF/NlY=", - "dev": true, - "requires": { - "lodash": "3.10.1", - "underscore.string": "2.3.3" - }, - "dependencies": { - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", - "dev": true - } - } + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.4.tgz", + "integrity": "sha512-d4SJySNBXDaQp+DPrziv3xGS6w3d2Xt69FijJr86zMPBy23JEloMCEOUBBzuN7xCtjLCnmB9tI/z7SBCahHBOw==", + "dev": true }, "urix": { "version": "0.1.0", @@ -21800,9 +21938,9 @@ }, "dependencies": { "clone": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", - "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", "dev": true }, "clone-stats": { @@ -21829,7 +21967,7 @@ "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, "requires": { - "clone": "1.0.3", + "clone": "1.0.4", "clone-stats": "0.0.1", "replace-ext": "0.0.1" } diff --git a/package.json b/package.json index 228f8b801..21cc2678d 100644 --- a/package.json +++ b/package.json @@ -259,8 +259,8 @@ "react-addons-test-utils": "^15.5.1", "react-test-renderer": "^15.6.2", "react-testutils-additions": "^15.2.0", - "selenium-webdriver": "^3.5.0", "redux-test-utils": "^0.2.2", + "selenium-webdriver": "^3.5.0", "sinon": "^5.0.0", "stylelint-config-standard": "^18.2.0", "tape": "^4.5.1", From 28306cc453477c318de99a38abfc3daa976dd173 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 23:15:00 -0700 Subject: [PATCH 106/246] ci - artifacts - simplify result path --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index ac05e747c..d82ab3bc7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -100,6 +100,7 @@ jobs: - dist - store_artifacts: path: dist/mascara + destination: build - run: name: build:announce command: | From 085e7d7dec1cdd05069db1fb7afa797c6be2f6ad Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 23:19:07 -0700 Subject: [PATCH 107/246] ui - fix typo in settings --- ui/app/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/settings.js b/ui/app/settings.js index 171264ed4..ec24172e8 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -108,7 +108,7 @@ class Settings extends Component { renderCurrentLocale () { const { updateCurrentLocale, currentLocale } = this.props const currentLocaleMeta = locales.find(locale => locale.code === currentLocale) - const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name || '' + const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name : '' return h('div.settings__content-row', [ h('div.settings__content-item', [ From 399381f9d255ff45a824f3c00494dcec63d90076 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 23:26:58 -0700 Subject: [PATCH 108/246] ci - upload whole dist + fix announce mascara url --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d82ab3bc7..fb274d0d6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -99,14 +99,14 @@ jobs: paths: - dist - store_artifacts: - path: dist/mascara - destination: build + path: dist + destination: builds - run: name: build:announce command: | CIRCLE_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}" SHORT_SHA1=$(echo $CIRCLE_SHA1 | cut -c 1-7) - QA_BUILD_URL="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0/home/circleci/project/dist/mascara/home.html" + QA_BUILD_URL="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0/builds/mascara/home.html" COMMENT_BODY="[Try QA Build for $SHORT_SHA1]($QA_BUILD_URL)" JSON_PAYLOAD="{\"body\":\"$COMMENT_BODY\"}" POST_COMMENT_URI="https://api.github.com/repos/metamask/metamask-extension/issues/$CIRCLE_PR_NUMBER/comments" From e7f655ec6da79035179323a9ebe63a93677b1649 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 23:45:33 -0700 Subject: [PATCH 109/246] npm scripts - simplify and speed up dist builds --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 21cc2678d..2dd63c1d1 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,7 @@ "mock": "beefy development/mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./", "watch": "mocha watch --recursive \"test/unit/**/*.js\"", "mascara": "gulp build && cross-env METAMASK_DEBUG=true node ./mascara/example/server", - "dist": "npm run dist:clear && npm install && gulp dist", - "dist:clear": "rm -rf node_modules/eth-contract-metadata && rm -rf node_modules/eth-phishing-detect", + "dist": "gulp dist", "test": "npm run test:unit && npm run test:integration && npm run lint", "test:unit": "cross-env METAMASK_ENV=test mocha --exit --require babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"", "test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js", From 93ac72801afb318c6003e4d8ff2f22af06356ac8 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 28 Mar 2018 23:47:11 -0700 Subject: [PATCH 110/246] ci - artifacts - upload extension builds, dont upload extension source --- .circleci/config.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fb274d0d6..0173b8b3d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -99,7 +99,10 @@ jobs: paths: - dist - store_artifacts: - path: dist + path: dist/mascara + destination: builds/mascara + - store_artifacts: + path: builds destination: builds - run: name: build:announce From ec608cb1b0bca09ddeb33f6c54146b3ab90925a8 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 00:17:14 -0700 Subject: [PATCH 111/246] ci - build:announce - link all builds --- .circleci/config.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0173b8b3d..5e84fb783 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -109,8 +109,15 @@ jobs: command: | CIRCLE_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}" SHORT_SHA1=$(echo $CIRCLE_SHA1 | cut -c 1-7) - QA_BUILD_URL="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0/builds/mascara/home.html" - COMMENT_BODY="[Try QA Build for $SHORT_SHA1]($QA_BUILD_URL)" + BUILD_LINK_BASE="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0/builds" + MASCARA="BUILD_LINK_BASE/mascara/home.html" + CHROME="BUILD_LINK_BASE/chrome.zip" + FIREFOX="BUILD_LINK_BASE/firefox.zip" + OPERA="BUILD_LINK_BASE/opera.zip" + EDGE="BUILD_LINK_BASE/edge.zip" + COMMENT_MAIN="Builds ready [$SHORT_SHA1]: [mascara][mascara], [chrome][chrome], [firefox][firefox], [edge][edge], [opera][opera]" + COMMENT_LINKS="[mascara]:$MASCARA\n[chrome]:$CHROME\n[firefox]:$FIREFOX\n[opera]:$OPERA\n[edge]:$EDGE\n" + COMMENT_BODY="$COMMENT_MAIN\n\n$COMMENT_LINKS" JSON_PAYLOAD="{\"body\":\"$COMMENT_BODY\"}" POST_COMMENT_URI="https://api.github.com/repos/metamask/metamask-extension/issues/$CIRCLE_PR_NUMBER/comments" echo "Announcement:\n$COMMENT_BODY" From 001595b2b9e0a06b3e16033143128620ead544bc Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 00:24:50 -0700 Subject: [PATCH 112/246] ci - build:announce - fix link --- .circleci/config.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5e84fb783..fa694dcff 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -110,11 +110,11 @@ jobs: CIRCLE_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}" SHORT_SHA1=$(echo $CIRCLE_SHA1 | cut -c 1-7) BUILD_LINK_BASE="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0/builds" - MASCARA="BUILD_LINK_BASE/mascara/home.html" - CHROME="BUILD_LINK_BASE/chrome.zip" - FIREFOX="BUILD_LINK_BASE/firefox.zip" - OPERA="BUILD_LINK_BASE/opera.zip" - EDGE="BUILD_LINK_BASE/edge.zip" + MASCARA="$BUILD_LINK_BASE/mascara/home.html" + CHROME="$BUILD_LINK_BASE/chrome.zip" + FIREFOX="$BUILD_LINK_BASE/firefox.zip" + OPERA="$BUILD_LINK_BASE/opera.zip" + EDGE="$BUILD_LINK_BASE/edge.zip" COMMENT_MAIN="Builds ready [$SHORT_SHA1]: [mascara][mascara], [chrome][chrome], [firefox][firefox], [edge][edge], [opera][opera]" COMMENT_LINKS="[mascara]:$MASCARA\n[chrome]:$CHROME\n[firefox]:$FIREFOX\n[opera]:$OPERA\n[edge]:$EDGE\n" COMMENT_BODY="$COMMENT_MAIN\n\n$COMMENT_LINKS" From 93c123c6f52b28b525658492ce93fbcc30fc1e7c Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 00:34:01 -0700 Subject: [PATCH 113/246] ci - build:announce - fix links to extension builds --- .circleci/config.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fa694dcff..bb14d2a3a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -110,11 +110,12 @@ jobs: CIRCLE_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}" SHORT_SHA1=$(echo $CIRCLE_SHA1 | cut -c 1-7) BUILD_LINK_BASE="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0/builds" + VERSION=$(node -p 'require("./dist/chrome/manifest.json").version') MASCARA="$BUILD_LINK_BASE/mascara/home.html" - CHROME="$BUILD_LINK_BASE/chrome.zip" - FIREFOX="$BUILD_LINK_BASE/firefox.zip" - OPERA="$BUILD_LINK_BASE/opera.zip" - EDGE="$BUILD_LINK_BASE/edge.zip" + CHROME="$BUILD_LINK_BASE/metamask-chrome-$VERSION.zip" + FIREFOX="$BUILD_LINK_BASE/metamask-firefox-$VERSION.zip" + OPERA="$BUILD_LINK_BASE/metamask-opera-$VERSION.zip" + EDGE="$BUILD_LINK_BASE/metamask-edge-$VERSION.zip" COMMENT_MAIN="Builds ready [$SHORT_SHA1]: [mascara][mascara], [chrome][chrome], [firefox][firefox], [edge][edge], [opera][opera]" COMMENT_LINKS="[mascara]:$MASCARA\n[chrome]:$CHROME\n[firefox]:$FIREFOX\n[opera]:$OPERA\n[edge]:$EDGE\n" COMMENT_BODY="$COMMENT_MAIN\n\n$COMMENT_LINKS" From 1b2674119ec5d63b75cb118949297f3c6e9d362b Mon Sep 17 00:00:00 2001 From: FBrinkkemper Date: Thu, 29 Mar 2018 12:30:59 +0200 Subject: [PATCH 114/246] changed zaad -> back-up woorden Zaad sounds strange in Dutch. Back-up woorden (back-up words) are a better translation in Dutch. Back-up is also a Dutch phrase, like it is in English. --- app/_locales/nl/messages.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json index aacb81fee..487002add 100644 --- a/app/_locales/nl/messages.json +++ b/app/_locales/nl/messages.json @@ -299,7 +299,7 @@ "message": "De gaslimiet moet minstens 21000 zijn" }, "generatingSeed": { - "message": "Zaad produceren ..." + "message": "Back-up woorden produceren ..." }, "gasPrice": { "message": "Gasprijs (GWEI)" @@ -432,7 +432,7 @@ "message": "Los" }, "loweCaseWords": { - "message": "zaadwoorden hebben alleen kleine letters" + "message": "back-up woorden hebben alleen kleine letters" }, "mainnet": { "message": "belangrijkste ethereum-netwerk" @@ -532,7 +532,7 @@ "description": "Voor het importeren van een account vanaf een privésleutel" }, "pasteSeed": { - "message": "Plak je zaadzin hier!" + "message": "Plak je back-up woorden hier!" }, "personalAddressDetected": { "message": "Persoonlijk adres gedetecteerd. Voer het tokencontractadres in." @@ -581,7 +581,7 @@ "message": "Account opnieuw instellen" }, "restoreFromSeed": { - "message": "Herstel van zaaduitdrukking" + "message": "Herstel vanuit back-up woorden" }, "required": { "message": "Verplicht" @@ -590,10 +590,10 @@ "message": "Probeer hier opnieuw met een hogere gasprijs" }, "revealSeedWords": { - "message": "Onthul zaadwoorden" + "message": "Onthul back-up woorden" }, "revealSeedWordsWarning": { - "message": "Herstel je zaadwoorden niet op een openbare plaats! Deze woorden kunnen worden gebruikt om al uw accounts te stelen." + "message": "Zorg dat je back-up woorden niet op een openbare plaats bekijkt! Deze woorden kunnen worden gebruikt om al uw accounts opnieuw te genereren (en dus uw account te stelen)." }, "revert": { "message": "terugkeren" @@ -616,7 +616,7 @@ "description": "Account export proces" }, "saveSeedAsFile": { - "message": "Bewaar zaadwoorden als bestand" + "message": "Bewaar back-up woorden als bestand" }, "search": { "message": "Zoeken" @@ -625,7 +625,7 @@ "message": "Voer hier je geheime twaalfwoordfrase in om je kluis te herstellen." }, "seedPhraseReq": { - "message": "zaadzinnen zijn 12 woorden lang" + "message": "Back-up woorden zijn 12 woorden lang" }, "select": { "message": "kiezen" From 01e3293b65bb153325479f7366113e037fee659b Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 29 Mar 2018 10:32:30 -0230 Subject: [PATCH 115/246] Ensure correct address used when rendering transfer transactions. --- ui/app/components/tx-list-item.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index a411edd89..116813547 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -71,7 +71,8 @@ TxListItem.prototype.getAddressText = function () { let addressText if (txDataName === 'transfer' || address) { - addressText = `${value.slice(0, 10)}...${value.slice(-4)}` + const addressToRender = txDataName === 'transfer' ? value : address + addressText = `${addressToRender.slice(0, 10)}...${addressToRender.slice(-4)}` } else if (isMsg) { addressText = this.props.t('sigRequest') } else { From 0a711f0de0e342b24988a5da4ca5c64342153210 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 29 Mar 2018 12:30:44 -0230 Subject: [PATCH 116/246] Removes t from props via metamask-connect and instead places it on context via a provider. --- ui/app/accounts/import/index.js | 22 +++-- ui/app/accounts/import/json.js | 25 +++--- ui/app/accounts/import/private-key.js | 14 +++- ui/app/accounts/import/seed.js | 12 ++- ui/app/accounts/new-account/create-form.js | 17 ++-- ui/app/accounts/new-account/index.js | 14 +++- ui/app/add-token.js | 56 +++++++------ ui/app/app.js | 32 +++++--- ui/app/components/account-dropdowns.js | 20 +++-- ui/app/components/account-export.js | 22 +++-- ui/app/components/account-menu/index.js | 22 +++-- ui/app/components/balance-component.js | 2 +- ui/app/components/bn-as-decimal-input.js | 16 ++-- ui/app/components/buy-button-subview.js | 22 +++-- ui/app/components/coinbase-form.js | 12 ++- ui/app/components/copyButton.js | 10 ++- ui/app/components/copyable.js | 10 ++- .../components/customize-gas-modal/index.js | 28 ++++--- .../dropdowns/components/account-dropdowns.js | 25 +++--- .../components/dropdowns/network-dropdown.js | 34 ++++---- .../dropdowns/token-menu-dropdown.js | 10 ++- ui/app/components/ens-input.js | 12 ++- ui/app/components/hex-as-decimal-input.js | 16 ++-- ui/app/components/identicon.js | 2 +- .../modals/account-details-modal.js | 12 ++- .../modals/account-modal-container.js | 10 ++- ui/app/components/modals/buy-options-modal.js | 22 +++-- .../components/modals/deposit-ether-modal.js | 38 +++++---- .../modals/edit-account-name-modal.js | 12 ++- .../modals/export-private-key-modal.js | 20 +++-- .../modals/hide-token-confirmation-modal.js | 16 ++-- ui/app/components/modals/new-account-modal.js | 21 +++-- .../components/modals/notification-modal.js | 11 ++- .../confirm-reset-account.js | 2 +- .../modals/shapeshift-deposit-tx-modal.js | 2 +- ui/app/components/network-display.js | 9 ++- ui/app/components/network.js | 33 +++++--- ui/app/components/notice.js | 10 ++- ui/app/components/pending-msg-details.js | 10 ++- ui/app/components/pending-msg.js | 18 +++-- .../pending-tx/confirm-deploy-contract.js | 32 ++++---- .../pending-tx/confirm-send-ether.js | 26 +++--- .../pending-tx/confirm-send-token.js | 42 +++++----- ui/app/components/pending-tx/index.js | 2 +- ui/app/components/qr-code.js | 2 +- ui/app/components/send/account-list-item.js | 2 +- ui/app/components/send/gas-fee-display-v2.js | 12 ++- ui/app/components/send/gas-tooltip.js | 10 ++- ui/app/components/send/send-v2-container.js | 2 +- ui/app/components/send/to-autocomplete.js | 10 ++- ui/app/components/sender-to-recipient.js | 9 ++- ui/app/components/shapeshift-form.js | 28 ++++--- ui/app/components/shift-list-item.js | 22 +++-- ui/app/components/signature-request.js | 28 ++++--- ui/app/components/token-balance.js | 2 +- ui/app/components/token-cell.js | 2 +- ui/app/components/token-list.js | 14 +++- ui/app/components/tx-list-item.js | 26 +++--- ui/app/components/tx-list.js | 14 +++- ui/app/components/tx-view.js | 14 +++- ui/app/components/wallet-view.js | 16 ++-- ui/app/conf-tx.js | 2 +- ui/app/first-time/init-menu.js | 26 +++--- ui/app/i18n-provider.js | 37 +++++++++ ui/app/keychains/hd/create-vault-complete.js | 2 +- .../keychains/hd/recover-seed/confirmation.js | 15 ++-- ui/app/keychains/hd/restore-vault.js | 32 +++++--- ui/app/new-keychain.js | 2 +- ui/app/root.js | 3 +- ui/app/select-app.js | 2 +- ui/app/send-v2.js | 33 ++++---- ui/app/settings.js | 81 ++++++++++--------- ui/app/unlock.js | 16 ++-- 73 files changed, 817 insertions(+), 450 deletions(-) create mode 100644 ui/app/i18n-provider.js diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js index b09b50ef7..52d3dcde9 100644 --- a/ui/app/accounts/import/index.js +++ b/ui/app/accounts/import/index.js @@ -1,7 +1,8 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('../../metamask-connect') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect import Select from 'react-select' // Subviews @@ -9,8 +10,13 @@ const JsonImportView = require('./json.js') const PrivateKeyImportView = require('./private-key.js') +AccountImportSubview.contextTypes = { + t: PropTypes.func, +} + module.exports = connect()(AccountImportSubview) + inherits(AccountImportSubview, Component) function AccountImportSubview () { Component.call(this) @@ -18,8 +24,8 @@ function AccountImportSubview () { AccountImportSubview.prototype.getMenuItemTexts = function () { return [ - this.props.t('privateKey'), - this.props.t('jsonFile'), + this.context.t('privateKey'), + this.context.t('jsonFile'), ] } @@ -32,7 +38,7 @@ AccountImportSubview.prototype.render = function () { h('div.new-account-import-form', [ h('.new-account-import-disclaimer', [ - h('span', this.props.t('importAccountMsg')), + h('span', this.context.t('importAccountMsg')), h('span', { style: { cursor: 'pointer', @@ -43,12 +49,12 @@ AccountImportSubview.prototype.render = function () { url: 'https://metamask.helpscoutdocs.com/article/17-what-are-loose-accounts', }) }, - }, this.props.t('here')), + }, this.context.t('here')), ]), h('div.new-account-import-form__select-section', [ - h('div.new-account-import-form__select-label', this.props.t('selectType')), + h('div.new-account-import-form__select-label', this.context.t('selectType')), h(Select, { className: 'new-account-import-form__select', @@ -80,9 +86,9 @@ AccountImportSubview.prototype.renderImportView = function () { const current = type || menuItems[0] switch (current) { - case this.props.t('privateKey'): + case this.context.t('privateKey'): return h(PrivateKeyImportView) - case this.props.t('jsonFile'): + case this.context.t('jsonFile'): return h(JsonImportView) default: return h(JsonImportView) diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index 02b64858d..e53c1c9ca 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -1,7 +1,7 @@ const Component = require('react').Component const PropTypes = require('prop-types') const h = require('react-hyperscript') -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') const FileInput = require('react-simple-file-input').default @@ -24,11 +24,11 @@ class JsonImportSubview extends Component { return ( h('div.new-account-import-form__json', [ - h('p', this.props.t('usedByClients')), + h('p', this.context.t('usedByClients')), h('a.warning', { href: HELP_LINK, target: '_blank', - }, this.props.t('fileImportFail')), + }, this.context.t('fileImportFail')), h(FileInput, { readAs: 'text', @@ -43,7 +43,7 @@ class JsonImportSubview extends Component { h('input.new-account-import-form__input-password', { type: 'password', - placeholder: this.props.t('enterPassword'), + placeholder: this.context.t('enterPassword'), id: 'json-password-box', onKeyPress: this.createKeyringOnEnter.bind(this), }), @@ -53,13 +53,13 @@ class JsonImportSubview extends Component { h('button.btn-secondary.new-account-create-form__button', { onClick: () => this.props.goHome(), }, [ - this.props.t('cancel'), + this.context.t('cancel'), ]), h('button.btn-primary.new-account-create-form__button', { onClick: () => this.createNewKeychain(), }, [ - this.props.t('import'), + this.context.t('import'), ]), ]), @@ -84,14 +84,14 @@ class JsonImportSubview extends Component { const state = this.state if (!state) { - const message = this.props.t('validFileImport') + const message = this.context.t('validFileImport') return this.props.displayWarning(message) } const { fileContents } = state if (!fileContents) { - const message = this.props.t('needImportFile') + const message = this.context.t('needImportFile') return this.props.displayWarning(message) } @@ -99,7 +99,7 @@ class JsonImportSubview extends Component { const password = passwordInput.value if (!password) { - const message = this.props.t('needImportPassword') + const message = this.context.t('needImportPassword') return this.props.displayWarning(message) } @@ -112,7 +112,7 @@ JsonImportSubview.propTypes = { goHome: PropTypes.func, displayWarning: PropTypes.func, importNewJsonAccount: PropTypes.func, - t: PropTypes.func, + t: PropTypes.func, } const mapStateToProps = state => { @@ -129,4 +129,9 @@ const mapDispatchToProps = dispatch => { } } +JsonImportSubview.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(JsonImportSubview) + diff --git a/ui/app/accounts/import/private-key.js b/ui/app/accounts/import/private-key.js index bdf581b01..006131bdc 100644 --- a/ui/app/accounts/import/private-key.js +++ b/ui/app/accounts/import/private-key.js @@ -1,11 +1,17 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('../../metamask-connect') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect const actions = require('../../actions') +PrivateKeyImportView.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(PrivateKeyImportView) + function mapStateToProps (state) { return { error: state.appState.warning, @@ -33,7 +39,7 @@ PrivateKeyImportView.prototype.render = function () { return ( h('div.new-account-import-form__private-key', [ - h('span.new-account-create-form__instruction', this.props.t('pastePrivateKey')), + h('span.new-account-create-form__instruction', this.context.t('pastePrivateKey')), h('div.new-account-import-form__private-key-password-container', [ @@ -50,13 +56,13 @@ PrivateKeyImportView.prototype.render = function () { h('button.btn-secondary--lg.new-account-create-form__button', { onClick: () => goHome(), }, [ - this.props.t('cancel'), + this.context.t('cancel'), ]), h('button.btn-primary--lg.new-account-create-form__button', { onClick: () => this.createNewKeychain(), }, [ - this.props.t('import'), + this.context.t('import'), ]), ]), diff --git a/ui/app/accounts/import/seed.js b/ui/app/accounts/import/seed.js index 5479a6be9..d98909baa 100644 --- a/ui/app/accounts/import/seed.js +++ b/ui/app/accounts/import/seed.js @@ -1,10 +1,16 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('../../metamask-connect') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect + +SeedImportSubview.contextTypes = { + t: PropTypes.func, +} module.exports = connect(mapStateToProps)(SeedImportSubview) + function mapStateToProps (state) { return {} } @@ -20,10 +26,10 @@ SeedImportSubview.prototype.render = function () { style: { }, }, [ - this.props.t('pasteSeed'), + this.context.t('pasteSeed'), h('textarea'), h('br'), - h('button', this.props.t('submit')), + h('button', this.context.t('submit')), ]) ) } diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js index 69fbf1e35..48c74192a 100644 --- a/ui/app/accounts/new-account/create-form.js +++ b/ui/app/accounts/new-account/create-form.js @@ -1,11 +1,11 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') class NewAccountCreateForm extends Component { - constructor (props) { + constructor (props, context) { super(props) const { numberOfExistingAccounts = 0 } = props @@ -13,7 +13,7 @@ class NewAccountCreateForm extends Component { this.state = { newAccountName: '', - defaultAccountName: this.props.t('newAccountNumberName', [newAccountNumber]), + defaultAccountName: context.t('newAccountNumberName', [newAccountNumber]), } } @@ -24,7 +24,7 @@ class NewAccountCreateForm extends Component { return h('div.new-account-create-form', [ h('div.new-account-create-form__input-label', {}, [ - this.props.t('accountName'), + this.context.t('accountName'), ]), h('div.new-account-create-form__input-wrapper', {}, [ @@ -40,13 +40,13 @@ class NewAccountCreateForm extends Component { h('button.btn-secondary--lg.new-account-create-form__button', { onClick: () => this.props.goHome(), }, [ - this.props.t('cancel'), + this.context.t('cancel'), ]), h('button.btn-primary--lg.new-account-create-form__button', { onClick: () => this.props.createAccount(newAccountName || defaultAccountName), }, [ - this.props.t('create'), + this.context.t('create'), ]), ]), @@ -97,4 +97,9 @@ const mapDispatchToProps = dispatch => { } } +NewAccountCreateForm.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(NewAccountCreateForm) + diff --git a/ui/app/accounts/new-account/index.js b/ui/app/accounts/new-account/index.js index 584016974..207cf7760 100644 --- a/ui/app/accounts/new-account/index.js +++ b/ui/app/accounts/new-account/index.js @@ -1,7 +1,8 @@ const Component = require('react').Component const h = require('react-hyperscript') +const PropTypes = require('prop-types') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') const { getCurrentViewContext } = require('../../selectors') const classnames = require('classnames') @@ -36,8 +37,13 @@ function AccountDetailsModal (props) { } } +AccountDetailsModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountDetailsModal) + AccountDetailsModal.prototype.render = function () { const { displayedForm, displayForm } = this.props @@ -45,7 +51,7 @@ AccountDetailsModal.prototype.render = function () { h('div.new-account__header', [ - h('div.new-account__title', this.props.t('newAccount')), + h('div.new-account__title', this.context.t('newAccount')), h('div.new-account__tabs', [ @@ -55,7 +61,7 @@ AccountDetailsModal.prototype.render = function () { 'new-account__tabs__unselected cursor-pointer': displayedForm !== 'CREATE', }), onClick: () => displayForm('CREATE'), - }, this.props.t('createDen')), + }, this.context.t('createDen')), h('div.new-account__tabs__tab', { className: classnames('new-account__tabs__tab', { @@ -63,7 +69,7 @@ AccountDetailsModal.prototype.render = function () { 'new-account__tabs__unselected cursor-pointer': displayedForm !== 'IMPORT', }), onClick: () => displayForm('IMPORT'), - }, this.props.t('import')), + }, this.context.t('import')), ]), diff --git a/ui/app/add-token.js b/ui/app/add-token.js index 472f3b736..ebdd220aa 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -2,7 +2,8 @@ const inherits = require('util').inherits const Component = require('react').Component const classnames = require('classnames') const h = require('react-hyperscript') -const connect = require('./metamask-connect') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect const R = require('ramda') const Fuse = require('fuse.js') const contractMap = require('eth-contract-metadata') @@ -29,8 +30,13 @@ const { tokenInfoGetter } = require('./token-util') const emptyAddr = '0x0000000000000000000000000000000000000000' +AddTokenScreen.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(AddTokenScreen) + function mapStateToProps (state) { const { identities, tokens } = state.metamask return { @@ -139,7 +145,7 @@ AddTokenScreen.prototype.validate = function () { if (customAddress) { const validAddress = ethUtil.isValidAddress(customAddress) if (!validAddress) { - errors.customAddress = this.props.t('invalidAddress') + errors.customAddress = this.context.t('invalidAddress') } const validDecimals = customDecimals !== null @@ -147,23 +153,23 @@ AddTokenScreen.prototype.validate = function () { && customDecimals >= 0 && customDecimals < 36 if (!validDecimals) { - errors.customDecimals = this.props.t('decimalsMustZerotoTen') + errors.customDecimals = this.context.t('decimalsMustZerotoTen') } const symbolLen = customSymbol.trim().length const validSymbol = symbolLen > 0 && symbolLen < 10 if (!validSymbol) { - errors.customSymbol = this.props.t('symbolBetweenZeroTen') + errors.customSymbol = this.context.t('symbolBetweenZeroTen') } const ownAddress = identitiesList.includes(standardAddress) if (ownAddress) { - errors.customAddress = this.props.t('personalAddressDetected') + errors.customAddress = this.context.t('personalAddressDetected') } const tokenAlreadyAdded = this.checkExistingAddresses(customAddress) if (tokenAlreadyAdded) { - errors.customAddress = this.props.t('tokenAlreadyAdded') + errors.customAddress = this.context.t('tokenAlreadyAdded') } } else if ( Object.entries(selectedTokens) @@ -171,7 +177,7 @@ AddTokenScreen.prototype.validate = function () { isEmpty && !isSelected ), true) ) { - errors.tokenSelector = this.props.t('mustSelectOne') + errors.tokenSelector = this.context.t('mustSelectOne') } return { @@ -201,7 +207,7 @@ AddTokenScreen.prototype.renderCustomForm = function () { 'add-token__add-custom-field--error': errors.customAddress, }), }, [ - h('div.add-token__add-custom-label', this.props.t('tokenAddress')), + h('div.add-token__add-custom-label', this.context.t('tokenAddress')), h('input.add-token__add-custom-input', { type: 'text', onChange: this.tokenAddressDidChange, @@ -214,7 +220,7 @@ AddTokenScreen.prototype.renderCustomForm = function () { 'add-token__add-custom-field--error': errors.customSymbol, }), }, [ - h('div.add-token__add-custom-label', this.props.t('tokenSymbol')), + h('div.add-token__add-custom-label', this.context.t('tokenSymbol')), h('input.add-token__add-custom-input', { type: 'text', onChange: this.tokenSymbolDidChange, @@ -228,7 +234,7 @@ AddTokenScreen.prototype.renderCustomForm = function () { 'add-token__add-custom-field--error': errors.customDecimals, }), }, [ - h('div.add-token__add-custom-label', this.props.t('decimal')), + h('div.add-token__add-custom-label', this.context.t('decimal')), h('input.add-token__add-custom-input', { type: 'number', onChange: this.tokenDecimalsDidChange, @@ -250,7 +256,7 @@ AddTokenScreen.prototype.renderTokenList = function () { const results = [...addressSearchResult, ...fuseSearchResult] return h('div', [ - results.length > 0 && h('div.add-token__token-icons-title', this.props.t('popularTokens')), + results.length > 0 && h('div.add-token__token-icons-title', this.context.t('popularTokens')), h('div.add-token__token-icons-container', Array(6).fill(undefined) .map((_, i) => { const { logo, symbol, name, address } = results[i] || {} @@ -305,10 +311,10 @@ AddTokenScreen.prototype.renderConfirmation = function () { h('div.add-token', [ h('div.add-token__wrapper', [ h('div.add-token__title-container.add-token__confirmation-title', [ - h('div.add-token__description', this.props.t('likeToAddTokens')), + h('div.add-token__description', this.context.t('likeToAddTokens')), ]), h('div.add-token__content-container.add-token__confirmation-content', [ - h('div.add-token__description.add-token__confirmation-description', this.props.t('balances')), + h('div.add-token__description.add-token__confirmation-description', this.context.t('balances')), h('div.add-token__confirmation-token-list', Object.entries(tokens) .map(([ address, token ]) => ( @@ -327,10 +333,10 @@ AddTokenScreen.prototype.renderConfirmation = function () { h('div.add-token__buttons', [ h('button.btn-secondary--lg.add-token__cancel-button', { onClick: () => this.setState({ isShowingConfirmation: false }), - }, this.props.t('back')), + }, this.context.t('back')), h('button.btn-primary--lg', { onClick: () => addTokens(tokens).then(goHome), - }, this.props.t('addTokens')), + }, this.context.t('addTokens')), ]), ]) ) @@ -350,14 +356,14 @@ AddTokenScreen.prototype.renderTabs = function () { h('div.add-token__content-container', [ h('div.add-token__info-box', [ h('div.add-token__info-box__close'), - h('div.add-token__info-box__title', this.props.t('whatsThis')), - h('div.add-token__info-box__copy', this.props.t('keepTrackTokens')), - h('div.add-token__info-box__copy--blue', this.props.t('learnMore')), + h('div.add-token__info-box__title', this.context.t('whatsThis')), + h('div.add-token__info-box__copy', this.context.t('keepTrackTokens')), + h('div.add-token__info-box__copy--blue', this.context.t('learnMore')), ]), h('div.add-token__input-container', [ h('input.add-token__input', { type: 'text', - placeholder: this.props.t('searchTokens'), + placeholder: this.context.t('searchTokens'), onChange: e => this.setState({ searchQuery: e.target.value }), }), h('div.add-token__search-input-error-message', errors.tokenSelector), @@ -381,9 +387,9 @@ AddTokenScreen.prototype.render = function () { onClick: () => goHome(), }, [ h('i.fa.fa-angle-left.fa-lg'), - h('span', this.props.t('cancel')), + h('span', this.context.t('cancel')), ]), - h('div.add-token__header__title', this.props.t('addTokens')), + h('div.add-token__header__title', this.context.t('addTokens')), !isShowingConfirmation && h('div.add-token__header__tabs', [ h('div.add-token__header__tabs__tab', { @@ -392,7 +398,7 @@ AddTokenScreen.prototype.render = function () { 'add-token__header__tabs__unselected cursor-pointer': displayedTab !== 'SEARCH', }), onClick: () => this.displayTab('SEARCH'), - }, this.props.t('search')), + }, this.context.t('search')), h('div.add-token__header__tabs__tab', { className: classnames('add-token__header__tabs__tab', { @@ -400,7 +406,7 @@ AddTokenScreen.prototype.render = function () { 'add-token__header__tabs__unselected cursor-pointer': displayedTab !== 'CUSTOM_TOKEN', }), onClick: () => this.displayTab('CUSTOM_TOKEN'), - }, this.props.t('customToken')), + }, this.context.t('customToken')), ]), ]), @@ -412,10 +418,10 @@ AddTokenScreen.prototype.render = function () { !isShowingConfirmation && h('div.add-token__buttons', [ h('button.btn-secondary--lg.add-token__cancel-button', { onClick: goHome, - }, this.props.t('cancel')), + }, this.context.t('cancel')), h('button.btn-primary--lg.add-token__confirm-button', { onClick: this.onNext, - }, this.props.t('next')), + }, this.context.t('next')), ]), ]) } diff --git a/ui/app/app.js b/ui/app/app.js index d23238bab..ea88f3039 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -1,7 +1,8 @@ const inherits = require('util').inherits const Component = require('react').Component -const connect = require('./metamask-connect') +const connect = require('react-redux').connect const h = require('react-hyperscript') +const PropTypes = require('prop-types') const actions = require('./actions') const classnames = require('classnames') @@ -45,8 +46,13 @@ const QrView = require('./components/qr-code') // Global Modals const Modal = require('./components/modals/index').Modal +App.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(App) + inherits(App, Component) function App () { Component.call(this) } @@ -293,8 +299,8 @@ App.prototype.renderAppBar = function () { // metamask name h('.flex-row', [ - h('h1', this.props.t('appName')), - h('div.beta-label', this.props.t('beta')), + h('h1', this.context.t('appName')), + h('div.beta-label', this.context.t('beta')), ]), ]), @@ -556,15 +562,15 @@ App.prototype.getConnectingLabel = function () { let name if (providerName === 'mainnet') { - name = this.props.t('connectingToMainnet') + name = this.context.t('connectingToMainnet') } else if (providerName === 'ropsten') { - name = this.props.t('connectingToRopsten') + name = this.context.t('connectingToRopsten') } else if (providerName === 'kovan') { - name = this.props.t('connectingToRopsten') + name = this.context.t('connectingToRopsten') } else if (providerName === 'rinkeby') { - name = this.props.t('connectingToRinkeby') + name = this.context.t('connectingToRinkeby') } else { - name = this.props.t('connectingToUnknown') + name = this.context.t('connectingToUnknown') } return name @@ -577,15 +583,15 @@ App.prototype.getNetworkName = function () { let name if (providerName === 'mainnet') { - name = this.props.t('mainnet') + name = this.context.t('mainnet') } else if (providerName === 'ropsten') { - name = this.props.t('ropsten') + name = this.context.t('ropsten') } else if (providerName === 'kovan') { - name = this.props.t('kovan') + name = this.context.t('kovan') } else if (providerName === 'rinkeby') { - name = this.props.t('rinkeby') + name = this.context.t('rinkeby') } else { - name = this.props.t('unknownNetwork') + name = this.context.t('unknownNetwork') } return name diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index 84678fee6..03955e077 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -3,7 +3,7 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const actions = require('../actions') const genAccountLink = require('etherscan-link').createAccountLink -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const Dropdown = require('./dropdown').Dropdown const DropdownMenuItem = require('./dropdown').DropdownMenuItem const Identicon = require('./identicon') @@ -79,7 +79,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label.allcaps', this.props.t('loose')) : null + return isLoose ? h('.keyring-label.allcaps', this.context.t('loose')) : null } catch (e) { return } } @@ -129,7 +129,7 @@ class AccountDropdowns extends Component { diameter: 32, }, ), - h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, this.props.t('createAccount')), + h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, this.context.t('createAccount')), ], ), h( @@ -154,7 +154,7 @@ class AccountDropdowns extends Component { fontSize: '24px', marginBottom: '5px', }, - }, this.props.t('importAccount')), + }, this.context.t('importAccount')), ] ), ] @@ -192,7 +192,7 @@ class AccountDropdowns extends Component { global.platform.openWindow({ url }) }, }, - this.props.t('etherscanView'), + this.context.t('etherscanView'), ), h( DropdownMenuItem, @@ -204,7 +204,7 @@ class AccountDropdowns extends Component { actions.showQrView(selected, identity ? identity.name : '') }, }, - this.props.t('showQRCode'), + this.context.t('showQRCode'), ), h( DropdownMenuItem, @@ -216,7 +216,7 @@ class AccountDropdowns extends Component { copyToClipboard(checkSumAddress) }, }, - this.props.t('copyAddress'), + this.context.t('copyAddress'), ), h( DropdownMenuItem, @@ -226,7 +226,7 @@ class AccountDropdowns extends Component { actions.requestAccountExport() }, }, - this.props.t('exportPrivateKey'), + this.context.t('exportPrivateKey'), ), ] ) @@ -316,6 +316,10 @@ const mapDispatchToProps = (dispatch) => { } } +AccountDropdowns.contextTypes = { + t: PropTypes.func, +} + module.exports = { AccountDropdowns: connect(null, mapDispatchToProps)(AccountDropdowns), } diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js index 8889f88a7..865207487 100644 --- a/ui/app/components/account-export.js +++ b/ui/app/components/account-export.js @@ -1,14 +1,20 @@ const Component = require('react').Component const h = require('react-hyperscript') +const PropTypes = require('prop-types') const inherits = require('util').inherits const exportAsFile = require('../util').exportAsFile const copyToClipboard = require('copy-to-clipboard') const actions = require('../actions') const ethUtil = require('ethereumjs-util') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect + +ExportAccountView.contextTypes = { + t: PropTypes.func, +} module.exports = connect(mapStateToProps)(ExportAccountView) + inherits(ExportAccountView, Component) function ExportAccountView () { Component.call(this) @@ -35,7 +41,7 @@ ExportAccountView.prototype.render = function () { if (notExporting) return h('div') if (exportRequested) { - const warning = this.props.t('exportPrivateKeyWarning') + const warning = this.context.t('exportPrivateKeyWarning') return ( h('div', { style: { @@ -53,7 +59,7 @@ ExportAccountView.prototype.render = function () { h('p.error', warning), h('input#exportAccount.sizing-input', { type: 'password', - placeholder: this.props.t('confirmPassword').toLowerCase(), + placeholder: this.context.t('confirmPassword').toLowerCase(), onKeyPress: this.onExportKeyPress.bind(this), style: { position: 'relative', @@ -74,10 +80,10 @@ ExportAccountView.prototype.render = function () { style: { marginRight: '10px', }, - }, this.props.t('submit')), + }, this.context.t('submit')), h('button', { onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)), - }, this.props.t('cancel')), + }, this.context.t('cancel')), ]), (this.props.warning) && ( h('span.error', { @@ -98,7 +104,7 @@ ExportAccountView.prototype.render = function () { margin: '0 20px', }, }, [ - h('label', this.props.t('copyPrivateKey') + ':'), + h('label', this.context.t('copyPrivateKey') + ':'), h('p.error.cursor-pointer', { style: { textOverflow: 'ellipsis', @@ -112,13 +118,13 @@ ExportAccountView.prototype.render = function () { }, plainKey), h('button', { onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)), - }, this.props.t('done')), + }, this.context.t('done')), h('button', { style: { marginLeft: '10px', }, onClick: () => exportAsFile(`MetaMask ${nickname} Private Key`, plainKey), - }, this.props.t('saveAsFile')), + }, this.context.t('saveAsFile')), ]) } } diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js index a9120f9db..21de358d6 100644 --- a/ui/app/components/account-menu/index.js +++ b/ui/app/components/account-menu/index.js @@ -1,14 +1,20 @@ const inherits = require('util').inherits const Component = require('react').Component -const connect = require('../../metamask-connect') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect const h = require('react-hyperscript') const actions = require('../../actions') const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu') const Identicon = require('../identicon') const { formatBalance } = require('../../util') +AccountMenu.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountMenu) + inherits(AccountMenu, Component) function AccountMenu () { Component.call(this) } @@ -70,10 +76,10 @@ AccountMenu.prototype.render = function () { h(Item, { className: 'account-menu__header', }, [ - this.props.t('myAccounts'), + this.context.t('myAccounts'), h('button.account-menu__logout-button', { onClick: lockMetamask, - }, this.props.t('logout')), + }, this.context.t('logout')), ]), h(Divider), h('div.account-menu__accounts', this.renderAccounts()), @@ -81,23 +87,23 @@ AccountMenu.prototype.render = function () { h(Item, { onClick: () => showNewAccountPage('CREATE'), icon: h('img.account-menu__item-icon', { src: 'images/plus-btn-white.svg' }), - text: this.props.t('createAccount'), + text: this.context.t('createAccount'), }), h(Item, { onClick: () => showNewAccountPage('IMPORT'), icon: h('img.account-menu__item-icon', { src: 'images/import-account.svg' }), - text: this.props.t('importAccount'), + text: this.context.t('importAccount'), }), h(Divider), h(Item, { onClick: showInfoPage, icon: h('img', { src: 'images/mm-info-icon.svg' }), - text: this.props.t('infoHelp'), + text: this.context.t('infoHelp'), }), h(Item, { onClick: showConfigPage, icon: h('img.account-menu__item-icon', { src: 'images/settings.svg' }), - text: this.props.t('settings'), + text: this.context.t('settings'), }), ]) } @@ -155,6 +161,6 @@ AccountMenu.prototype.indicateIfLoose = function (keyring) { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label.allcaps', this.props.t('imported')) : null + return isLoose ? h('.keyring-label.allcaps', this.context.t('imported')) : null } catch (e) { return } } diff --git a/ui/app/components/balance-component.js b/ui/app/components/balance-component.js index f6292e358..d591ab455 100644 --- a/ui/app/components/balance-component.js +++ b/ui/app/components/balance-component.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const h = require('react-hyperscript') const inherits = require('util').inherits const TokenBalance = require('./token-balance') diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js index 0ace2b840..9a033f893 100644 --- a/ui/app/components/bn-as-decimal-input.js +++ b/ui/app/components/bn-as-decimal-input.js @@ -1,13 +1,19 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const extend = require('xtend') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect + +BnAsDecimalInput.contextTypes = { + t: PropTypes.func, +} module.exports = connect()(BnAsDecimalInput) + inherits(BnAsDecimalInput, Component) function BnAsDecimalInput () { this.state = { invalid: null } @@ -137,13 +143,13 @@ BnAsDecimalInput.prototype.constructWarning = function () { let message = name ? name + ' ' : '' if (min && max) { - message += this.props.t('betweenMinAndMax', [`${newMin} ${suffix}`, `${newMax} ${suffix}`]) + message += this.context.t('betweenMinAndMax', [`${newMin} ${suffix}`, `${newMax} ${suffix}`]) } else if (min) { - message += this.props.t('greaterThanMin', [`${newMin} ${suffix}`]) + message += this.context.t('greaterThanMin', [`${newMin} ${suffix}`]) } else if (max) { - message += this.props.t('lessThanMax', [`${newMax} ${suffix}`]) + message += this.context.t('lessThanMax', [`${newMax} ${suffix}`]) } else { - message += this.props.t('invalidInput') + message += this.context.t('invalidInput') } return message diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js index eafa2af91..9ac565cf4 100644 --- a/ui/app/components/buy-button-subview.js +++ b/ui/app/components/buy-button-subview.js @@ -1,7 +1,8 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const actions = require('../actions') const CoinbaseForm = require('./coinbase-form') const ShapeshiftForm = require('./shapeshift-form') @@ -10,8 +11,13 @@ const AccountPanel = require('./account-panel') const RadioList = require('./custom-radio-list') const networkNames = require('../../../app/scripts/config.js').networkNames +BuyButtonSubview.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(BuyButtonSubview) + function mapStateToProps (state) { return { identity: state.appState.identity, @@ -76,7 +82,7 @@ BuyButtonSubview.prototype.headerSubview = function () { paddingTop: '4px', paddingBottom: '4px', }, - }, this.props.t('depositEth')), + }, this.context.t('depositEth')), ]), // loading indication @@ -118,7 +124,7 @@ BuyButtonSubview.prototype.headerSubview = function () { paddingTop: '4px', paddingBottom: '4px', }, - }, this.props.t('selectService')), + }, this.context.t('selectService')), ]), ]) @@ -143,7 +149,7 @@ BuyButtonSubview.prototype.primarySubview = function () { case '4': case '42': const networkName = networkNames[network] - const label = `${networkName} ${this.props.t('testFaucet')}` + const label = `${networkName} ${this.context.t('testFaucet')}` return ( h('div.flex-column', { style: { @@ -164,14 +170,14 @@ BuyButtonSubview.prototype.primarySubview = function () { style: { marginTop: '15px', }, - }, this.props.t('borrowDharma')) + }, this.context.t('borrowDharma')) ) : null, ]) ) default: return ( - h('h2.error', this.props.t('unknownNetworkId')) + h('h2.error', this.context.t('unknownNetworkId')) ) } @@ -203,8 +209,8 @@ BuyButtonSubview.prototype.mainnetSubview = function () { 'ShapeShift', ], subtext: { - 'Coinbase': `${this.props.t('crypto')}/${this.props.t('fiat')} (${this.props.t('usaOnly')})`, - 'ShapeShift': this.props.t('crypto'), + 'Coinbase': `${this.context.t('crypto')}/${this.context.t('fiat')} (${this.context.t('usaOnly')})`, + 'ShapeShift': this.context.t('crypto'), }, onClick: this.radioHandler.bind(this), }), diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js index 0f980fbd5..d5915292e 100644 --- a/ui/app/components/coinbase-form.js +++ b/ui/app/components/coinbase-form.js @@ -1,11 +1,17 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const actions = require('../actions') +CoinbaseForm.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(CoinbaseForm) + function mapStateToProps (state) { return { warning: state.appState.warning, @@ -37,11 +43,11 @@ CoinbaseForm.prototype.render = function () { }, [ h('button.btn-green', { onClick: this.toCoinbase.bind(this), - }, this.props.t('continueToCoinbase')), + }, this.context.t('continueToCoinbase')), h('button.btn-red', { onClick: () => props.dispatch(actions.goHome()), - }, this.props.t('cancel')), + }, this.context.t('cancel')), ]), ]) } diff --git a/ui/app/components/copyButton.js b/ui/app/components/copyButton.js index ea1c43d54..a60d33523 100644 --- a/ui/app/components/copyButton.js +++ b/ui/app/components/copyButton.js @@ -1,13 +1,19 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const copyToClipboard = require('copy-to-clipboard') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const Tooltip = require('./tooltip') +CopyButton.contextTypes = { + t: PropTypes.func, +} + module.exports = connect()(CopyButton) + inherits(CopyButton, Component) function CopyButton () { Component.call(this) @@ -23,7 +29,7 @@ CopyButton.prototype.render = function () { const value = props.value const copied = state.copied - const message = copied ? this.props.t('copiedButton') : props.title || this.props.t('copyButton') + const message = copied ? this.context.t('copiedButton') : props.title || this.context.t('copyButton') return h('.copy-button', { style: { diff --git a/ui/app/components/copyable.js b/ui/app/components/copyable.js index 28def9adb..ad504deb8 100644 --- a/ui/app/components/copyable.js +++ b/ui/app/components/copyable.js @@ -1,13 +1,19 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const Tooltip = require('./tooltip') const copyToClipboard = require('copy-to-clipboard') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect + +Copyable.contextTypes = { + t: PropTypes.func, +} module.exports = connect()(Copyable) + inherits(Copyable, Component) function Copyable () { Component.call(this) @@ -23,7 +29,7 @@ Copyable.prototype.render = function () { const { copied } = state return h(Tooltip, { - title: copied ? this.props.t('copiedExclamation') : this.props.t('copy'), + title: copied ? this.context.t('copiedExclamation') : this.context.t('copy'), position: 'bottom', }, h('span', { style: { diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index 8234f8d19..825366cb2 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -1,7 +1,8 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') const GasModalCard = require('./gas-modal-card') @@ -94,8 +95,13 @@ function CustomizeGasModal (props) { this.state = getOriginalState(props) } +CustomizeGasModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(CustomizeGasModal) + CustomizeGasModal.prototype.save = function (gasPrice, gasLimit, gasTotal) { const { updateGasPrice, @@ -149,7 +155,7 @@ CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) { }) if (!balanceIsSufficient) { - error = this.props.t('balanceIsInsufficientGas') + error = this.context.t('balanceIsInsufficientGas') } const gasLimitTooLow = gasLimit && conversionGreaterThan( @@ -165,7 +171,7 @@ CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) { ) if (gasLimitTooLow) { - error = this.props.t('gasLimitTooLow') + error = this.context.t('gasLimitTooLow') } this.setState({ error }) @@ -258,7 +264,7 @@ CustomizeGasModal.prototype.render = function () { }, [ h('div.send-v2__customize-gas__header', {}, [ - h('div.send-v2__customize-gas__title', this.props.t('customGas')), + h('div.send-v2__customize-gas__title', this.context.t('customGas')), h('div.send-v2__customize-gas__close', { onClick: hideModal, @@ -274,8 +280,8 @@ CustomizeGasModal.prototype.render = function () { // max: 1000, step: multiplyCurrencies(MIN_GAS_PRICE_GWEI, 10), onChange: value => this.convertAndSetGasPrice(value), - title: this.props.t('gasPrice'), - copy: this.props.t('gasPriceCalculation'), + title: this.context.t('gasPrice'), + copy: this.context.t('gasPriceCalculation'), }), h(GasModalCard, { @@ -284,8 +290,8 @@ CustomizeGasModal.prototype.render = function () { // max: 100000, step: 1, onChange: value => this.convertAndSetGasLimit(value), - title: this.props.t('gasLimit'), - copy: this.props.t('gasLimitCalculation'), + title: this.context.t('gasLimit'), + copy: this.context.t('gasLimitCalculation'), }), ]), @@ -298,7 +304,7 @@ CustomizeGasModal.prototype.render = function () { h('div.send-v2__customize-gas__revert', { onClick: () => this.revert(), - }, [this.props.t('revert')]), + }, [this.context.t('revert')]), h('div.send-v2__customize-gas__buttons', [ h('button.btn-secondary.send-v2__customize-gas__cancel', { @@ -306,12 +312,12 @@ CustomizeGasModal.prototype.render = function () { style: { marginRight: '10px', }, - }, [this.props.t('cancel')]), + }, [this.context.t('cancel')]), h('button.btn-primary.send-v2__customize-gas__save', { onClick: () => !error && this.save(newGasPrice, gasLimit, gasTotal), className: error && 'btn-primary--disabled', - }, [this.props.t('save')]), + }, [this.context.t('save')]), ]), ]), diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index 5e7c0d554..a133f0e29 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -3,7 +3,7 @@ const PropTypes = require('prop-types') const h = require('react-hyperscript') const actions = require('../../../actions') const genAccountLink = require('../../../../lib/account-link.js') -const connect = require('../../../metamask-connect') +const connect = require('react-redux').connect const Dropdown = require('./dropdown').Dropdown const DropdownMenuItem = require('./dropdown').DropdownMenuItem const Identicon = require('../../identicon') @@ -130,7 +130,7 @@ class AccountDropdowns extends Component { actions.showEditAccountModal(identity) }, }, [ - this.props.t('edit'), + this.context.t('edit'), ]), ]), @@ -144,7 +144,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label.allcaps', this.props.t('loose')) : null + return isLoose ? h('.keyring-label.allcaps', this.context.t('loose')) : null } catch (e) { return } } @@ -202,7 +202,7 @@ class AccountDropdowns extends Component { fontSize: '16px', lineHeight: '23px', }, - }, this.props.t('createAccount')), + }, this.context.t('createAccount')), ], ), h( @@ -236,7 +236,7 @@ class AccountDropdowns extends Component { fontSize: '16px', lineHeight: '23px', }, - }, this.props.t('importAccount')), + }, this.context.t('importAccount')), ] ), ] @@ -287,7 +287,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - this.props.t('accountDetails'), + this.context.t('accountDetails'), ), h( DropdownMenuItem, @@ -303,7 +303,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - this.props.t('etherscanView'), + this.context.t('etherscanView'), ), h( DropdownMenuItem, @@ -319,7 +319,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - this.props.t('copyAddress'), + this.context.t('copyAddress'), ), h( DropdownMenuItem, @@ -331,7 +331,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - this.props.t('exportPrivateKey'), + this.context.t('exportPrivateKey'), ), h( DropdownMenuItem, @@ -346,7 +346,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - this.props.t('addToken'), + this.context.t('addToken'), ), ] @@ -464,4 +464,9 @@ function mapStateToProps (state) { } } +AccountDropdowns.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountDropdowns) + diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index aac7a9ee5..94e5d967b 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -1,7 +1,8 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') const Dropdown = require('./components/dropdown').Dropdown const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem @@ -54,8 +55,13 @@ function NetworkDropdown () { Component.call(this) } +NetworkDropdown.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(NetworkDropdown) + // TODO: specify default props and proptypes NetworkDropdown.prototype.render = function () { const props = this.props @@ -94,13 +100,13 @@ NetworkDropdown.prototype.render = function () { }, [ h('div.network-dropdown-header', {}, [ - h('div.network-dropdown-title', {}, this.props.t('networks')), + h('div.network-dropdown-title', {}, this.context.t('networks')), h('div.network-dropdown-divider'), h('div.network-dropdown-content', {}, - this.props.t('defaultNetwork') + this.context.t('defaultNetwork') ), ]), @@ -122,7 +128,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'mainnet' ? '#ffffff' : '#9b9b9b', }, - }, this.props.t('mainnet')), + }, this.context.t('mainnet')), ] ), @@ -144,7 +150,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'ropsten' ? '#ffffff' : '#9b9b9b', }, - }, this.props.t('ropsten')), + }, this.context.t('ropsten')), ] ), @@ -166,7 +172,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'kovan' ? '#ffffff' : '#9b9b9b', }, - }, this.props.t('kovan')), + }, this.context.t('kovan')), ] ), @@ -188,7 +194,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'rinkeby' ? '#ffffff' : '#9b9b9b', }, - }, this.props.t('rinkeby')), + }, this.context.t('rinkeby')), ] ), @@ -210,7 +216,7 @@ NetworkDropdown.prototype.render = function () { style: { color: activeNetwork === 'http://localhost:8545' ? '#ffffff' : '#9b9b9b', }, - }, this.props.t('localhost')), + }, this.context.t('localhost')), ] ), @@ -234,7 +240,7 @@ NetworkDropdown.prototype.render = function () { style: { color: activeNetwork === 'custom' ? '#ffffff' : '#9b9b9b', }, - }, this.props.t('customRPC')), + }, this.context.t('customRPC')), ] ), @@ -249,15 +255,15 @@ NetworkDropdown.prototype.getNetworkName = function () { let name if (providerName === 'mainnet') { - name = this.props.t('mainnet') + name = this.context.t('mainnet') } else if (providerName === 'ropsten') { - name = this.props.t('ropsten') + name = this.context.t('ropsten') } else if (providerName === 'kovan') { - name = this.props.t('kovan') + name = this.context.t('kovan') } else if (providerName === 'rinkeby') { - name = this.props.t('rinkeby') + name = this.context.t('rinkeby') } else { - name = this.props.t('unknownNetwork') + name = this.context.t('unknownNetwork') } return name diff --git a/ui/app/components/dropdowns/token-menu-dropdown.js b/ui/app/components/dropdowns/token-menu-dropdown.js index 630e1f99d..b70d0b893 100644 --- a/ui/app/components/dropdowns/token-menu-dropdown.js +++ b/ui/app/components/dropdowns/token-menu-dropdown.js @@ -1,12 +1,18 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') +TokenMenuDropdown.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(null, mapDispatchToProps)(TokenMenuDropdown) + function mapDispatchToProps (dispatch) { return { showHideTokenConfirmationModal: (token) => { @@ -44,7 +50,7 @@ TokenMenuDropdown.prototype.render = function () { showHideTokenConfirmationModal(this.props.token) this.props.onClose() }, - }, this.props.t('hideToken')), + }, this.context.t('hideToken')), ]), ]), diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index 922f24d40..1f3946817 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -1,4 +1,5 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const extend = require('xtend') @@ -8,11 +9,16 @@ const ENS = require('ethjs-ens') const networkMap = require('ethjs-ens/lib/network-map.json') const ensRE = /.+\..+$/ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const ToAutoComplete = require('./send/to-autocomplete') +EnsInput.contextTypes = { + t: PropTypes.func, +} + module.exports = connect()(EnsInput) + inherits(EnsInput, Component) function EnsInput () { Component.call(this) @@ -70,13 +76,13 @@ EnsInput.prototype.lookupEnsName = function (recipient) { log.info(`ENS attempting to resolve name: ${recipient}`) this.ens.lookup(recipient.trim()) .then((address) => { - if (address === ZERO_ADDRESS) throw new Error(this.props.t('noAddressForName')) + if (address === ZERO_ADDRESS) throw new Error(this.context.t('noAddressForName')) if (address !== ensResolution) { this.setState({ loadingEns: false, ensResolution: address, nickname: recipient.trim(), - hoverText: address + '\n' + this.props.t('clickCopy'), + hoverText: address + '\n' + this.context.t('clickCopy'), ensFailure: false, }) } diff --git a/ui/app/components/hex-as-decimal-input.js b/ui/app/components/hex-as-decimal-input.js index be7ba4c9e..75303a34a 100644 --- a/ui/app/components/hex-as-decimal-input.js +++ b/ui/app/components/hex-as-decimal-input.js @@ -1,13 +1,19 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const extend = require('xtend') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect + +HexAsDecimalInput.contextTypes = { + t: PropTypes.func, +} module.exports = connect()(HexAsDecimalInput) + inherits(HexAsDecimalInput, Component) function HexAsDecimalInput () { this.state = { invalid: null } @@ -127,13 +133,13 @@ HexAsDecimalInput.prototype.constructWarning = function () { let message = name ? name + ' ' : '' if (min && max) { - message += this.props.t('betweenMinAndMax', [min, max]) + message += this.context.t('betweenMinAndMax', [min, max]) } else if (min) { - message += this.props.t('greaterThanMin', [min]) + message += this.context.t('greaterThanMin', [min]) } else if (max) { - message += this.props.t('lessThanMax', [max]) + message += this.context.t('lessThanMax', [max]) } else { - message += this.props.t('invalidInput') + message += this.context.t('invalidInput') } return message diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index 6b2a1b428..b803b7ceb 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const isNode = require('detect-node') const findDOMNode = require('react-dom').findDOMNode const jazzicon = require('jazzicon') diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js index c43e3e3a5..d9885daf5 100644 --- a/ui/app/components/modals/account-details-modal.js +++ b/ui/app/components/modals/account-details-modal.js @@ -1,7 +1,8 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') const AccountModalContainer = require('./account-modal-container') const { getSelectedIdentity } = require('../../selectors') @@ -33,8 +34,13 @@ function AccountDetailsModal () { Component.call(this) } +AccountDetailsModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountDetailsModal) + // Not yet pixel perfect todos: // fonts of qr-header @@ -64,12 +70,12 @@ AccountDetailsModal.prototype.render = function () { h('button.btn-primary.account-modal__button', { onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }), - }, this.props.t('etherscanView')), + }, this.context.t('etherscanView')), // Holding on redesign for Export Private Key functionality h('button.btn-primary.account-modal__button', { onClick: () => showExportPrivateKeyModal(), - }, this.props.t('exportPrivateKey')), + }, this.context.t('exportPrivateKey')), ]) } diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js index 70efe16cb..a9856b20f 100644 --- a/ui/app/components/modals/account-modal-container.js +++ b/ui/app/components/modals/account-modal-container.js @@ -1,7 +1,8 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') const { getSelectedIdentity } = require('../../selectors') const Identicon = require('../identicon') @@ -25,8 +26,13 @@ function AccountModalContainer () { Component.call(this) } +AccountModalContainer.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountModalContainer) + AccountModalContainer.prototype.render = function () { const { selectedIdentity, @@ -59,7 +65,7 @@ AccountModalContainer.prototype.render = function () { h('i.fa.fa-angle-left.fa-lg'), - h('span.account-modal-back__text', ' ' + this.props.t('back')), + h('span.account-modal-back__text', ' ' + this.context.t('back')), ]), diff --git a/ui/app/components/modals/buy-options-modal.js b/ui/app/components/modals/buy-options-modal.js index c0ee3632e..d871e7516 100644 --- a/ui/app/components/modals/buy-options-modal.js +++ b/ui/app/components/modals/buy-options-modal.js @@ -1,7 +1,8 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames @@ -32,8 +33,13 @@ function BuyOptions () { Component.call(this) } +BuyOptions.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(BuyOptions) + BuyOptions.prototype.renderModalContentOption = function (title, header, onClick) { return h('div.buy-modal-content-option', { onClick, @@ -56,15 +62,15 @@ BuyOptions.prototype.render = function () { }, [ h('div.buy-modal-content-title', { style: {}, - }, this.props.t('transfers')), - h('div', {}, this.props.t('howToDeposit')), + }, this.context.t('transfers')), + h('div', {}, this.context.t('howToDeposit')), ]), h('div.buy-modal-content-options.flex-column.flex-center', {}, [ isTestNetwork - ? this.renderModalContentOption(networkName, this.props.t('testFaucet'), () => toFaucet(network)) - : this.renderModalContentOption('Coinbase', this.props.t('depositFiat'), () => toCoinbase(address)), + ? this.renderModalContentOption(networkName, this.context.t('testFaucet'), () => toFaucet(network)) + : this.renderModalContentOption('Coinbase', this.context.t('depositFiat'), () => toCoinbase(address)), // h('div.buy-modal-content-option', {}, [ // h('div.buy-modal-content-option-title', {}, 'Shapeshift'), @@ -72,8 +78,8 @@ BuyOptions.prototype.render = function () { // ]),, this.renderModalContentOption( - this.props.t('directDeposit'), - this.props.t('depositFromAccount'), + this.context.t('directDeposit'), + this.context.t('depositFromAccount'), () => this.goToAccountDetailsModal() ), @@ -84,7 +90,7 @@ BuyOptions.prototype.render = function () { background: 'white', }, onClick: () => { this.props.hideModal() }, - }, h('div.buy-modal-content-footer#buy-modal-content-footer-text', {}, this.props.t('cancel'))), + }, h('div.buy-modal-content-footer#buy-modal-content-footer-text', {}, this.context.t('cancel'))), ]), ]) } diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index e38899d04..8854d258f 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -1,7 +1,8 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames const ShapeshiftForm = require('../shapeshift-form') @@ -40,27 +41,32 @@ function mapDispatchToProps (dispatch) { } inherits(DepositEtherModal, Component) -function DepositEtherModal (props) { +function DepositEtherModal (props, context) { Component.call(this) // need to set after i18n locale has loaded - DIRECT_DEPOSIT_ROW_TITLE = props.t('directDepositEther') - DIRECT_DEPOSIT_ROW_TEXT = props.t('directDepositEtherExplainer') - COINBASE_ROW_TITLE = props.t('buyCoinbase') - COINBASE_ROW_TEXT = props.t('buyCoinbaseExplainer') - SHAPESHIFT_ROW_TITLE = props.t('depositShapeShift') - SHAPESHIFT_ROW_TEXT = props.t('depositShapeShiftExplainer') - FAUCET_ROW_TITLE = props.t('testFaucet') + DIRECT_DEPOSIT_ROW_TITLE = context.t('directDepositEther') + DIRECT_DEPOSIT_ROW_TEXT = context.t('directDepositEtherExplainer') + COINBASE_ROW_TITLE = context.t('buyCoinbase') + COINBASE_ROW_TEXT = context.t('buyCoinbaseExplainer') + SHAPESHIFT_ROW_TITLE = context.t('depositShapeShift') + SHAPESHIFT_ROW_TEXT = context.t('depositShapeShiftExplainer') + FAUCET_ROW_TITLE = context.t('testFaucet') this.state = { buyingWithShapeshift: false, } } +DepositEtherModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(DepositEtherModal) + DepositEtherModal.prototype.facuetRowText = function (networkName) { - return this.props.t('getEtherFromFaucet', [networkName]) + return this.context.t('getEtherFromFaucet', [networkName]) } DepositEtherModal.prototype.renderRow = function ({ @@ -122,10 +128,10 @@ DepositEtherModal.prototype.render = function () { h('div.page-container__header', [ - h('div.page-container__title', [this.props.t('depositEther')]), + h('div.page-container__title', [this.context.t('depositEther')]), h('div.page-container__subtitle', [ - this.props.t('needEtherInWallet'), + this.context.t('needEtherInWallet'), ]), h('div.page-container__header-close', { @@ -148,7 +154,7 @@ DepositEtherModal.prototype.render = function () { }), title: DIRECT_DEPOSIT_ROW_TITLE, text: DIRECT_DEPOSIT_ROW_TEXT, - buttonLabel: this.props.t('viewAccount'), + buttonLabel: this.context.t('viewAccount'), onButtonClick: () => this.goToAccountDetailsModal(), hide: buyingWithShapeshift, }), @@ -157,7 +163,7 @@ DepositEtherModal.prototype.render = function () { logo: h('i.fa.fa-tint.fa-2x'), title: FAUCET_ROW_TITLE, text: this.facuetRowText(networkName), - buttonLabel: this.props.t('getEther'), + buttonLabel: this.context.t('getEther'), onButtonClick: () => toFaucet(network), hide: !isTestNetwork || buyingWithShapeshift, }), @@ -171,7 +177,7 @@ DepositEtherModal.prototype.render = function () { }), title: COINBASE_ROW_TITLE, text: COINBASE_ROW_TEXT, - buttonLabel: this.props.t('continueToCoinbase'), + buttonLabel: this.context.t('continueToCoinbase'), onButtonClick: () => toCoinbase(address), hide: isTestNetwork || buyingWithShapeshift, }), @@ -184,7 +190,7 @@ DepositEtherModal.prototype.render = function () { }), title: SHAPESHIFT_ROW_TITLE, text: SHAPESHIFT_ROW_TEXT, - buttonLabel: this.props.t('shapeshiftBuy'), + buttonLabel: this.context.t('shapeshiftBuy'), onButtonClick: () => this.setState({ buyingWithShapeshift: true }), hide: isTestNetwork, hideButton: buyingWithShapeshift, diff --git a/ui/app/components/modals/edit-account-name-modal.js b/ui/app/components/modals/edit-account-name-modal.js index 4f5bc001a..c79645dbf 100644 --- a/ui/app/components/modals/edit-account-name-modal.js +++ b/ui/app/components/modals/edit-account-name-modal.js @@ -1,7 +1,8 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') const { getSelectedAccount } = require('../../selectors') @@ -32,8 +33,13 @@ function EditAccountNameModal (props) { } } +EditAccountNameModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(EditAccountNameModal) + EditAccountNameModal.prototype.render = function () { const { hideModal, saveAccountLabel, identity } = this.props @@ -50,7 +56,7 @@ EditAccountNameModal.prototype.render = function () { ]), h('div.edit-account-name-modal-title', { - }, [this.props.t('editAccountName')]), + }, [this.context.t('editAccountName')]), h('input.edit-account-name-modal-input', { placeholder: identity.name, @@ -69,7 +75,7 @@ EditAccountNameModal.prototype.render = function () { }, disabled: this.state.inputText.length === 0, }, [ - this.props.t('save'), + this.context.t('save'), ]), ]), diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js index d5a1ba7b8..1f80aed39 100644 --- a/ui/app/components/modals/export-private-key-modal.js +++ b/ui/app/components/modals/export-private-key-modal.js @@ -1,7 +1,8 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const ethUtil = require('ethereumjs-util') const actions = require('../../actions') const AccountModalContainer = require('./account-modal-container') @@ -37,8 +38,13 @@ function ExportPrivateKeyModal () { } } +ExportPrivateKeyModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(ExportPrivateKeyModal) + ExportPrivateKeyModal.prototype.exportAccountAndGetPrivateKey = function (password, address) { const { exportAccount } = this.props @@ -48,8 +54,8 @@ ExportPrivateKeyModal.prototype.exportAccountAndGetPrivateKey = function (passwo ExportPrivateKeyModal.prototype.renderPasswordLabel = function (privateKey) { return h('span.private-key-password-label', privateKey - ? this.props.t('copyPrivateKey') - : this.props.t('typePassword') + ? this.context.t('copyPrivateKey') + : this.context.t('typePassword') ) } @@ -86,8 +92,8 @@ ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, password, ), (privateKey - ? this.renderButton('btn-primary--lg export-private-key__button', () => hideModal(), this.props.t('done')) - : this.renderButton('btn-primary--lg export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), this.props.t('confirm')) + ? this.renderButton('btn-primary--lg export-private-key__button', () => hideModal(), this.context.t('done')) + : this.renderButton('btn-primary--lg export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), this.context.t('confirm')) ), ]) @@ -120,7 +126,7 @@ ExportPrivateKeyModal.prototype.render = function () { h('div.account-modal-divider'), - h('span.modal-body-title', this.props.t('showPrivateKeys')), + h('span.modal-body-title', this.context.t('showPrivateKeys')), h('div.private-key-password', {}, [ this.renderPasswordLabel(privateKey), @@ -130,7 +136,7 @@ ExportPrivateKeyModal.prototype.render = function () { !warning ? null : h('span.private-key-password-error', warning), ]), - h('div.private-key-password-warning', this.props.t('privateKeyWarning')), + h('div.private-key-password-warning', this.context.t('privateKeyWarning')), this.renderButtons(privateKey, this.state.password, address, hideModal), diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js index 5207b4c95..72e9c84eb 100644 --- a/ui/app/components/modals/hide-token-confirmation-modal.js +++ b/ui/app/components/modals/hide-token-confirmation-modal.js @@ -1,7 +1,8 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') const Identicon = require('../identicon') @@ -31,8 +32,13 @@ function HideTokenConfirmationModal () { this.state = {} } +HideTokenConfirmationModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(HideTokenConfirmationModal) + HideTokenConfirmationModal.prototype.render = function () { const { token, network, hideToken, hideModal } = this.props const { symbol, address } = token @@ -41,7 +47,7 @@ HideTokenConfirmationModal.prototype.render = function () { h('div.hide-token-confirmation__container', { }, [ h('div.hide-token-confirmation__title', {}, [ - this.props.t('hideTokenPrompt'), + this.context.t('hideTokenPrompt'), ]), h(Identicon, { @@ -54,19 +60,19 @@ HideTokenConfirmationModal.prototype.render = function () { h('div.hide-token-confirmation__symbol', {}, symbol), h('div.hide-token-confirmation__copy', {}, [ - this.props.t('readdToken'), + this.context.t('readdToken'), ]), h('div.hide-token-confirmation__buttons', {}, [ h('button.btn-cancel.hide-token-confirmation__button.allcaps', { onClick: () => hideModal(), }, [ - this.props.t('cancel'), + this.context.t('cancel'), ]), h('button.btn-clear.hide-token-confirmation__button.allcaps', { onClick: () => hideToken(address), }, [ - this.props.t('hide'), + this.context.t('hide'), ]), ]), ]), diff --git a/ui/app/components/modals/new-account-modal.js b/ui/app/components/modals/new-account-modal.js index 372b65251..0635b3f72 100644 --- a/ui/app/components/modals/new-account-modal.js +++ b/ui/app/components/modals/new-account-modal.js @@ -1,7 +1,7 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') class NewAccountModal extends Component { @@ -11,7 +11,7 @@ class NewAccountModal extends Component { const newAccountNumber = numberOfExistingAccounts + 1 this.state = { - newAccountName: `${props.t('account')} ${newAccountNumber}`, + newAccountName: `${this.context.t('account')} ${newAccountNumber}`, } } @@ -22,7 +22,7 @@ class NewAccountModal extends Component { h('div.new-account-modal-wrapper', { }, [ h('div.new-account-modal-header', {}, [ - this.props.t('newAccount'), + this.context.t('newAccount'), ]), h('div.modal-close-x', { @@ -30,19 +30,19 @@ class NewAccountModal extends Component { }), h('div.new-account-modal-content', {}, [ - this.props.t('accountName'), + this.context.t('accountName'), ]), h('div.new-account-input-wrapper', {}, [ h('input.new-account-input', { value: this.state.newAccountName, - placeholder: this.props.t('sampleAccountName'), + placeholder: this.context.t('sampleAccountName'), onChange: event => this.setState({ newAccountName: event.target.value }), }, []), ]), h('div.new-account-modal-content.after-input', {}, [ - this.props.t('or'), + this.context.t('or'), ]), h('div.new-account-modal-content.after-input.pointer', { @@ -50,13 +50,13 @@ class NewAccountModal extends Component { this.props.hideModal() this.props.showImportPage() }, - }, this.props.t('importAnAccount')), + }, this.context.t('importAnAccount')), h('div.new-account-modal-content.button.allcaps', {}, [ h('button.btn-clear', { onClick: () => this.props.createAccount(newAccountName), }, [ - this.props.t('save'), + this.context.t('save'), ]), ]), ]), @@ -104,4 +104,9 @@ const mapDispatchToProps = dispatch => { } } +NewAccountModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(NewAccountModal) + diff --git a/ui/app/components/modals/notification-modal.js b/ui/app/components/modals/notification-modal.js index 5d6dca177..46a4c8a21 100644 --- a/ui/app/components/modals/notification-modal.js +++ b/ui/app/components/modals/notification-modal.js @@ -1,7 +1,7 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') class NotificationModal extends Component { @@ -22,12 +22,12 @@ class NotificationModal extends Component { }, [ h('div.notification-modal__header', {}, [ - this.props.t(header), + this.context.t(header), ]), h('div.notification-modal__message-wrapper', {}, [ h('div.notification-modal__message', {}, [ - this.props.t(message), + this.context.t(message), ]), ]), @@ -73,4 +73,9 @@ const mapDispatchToProps = dispatch => { } } +NotificationModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(null, mapDispatchToProps)(NotificationModal) + diff --git a/ui/app/components/modals/notification-modals/confirm-reset-account.js b/ui/app/components/modals/notification-modals/confirm-reset-account.js index 94ee997ab..89fa9bef1 100644 --- a/ui/app/components/modals/notification-modals/confirm-reset-account.js +++ b/ui/app/components/modals/notification-modals/confirm-reset-account.js @@ -1,7 +1,7 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const connect = require('../../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../../actions') const NotifcationModal = require('../notification-modal') diff --git a/ui/app/components/modals/shapeshift-deposit-tx-modal.js b/ui/app/components/modals/shapeshift-deposit-tx-modal.js index 28dcb1902..24af5a0de 100644 --- a/ui/app/components/modals/shapeshift-deposit-tx-modal.js +++ b/ui/app/components/modals/shapeshift-deposit-tx-modal.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') const QrView = require('../qr-code') const AccountModalContainer = require('./account-modal-container') diff --git a/ui/app/components/network-display.js b/ui/app/components/network-display.js index 111a82be1..59719d9a4 100644 --- a/ui/app/components/network-display.js +++ b/ui/app/components/network-display.js @@ -1,7 +1,7 @@ const { Component } = require('react') const h = require('react-hyperscript') const PropTypes = require('prop-types') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') const networkToColorHash = { @@ -30,7 +30,7 @@ class NetworkDisplay extends Component { const { provider: { type } } = this.props return h('.network-display__container', [ this.renderNetworkIcon(), - h('.network-name', this.props.t(type)), + h('.network-name', this.context.t(type)), ]) } } @@ -48,4 +48,9 @@ const mapStateToProps = ({ metamask: { network, provider } }) => { } } +NetworkDisplay.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(NetworkDisplay) + diff --git a/ui/app/components/network.js b/ui/app/components/network.js index 10961390e..83297c4f2 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -1,12 +1,18 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const classnames = require('classnames') const inherits = require('util').inherits const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') +Network.contextTypes = { + t: PropTypes.func, +} + module.exports = connect()(Network) + inherits(Network, Component) function Network () { @@ -15,6 +21,7 @@ function Network () { Network.prototype.render = function () { const props = this.props + const context = this.context const networkNumber = props.network let providerName try { @@ -34,7 +41,7 @@ Network.prototype.render = function () { onClick: (event) => this.props.onClick(event), }, [ h('img', { - title: props.t('attemptingConnect'), + title: context.t('attemptingConnect'), style: { width: '27px', }, @@ -42,22 +49,22 @@ Network.prototype.render = function () { }), ]) } else if (providerName === 'mainnet') { - hoverText = props.t('mainnet') + hoverText = context.t('mainnet') iconName = 'ethereum-network' } else if (providerName === 'ropsten') { - hoverText = props.t('ropsten') + hoverText = context.t('ropsten') iconName = 'ropsten-test-network' } else if (parseInt(networkNumber) === 3) { - hoverText = props.t('ropsten') + hoverText = context.t('ropsten') iconName = 'ropsten-test-network' } else if (providerName === 'kovan') { - hoverText = props.t('kovan') + hoverText = context.t('kovan') iconName = 'kovan-test-network' } else if (providerName === 'rinkeby') { - hoverText = props.t('rinkeby') + hoverText = context.t('rinkeby') iconName = 'rinkeby-test-network' } else { - hoverText = props.t('unknownNetwork') + hoverText = context.t('unknownNetwork') iconName = 'unknown-private-network' } @@ -85,7 +92,7 @@ Network.prototype.render = function () { backgroundColor: '#038789', // $blue-lagoon nonSelectBackgroundColor: '#15afb2', }), - h('.network-name', props.t('mainnet')), + h('.network-name', context.t('mainnet')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'ropsten-test-network': @@ -94,7 +101,7 @@ Network.prototype.render = function () { backgroundColor: '#e91550', // $crimson nonSelectBackgroundColor: '#ec2c50', }), - h('.network-name', props.t('ropsten')), + h('.network-name', context.t('ropsten')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'kovan-test-network': @@ -103,7 +110,7 @@ Network.prototype.render = function () { backgroundColor: '#690496', // $purple nonSelectBackgroundColor: '#b039f3', }), - h('.network-name', props.t('kovan')), + h('.network-name', context.t('kovan')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'rinkeby-test-network': @@ -112,7 +119,7 @@ Network.prototype.render = function () { backgroundColor: '#ebb33f', // $tulip-tree nonSelectBackgroundColor: '#ecb23e', }), - h('.network-name', props.t('rinkeby')), + h('.network-name', context.t('rinkeby')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) default: @@ -124,7 +131,7 @@ Network.prototype.render = function () { }, }), - h('.network-name', props.t('privateNetwork')), + h('.network-name', context.t('privateNetwork')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) } diff --git a/ui/app/components/notice.js b/ui/app/components/notice.js index a999ffd88..bb7e0814c 100644 --- a/ui/app/components/notice.js +++ b/ui/app/components/notice.js @@ -1,13 +1,19 @@ const inherits = require('util').inherits const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const ReactMarkdown = require('react-markdown') const linker = require('extension-link-enabler') const findDOMNode = require('react-dom').findDOMNode -const connect = require('../metamask-connect') +const connect = require('react-redux').connect + +Notice.contextTypes = { + t: PropTypes.func, +} module.exports = connect()(Notice) + inherits(Notice, Component) function Notice () { Component.call(this) @@ -111,7 +117,7 @@ Notice.prototype.render = function () { style: { marginTop: '18px', }, - }, this.props.t('accept')), + }, this.context.t('accept')), ]) ) } diff --git a/ui/app/components/pending-msg-details.js b/ui/app/components/pending-msg-details.js index ddec8470d..f16fcb1c7 100644 --- a/ui/app/components/pending-msg-details.js +++ b/ui/app/components/pending-msg-details.js @@ -1,12 +1,18 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const AccountPanel = require('./account-panel') +PendingMsgDetails.contextTypes = { + t: PropTypes.func, +} + module.exports = connect()(PendingMsgDetails) + inherits(PendingMsgDetails, Component) function PendingMsgDetails () { Component.call(this) @@ -40,7 +46,7 @@ PendingMsgDetails.prototype.render = function () { // message data h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [ h('.flex-column.flex-space-between', [ - h('label.font-small.allcaps', this.props.t('message')), + h('label.font-small.allcaps', this.context.t('message')), h('span.font-small', msgParams.data), ]), ]), diff --git a/ui/app/components/pending-msg.js b/ui/app/components/pending-msg.js index 56e646a1c..21a7864e4 100644 --- a/ui/app/components/pending-msg.js +++ b/ui/app/components/pending-msg.js @@ -1,11 +1,17 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const PendingTxDetails = require('./pending-msg-details') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect + +PendingMsg.contextTypes = { + t: PropTypes.func, +} module.exports = connect()(PendingMsg) + inherits(PendingMsg, Component) function PendingMsg () { Component.call(this) @@ -30,14 +36,14 @@ PendingMsg.prototype.render = function () { fontWeight: 'bold', textAlign: 'center', }, - }, this.props.t('signMessage')), + }, this.context.t('signMessage')), h('.error', { style: { margin: '10px', }, }, [ - this.props.t('signNotice'), + this.context.t('signNotice'), h('a', { href: 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527', style: { color: 'rgb(247, 134, 28)' }, @@ -46,7 +52,7 @@ PendingMsg.prototype.render = function () { const url = 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527' global.platform.openWindow({ url }) }, - }, this.props.t('readMore')), + }, this.context.t('readMore')), ]), // message details @@ -56,10 +62,10 @@ PendingMsg.prototype.render = function () { h('.flex-row.flex-space-around', [ h('button', { onClick: state.cancelMessage, - }, this.props.t('cancel')), + }, this.context.t('cancel')), h('button', { onClick: state.signMessage, - }, this.props.t('sign')), + }, this.context.t('sign')), ]), ]) diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index f41fa51e6..aa68a9eb0 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -1,5 +1,5 @@ const { Component } = require('react') -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const h = require('react-hyperscript') const PropTypes = require('prop-types') const actions = require('../../actions') @@ -32,7 +32,7 @@ class ConfirmDeployContract extends Component { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.displayWarning(this.props.t('invalidGasParams')) + this.props.displayWarning(this.context.t('invalidGasParams')) this.setState({ submitting: false }) } } @@ -177,7 +177,7 @@ class ConfirmDeployContract extends Component { return ( h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('gasFee') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('gasFee') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${fiatGas} ${currentCurrency.toUpperCase()}`), @@ -216,8 +216,8 @@ class ConfirmDeployContract extends Component { return ( h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ this.props.t('total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ this.props.t('amountPlusGas') ]), + h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -247,11 +247,11 @@ class ConfirmDeployContract extends Component { h('.page-container__header-row', [ h('span.page-container__back-button', { onClick: () => backToAccountDetail(selectedAddress), - }, this.props.t('back')), + }, this.context.t('back')), window.METAMASK_UI_TYPE === 'notification' && h(NetworkDisplay), ]), - h('.page-container__title', this.props.t('confirmContract')), - h('.page-container__subtitle', this.props.t('pleaseReviewTransaction')), + h('.page-container__title', this.context.t('confirmContract')), + h('.page-container__subtitle', this.context.t('pleaseReviewTransaction')), ]), // Main Send token Card h('.page-container__content', [ @@ -274,7 +274,7 @@ class ConfirmDeployContract extends Component { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('from') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -282,9 +282,9 @@ class ConfirmDeployContract extends Component { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('to') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('to') ]), h('div.confirm-screen-section-column', [ - h('div.confirm-screen-row-info', this.props.t('newContract')), + h('div.confirm-screen-row-info', this.context.t('newContract')), ]), ]), @@ -302,12 +302,12 @@ class ConfirmDeployContract extends Component { // Cancel Button h('button.btn-cancel.page-container__footer-button.allcaps', { onClick: event => this.cancel(event, txMeta), - }, this.props.t('cancel')), + }, this.context.t('cancel')), // Accept Button h('button.btn-confirm.page-container__footer-button.allcaps', { onClick: event => this.onSubmit(event), - }, this.props.t('confirm')), + }, this.context.t('confirm')), ]), ]), ]) @@ -351,4 +351,8 @@ const mapDispatchToProps = dispatch => { } } -module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmDeployContract) \ No newline at end of file +ConfirmDeployContract.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmDeployContract) diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index 255f0e8a2..b68de4704 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -1,5 +1,6 @@ const Component = require('react').Component -const connect = require('../../metamask-connect') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect const h = require('react-hyperscript') const inherits = require('util').inherits const actions = require('../../actions') @@ -18,8 +19,13 @@ const NetworkDisplay = require('../network-display') const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') +ConfirmSendEther.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmSendEther) + function mapStateToProps (state) { const { conversionRate, @@ -196,7 +202,7 @@ ConfirmSendEther.prototype.getData = function () { }, to: { address: txParams.to, - name: identities[txParams.to] ? identities[txParams.to].name : this.props.t('newRecipient'), + name: identities[txParams.to] ? identities[txParams.to].name : this.context.t('newRecipient'), }, memo: txParams.memo || '', gasFeeInFIAT, @@ -297,7 +303,7 @@ ConfirmSendEther.prototype.render = function () { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('from') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -305,7 +311,7 @@ ConfirmSendEther.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('to') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('to') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', toName), h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`), @@ -313,7 +319,7 @@ ConfirmSendEther.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('gasFee') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('gasFee') ]), h('div.confirm-screen-section-column', [ h(GasFeeDisplay, { gasTotal: gasTotal || gasFeeInHex, @@ -326,8 +332,8 @@ ConfirmSendEther.prototype.render = function () { h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ this.props.t('total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ this.props.t('amountPlusGas') ]), + h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -428,10 +434,10 @@ ConfirmSendEther.prototype.render = function () { clearSend() this.cancel(event, txMeta) }, - }, this.props.t('cancel')), + }, this.context.t('cancel')), // Accept Button - h('button.btn-confirm.page-container__footer-button.allcaps', [this.props.t('confirm')]), + h('button.btn-confirm.page-container__footer-button.allcaps', [this.context.t('confirm')]), ]), ]), ]) @@ -447,7 +453,7 @@ ConfirmSendEther.prototype.onSubmit = function (event) { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.dispatch(actions.displayWarning(this.props.t('invalidGasParams'))) + this.props.dispatch(actions.displayWarning(this.context.t('invalidGasParams'))) this.setState({ submitting: false }) } } diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index 3e66705ae..7fe260a61 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -1,5 +1,6 @@ const Component = require('react').Component -const connect = require('../../metamask-connect') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect const h = require('react-hyperscript') const inherits = require('util').inherits const tokenAbi = require('human-standard-token-abi') @@ -28,8 +29,13 @@ const { getSelectedTokenContract, } = require('../../selectors') +ConfirmSendToken.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmSendToken) + function mapStateToProps (state, ownProps) { const { token: { symbol }, txData } = ownProps const { txParams } = txData || {} @@ -168,7 +174,7 @@ ConfirmSendToken.prototype.getAmount = function () { ? +(sendTokenAmount * tokenExchangeRate * conversionRate).toFixed(2) : null, token: typeof value === 'undefined' - ? this.props.t('unknown') + ? this.context.t('unknown') : +sendTokenAmount.toFixed(decimals), } @@ -240,7 +246,7 @@ ConfirmSendToken.prototype.getData = function () { }, to: { address: value, - name: identities[value] ? identities[value].name : this.props.t('newRecipient'), + name: identities[value] ? identities[value].name : this.context.t('newRecipient'), }, memo: txParams.memo || '', } @@ -286,7 +292,7 @@ ConfirmSendToken.prototype.renderGasFee = function () { return ( h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('gasFee') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('gasFee') ]), h('div.confirm-screen-section-column', [ h(GasFeeDisplay, { gasTotal: gasTotal || gasFeeInHex, @@ -308,8 +314,8 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { ? ( h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ this.props.t('total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ this.props.t('amountPlusGas') ]), + h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -321,13 +327,13 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { : ( h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ this.props.t('total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ this.props.t('amountPlusGas') ]), + h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${tokenAmount} ${symbol}`), - h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} ${this.props.t('gas')}`), + h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} ${this.context.t('gas')}`), ]), ]) ) @@ -350,10 +356,10 @@ ConfirmSendToken.prototype.render = function () { this.inputs = [] const isTxReprice = Boolean(txMeta.lastGasPrice) - const title = isTxReprice ? this.props.t('reprice_title') : this.props.t('confirm') + const title = isTxReprice ? this.context.t('reprice_title') : this.context.t('confirm') const subtitle = isTxReprice - ? this.props.t('reprice_subtitle') - : this.props.t('pleaseReviewTransaction') + ? this.context.t('reprice_subtitle') + : this.context.t('pleaseReviewTransaction') return ( h('div.confirm-screen-container.confirm-send-token', [ @@ -362,7 +368,7 @@ ConfirmSendToken.prototype.render = function () { h('div.page-container__header', [ !txMeta.lastGasPrice && h('button.confirm-screen-back-button', { onClick: () => editTransaction(txMeta), - }, this.props.t('edit')), + }, this.context.t('edit')), h('div.page-container__title', title), h('div.page-container__subtitle', subtitle), ]), @@ -406,7 +412,7 @@ ConfirmSendToken.prototype.render = function () { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('from') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -414,7 +420,7 @@ ConfirmSendToken.prototype.render = function () { ]), toAddress && h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ this.props.t('to') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('to') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', toName), h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`), @@ -436,10 +442,10 @@ ConfirmSendToken.prototype.render = function () { // Cancel Button h('button.btn-cancel.page-container__footer-button.allcaps', { onClick: (event) => this.cancel(event, txMeta), - }, this.props.t('cancel')), + }, this.context.t('cancel')), // Accept Button - h('button.btn-confirm.page-container__footer-button.allcaps', [this.props.t('confirm')]), + h('button.btn-confirm.page-container__footer-button.allcaps', [this.context.t('confirm')]), ]), ]), ]), @@ -456,7 +462,7 @@ ConfirmSendToken.prototype.onSubmit = function (event) { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.dispatch(actions.displayWarning(this.props.t('invalidGasParams'))) + this.props.dispatch(actions.displayWarning(this.context.t('invalidGasParams'))) this.setState({ submitting: false }) } } diff --git a/ui/app/components/pending-tx/index.js b/ui/app/components/pending-tx/index.js index 0a8813b03..acdd99364 100644 --- a/ui/app/components/pending-tx/index.js +++ b/ui/app/components/pending-tx/index.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const h = require('react-hyperscript') const clone = require('clone') const abi = require('human-standard-token-abi') diff --git a/ui/app/components/qr-code.js b/ui/app/components/qr-code.js index 89504eca3..83885539c 100644 --- a/ui/app/components/qr-code.js +++ b/ui/app/components/qr-code.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const qrCode = require('qrcode-npm').qrcode const inherits = require('util').inherits -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const isHexPrefixed = require('ethereumjs-util').isHexPrefixed const ReadOnlyInput = require('./readonly-input') diff --git a/ui/app/components/send/account-list-item.js b/ui/app/components/send/account-list-item.js index 749339694..1ad3f69c1 100644 --- a/ui/app/components/send/account-list-item.js +++ b/ui/app/components/send/account-list-item.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const Identicon = require('../identicon') const CurrencyDisplay = require('./currency-display') const { conversionRateSelector, getCurrentCurrency } = require('../../selectors') diff --git a/ui/app/components/send/gas-fee-display-v2.js b/ui/app/components/send/gas-fee-display-v2.js index 76ed1b5d4..1423aa84d 100644 --- a/ui/app/components/send/gas-fee-display-v2.js +++ b/ui/app/components/send/gas-fee-display-v2.js @@ -1,11 +1,17 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const CurrencyDisplay = require('./currency-display') -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect + +GasFeeDisplay.contextTypes = { + t: PropTypes.func, +} module.exports = connect()(GasFeeDisplay) + inherits(GasFeeDisplay, Component) function GasFeeDisplay () { Component.call(this) @@ -33,8 +39,8 @@ GasFeeDisplay.prototype.render = function () { readOnly: true, }) : gasLoadingError - ? h('div.currency-display.currency-display--message', this.props.t('setGasPrice')) - : h('div.currency-display', this.props.t('loading')), + ? h('div.currency-display.currency-display--message', this.context.t('setGasPrice')) + : h('div.currency-display', this.context.t('loading')), h('button.sliders-icon-container', { onClick, diff --git a/ui/app/components/send/gas-tooltip.js b/ui/app/components/send/gas-tooltip.js index 607394c8b..62cdc1cad 100644 --- a/ui/app/components/send/gas-tooltip.js +++ b/ui/app/components/send/gas-tooltip.js @@ -1,11 +1,17 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const InputNumber = require('../input-number.js') -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect + +GasTooltip.contextTypes = { + t: PropTypes.func, +} module.exports = connect()(GasTooltip) + inherits(GasTooltip, Component) function GasTooltip () { Component.call(this) @@ -82,7 +88,7 @@ GasTooltip.prototype.render = function () { 'marginTop': '81px', }, }, [ - h('span.gas-tooltip-label', {}, [this.props.t('gasLimit')]), + h('span.gas-tooltip-label', {}, [this.context.t('gasLimit')]), h('i.fa.fa-info-circle'), ]), h(InputNumber, { diff --git a/ui/app/components/send/send-v2-container.js b/ui/app/components/send/send-v2-container.js index 5b903a96e..08c26a91f 100644 --- a/ui/app/components/send/send-v2-container.js +++ b/ui/app/components/send/send-v2-container.js @@ -1,4 +1,4 @@ -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const actions = require('../../actions') const abi = require('ethereumjs-abi') const SendEther = require('../../send-v2') diff --git a/ui/app/components/send/to-autocomplete.js b/ui/app/components/send/to-autocomplete.js index 4c54701cb..5ea17f9a2 100644 --- a/ui/app/components/send/to-autocomplete.js +++ b/ui/app/components/send/to-autocomplete.js @@ -1,11 +1,17 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const AccountListItem = require('./account-list-item') -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect + +ToAutoComplete.contextTypes = { + t: PropTypes.func, +} module.exports = connect()(ToAutoComplete) + inherits(ToAutoComplete, Component) function ToAutoComplete () { Component.call(this) @@ -93,7 +99,7 @@ ToAutoComplete.prototype.render = function () { return h('div.send-v2__to-autocomplete', {}, [ h('input.send-v2__to-autocomplete__input', { - placeholder: this.props.t('recipientAddress'), + placeholder: this.context.t('recipientAddress'), className: inError ? `send-v2__error-border` : '', value: to, onChange: event => onChange(event.target.value), diff --git a/ui/app/components/sender-to-recipient.js b/ui/app/components/sender-to-recipient.js index 4c3881668..6b9cd32ea 100644 --- a/ui/app/components/sender-to-recipient.js +++ b/ui/app/components/sender-to-recipient.js @@ -1,6 +1,6 @@ const { Component } = require('react') const h = require('react-hyperscript') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const PropTypes = require('prop-types') const Identicon = require('./identicon') @@ -21,7 +21,7 @@ class SenderToRecipient extends Component { this.renderRecipientIcon(), h( '.sender-to-recipient__name.sender-to-recipient__recipient-name', - recipientName || this.props.t('newContract') + recipientName || this.context.t('newContract') ), ]) ) @@ -64,4 +64,9 @@ SenderToRecipient.propTypes = { t: PropTypes.func, } +SenderToRecipient.contextTypes = { + t: PropTypes.func, +} + module.exports = connect()(SenderToRecipient) + diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js index 5f58527fe..fd4a80a4a 100644 --- a/ui/app/components/shapeshift-form.js +++ b/ui/app/components/shapeshift-form.js @@ -1,7 +1,8 @@ const h = require('react-hyperscript') const inherits = require('util').inherits +const PropTypes = require('prop-types') const Component = require('react').Component -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const classnames = require('classnames') const { qrcode } = require('qrcode-npm') const { shapeShiftSubview, pairUpdate, buyWithShapeShift } = require('../actions') @@ -32,8 +33,13 @@ function mapDispatchToProps (dispatch) { } } +ShapeshiftForm.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(ShapeshiftForm) + inherits(ShapeshiftForm, Component) function ShapeshiftForm () { Component.call(this) @@ -93,7 +99,7 @@ ShapeshiftForm.prototype.onBuyWithShapeShift = function () { })) .catch(() => this.setState({ showQrCode: false, - errorMessage: this.props.t('invalidRequest'), + errorMessage: this.context.t('invalidRequest'), isLoading: false, })) } @@ -125,10 +131,10 @@ ShapeshiftForm.prototype.renderMarketInfo = function () { return h('div.shapeshift-form__metadata', {}, [ - this.renderMetadata(this.props.t('status'), limit ? this.props.t('available') : this.props.t('unavailable')), - this.renderMetadata(this.props.t('limit'), limit), - this.renderMetadata(this.props.t('exchangeRate'), rate), - this.renderMetadata(this.props.t('min'), minimum), + this.renderMetadata(this.context.t('status'), limit ? this.context.t('available') : this.context.t('unavailable')), + this.renderMetadata(this.context.t('limit'), limit), + this.renderMetadata(this.context.t('exchangeRate'), rate), + this.renderMetadata(this.context.t('min'), minimum), ]) } @@ -142,7 +148,7 @@ ShapeshiftForm.prototype.renderQrCode = function () { return h('div.shapeshift-form', {}, [ h('div.shapeshift-form__deposit-instruction', [ - this.props.t('depositCoin', [depositCoin.toUpperCase()]), + this.context.t('depositCoin', [depositCoin.toUpperCase()]), ]), h('div', depositAddress), @@ -179,7 +185,7 @@ ShapeshiftForm.prototype.render = function () { h('div.shapeshift-form__selector', [ - h('div.shapeshift-form__selector-label', this.props.t('deposit')), + h('div.shapeshift-form__selector-label', this.context.t('deposit')), h(SimpleDropdown, { selectedOption: this.state.depositCoin, @@ -199,7 +205,7 @@ ShapeshiftForm.prototype.render = function () { h('div.shapeshift-form__selector', [ h('div.shapeshift-form__selector-label', [ - this.props.t('receive'), + this.context.t('receive'), ]), h('div.shapeshift-form__selector-input', ['ETH']), @@ -217,7 +223,7 @@ ShapeshiftForm.prototype.render = function () { }, [ h('div.shapeshift-form__address-input-label', [ - this.props.t('refundAddress'), + this.context.t('refundAddress'), ]), h('input.shapeshift-form__address-input', { @@ -239,7 +245,7 @@ ShapeshiftForm.prototype.render = function () { className: btnClass, disabled: !token, onClick: () => this.onBuyWithShapeShift(), - }, [this.props.t('buy')]), + }, [this.context.t('buy')]), ]) } diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index d810eddc9..4334aacba 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -1,7 +1,8 @@ const inherits = require('util').inherits const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const vreme = new (require('vreme'))() const explorerLink = require('etherscan-link').createExplorerLink const actions = require('../actions') @@ -12,8 +13,13 @@ const EthBalance = require('./eth-balance') const Tooltip = require('./tooltip') +ShiftListItem.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(ShiftListItem) + function mapStateToProps (state) { return { selectedAddress: state.metamask.selectedAddress, @@ -75,7 +81,7 @@ ShiftListItem.prototype.renderUtilComponents = function () { value: this.props.depositAddress, }), h(Tooltip, { - title: this.props.t('qrCode'), + title: this.context.t('qrCode'), }, [ h('i.fa.fa-qrcode.pointer.pop-hover', { onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType)), @@ -135,8 +141,8 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, this.props.t('toETHviaShapeShift', [props.depositType])), - h('div', this.props.t('noDeposits')), + }, this.context.t('toETHviaShapeShift', [props.depositType])), + h('div', this.context.t('noDeposits')), h('div', { style: { fontSize: 'x-small', @@ -158,8 +164,8 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, this.props.t('toETHviaShapeShift', [props.depositType])), - h('div', this.props.t('conversionProgress')), + }, this.context.t('toETHviaShapeShift', [props.depositType])), + h('div', this.context.t('conversionProgress')), h('div', { style: { fontSize: 'x-small', @@ -184,7 +190,7 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, this.props.t('fromShapeShift')), + }, this.context.t('fromShapeShift')), h('div', formatDate(props.time)), h('div', { style: { @@ -196,7 +202,7 @@ ShiftListItem.prototype.renderInfo = function () { ]) case 'failed': - return h('span.error', '(' + this.props.t('failed') + ')') + return h('span.error', '(' + this.context.t('failed') + ')') default: return '' } diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index b76c1e60f..41415411e 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -1,8 +1,9 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const Identicon = require('./identicon') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const ethUtil = require('ethereumjs-util') const classnames = require('classnames') @@ -37,8 +38,13 @@ function mapDispatchToProps (dispatch) { } } +SignatureRequest.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(SignatureRequest) + inherits(SignatureRequest, Component) function SignatureRequest (props) { Component.call(this) @@ -54,7 +60,7 @@ SignatureRequest.prototype.renderHeader = function () { h('div.request-signature__header-background'), - h('div.request-signature__header__text', this.props.t('sigRequest')), + h('div.request-signature__header__text', this.context.t('sigRequest')), h('div.request-signature__header__tip-container', [ h('div.request-signature__header__tip'), @@ -75,7 +81,7 @@ SignatureRequest.prototype.renderAccountDropdown = function () { return h('div.request-signature__account', [ - h('div.request-signature__account-text', [this.props.t('account') + ':']), + h('div.request-signature__account-text', [this.context.t('account') + ':']), h(AccountDropdownMini, { selectedAccount, @@ -102,7 +108,7 @@ SignatureRequest.prototype.renderBalance = function () { return h('div.request-signature__balance', [ - h('div.request-signature__balance-text', [this.props.t('balance')]), + h('div.request-signature__balance-text', [this.context.t('balance')]), h('div.request-signature__balance-value', `${balanceInEther} ETH`), @@ -136,7 +142,7 @@ SignatureRequest.prototype.renderRequestInfo = function () { return h('div.request-signature__request-info', [ h('div.request-signature__headline', [ - this.props.t('yourSigRequested'), + this.context.t('yourSigRequested'), ]), ]) @@ -154,18 +160,18 @@ SignatureRequest.prototype.msgHexToText = function (hex) { SignatureRequest.prototype.renderBody = function () { let rows - let notice = this.props.t('youSign') + ':' + let notice = this.context.t('youSign') + ':' const { txData } = this.props const { type, msgParams: { data } } = txData if (type === 'personal_sign') { - rows = [{ name: this.props.t('message'), value: this.msgHexToText(data) }] + rows = [{ name: this.context.t('message'), value: this.msgHexToText(data) }] } else if (type === 'eth_signTypedData') { rows = data } else if (type === 'eth_sign') { - rows = [{ name: this.props.t('message'), value: data }] - notice = this.props.t('signNotice') + rows = [{ name: this.context.t('message'), value: data }] + notice = this.context.t('signNotice') } return h('div.request-signature__body', {}, [ @@ -224,10 +230,10 @@ SignatureRequest.prototype.renderFooter = function () { return h('div.request-signature__footer', [ h('button.btn-secondary--lg.request-signature__footer__cancel-button', { onClick: cancel, - }, this.props.t('cancel')), + }, this.context.t('cancel')), h('button.btn-primary--lg', { onClick: sign, - }, this.props.t('sign')), + }, this.context.t('sign')), ]) } diff --git a/ui/app/components/token-balance.js b/ui/app/components/token-balance.js index 7d7744fe6..2f71c0687 100644 --- a/ui/app/components/token-balance.js +++ b/ui/app/components/token-balance.js @@ -2,7 +2,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits const TokenTracker = require('eth-token-tracker') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const selectors = require('../selectors') function mapStateToProps (state) { diff --git a/ui/app/components/token-cell.js b/ui/app/components/token-cell.js index a24781af1..0332fde88 100644 --- a/ui/app/components/token-cell.js +++ b/ui/app/components/token-cell.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const Identicon = require('./identicon') const prefixForNetwork = require('../../lib/etherscan-prefix-for-network') const selectors = require('../selectors') diff --git a/ui/app/components/token-list.js b/ui/app/components/token-list.js index ae22f3702..150a3762d 100644 --- a/ui/app/components/token-list.js +++ b/ui/app/components/token-list.js @@ -1,9 +1,10 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const TokenTracker = require('eth-token-tracker') const TokenCell = require('./token-cell.js') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const selectors = require('../selectors') function mapStateToProps (state) { @@ -24,8 +25,13 @@ for (const address in contracts) { } } +TokenList.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(TokenList) + inherits(TokenList, Component) function TokenList () { this.state = { @@ -42,7 +48,7 @@ TokenList.prototype.render = function () { const { tokens, isLoading, error } = state if (isLoading) { - return this.message(this.props.t('loadingTokens')) + return this.message(this.context.t('loadingTokens')) } if (error) { @@ -52,7 +58,7 @@ TokenList.prototype.render = function () { padding: '80px', }, }, [ - this.props.t('troubleTokenBalances'), + this.context.t('troubleTokenBalances'), h('span.hotFix', { style: { color: 'rgba(247, 134, 28, 1)', @@ -63,7 +69,7 @@ TokenList.prototype.render = function () { url: `https://ethplorer.io/address/${userAddress}`, }) }, - }, this.props.t('here')), + }, this.context.t('here')), ]) } diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index 5e88d38d3..622664786 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -1,6 +1,7 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') -const connect = require('../metamask-connect') +const connect = require('react-redux').connect const inherits = require('util').inherits const classnames = require('classnames') const abi = require('human-standard-token-abi') @@ -15,8 +16,13 @@ const { calcTokenAmount } = require('../token-util') const { getCurrentCurrency } = require('../selectors') +TxListItem.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(TxListItem) + function mapStateToProps (state) { return { tokens: state.metamask.tokens, @@ -74,7 +80,7 @@ TxListItem.prototype.getAddressText = function () { default: return address ? `${address.slice(0, 10)}...${address.slice(-4)}` - : this.props.t('contractDeployment') + : this.context.t('contractDeployment') } } @@ -306,21 +312,21 @@ TxListItem.prototype.txStatusIndicator = function () { let name if (transactionStatus === 'unapproved') { - name = this.props.t('unapproved') + name = this.context.t('unapproved') } else if (transactionStatus === 'rejected') { - name = this.props.t('rejected') + name = this.context.t('rejected') } else if (transactionStatus === 'approved') { - name = this.props.t('approved') + name = this.context.t('approved') } else if (transactionStatus === 'signed') { - name = this.props.t('signed') + name = this.context.t('signed') } else if (transactionStatus === 'submitted') { - name = this.props.t('submitted') + name = this.context.t('submitted') } else if (transactionStatus === 'confirmed') { - name = this.props.t('confirmed') + name = this.context.t('confirmed') } else if (transactionStatus === 'failed') { - name = this.props.t('failed') + name = this.context.t('failed') } else if (transactionStatus === 'dropped') { - name = this.props.t('dropped') + name = this.context.t('dropped') } return name } diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js index 5f09d887e..fa01c7b29 100644 --- a/ui/app/components/tx-list.js +++ b/ui/app/components/tx-list.js @@ -1,5 +1,6 @@ const Component = require('react').Component -const connect = require('../metamask-connect') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect const h = require('react-hyperscript') const inherits = require('util').inherits const prefixForNetwork = require('../../lib/etherscan-prefix-for-network') @@ -11,8 +12,13 @@ const { showConfTxPage } = require('../actions') const classnames = require('classnames') const { tokenInfoGetter } = require('../token-util') +TxList.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(TxList) + function mapStateToProps (state) { return { txsToRender: selectors.transactionsSelector(state), @@ -39,7 +45,7 @@ TxList.prototype.render = function () { return h('div.flex-column', [ h('div.flex-row.tx-list-header-wrapper', [ h('div.flex-row.tx-list-header', [ - h('div', this.props.t('transactions')), + h('div', this.context.t('transactions')), ]), ]), h('div.flex-column.tx-list-container', {}, [ @@ -56,7 +62,7 @@ TxList.prototype.renderTransaction = function () { : [h( 'div.tx-list-item.tx-list-item--empty', { key: 'tx-list-none' }, - [ this.props.t('noTransactions') ], + [ this.context.t('noTransactions') ], )] } @@ -110,7 +116,7 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa if (isUnapproved) { opts.onClick = () => showConfTxPage({ id: transactionId }) - opts.transactionStatus = this.props.t('notStarted') + opts.transactionStatus = this.context.t('notStarted') } else if (transactionHash) { opts.onClick = () => this.view(transactionHash, transactionNetworkId) } diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js index 8b0cc890a..ca24e813f 100644 --- a/ui/app/components/tx-view.js +++ b/ui/app/components/tx-view.js @@ -1,5 +1,6 @@ const Component = require('react').Component -const connect = require('../metamask-connect') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect const h = require('react-hyperscript') const ethUtil = require('ethereumjs-util') const inherits = require('util').inherits @@ -10,8 +11,13 @@ const BalanceComponent = require('./balance-component') const TxList = require('./tx-list') const Identicon = require('./identicon') +TxView.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(TxView) + function mapStateToProps (state) { const sidebarOpen = state.appState.sidebarOpen const isMascara = state.appState.isMascara @@ -72,21 +78,21 @@ TxView.prototype.renderButtons = function () { onClick: () => showModal({ name: 'DEPOSIT_ETHER', }), - }, this.props.t('deposit')), + }, this.context.t('deposit')), h('button.btn-primary.hero-balance-button', { style: { marginLeft: '0.8em', }, onClick: showSendPage, - }, this.props.t('send')), + }, this.context.t('send')), ]) ) : ( h('div.flex-row.flex-center.hero-balance-buttons', [ h('button.btn-primary.hero-balance-button', { onClick: showSendTokenPage, - }, this.props.t('send')), + }, this.context.t('send')), ]) ) } diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index 5f1ed7b60..e6b94ad12 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -1,5 +1,6 @@ const Component = require('react').Component -const connect = require('../metamask-connect') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect const h = require('react-hyperscript') const inherits = require('util').inherits const classnames = require('classnames') @@ -12,8 +13,13 @@ const BalanceComponent = require('./balance-component') const TokenList = require('./token-list') const selectors = require('../selectors') +WalletView.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(WalletView) + function mapStateToProps (state) { return { @@ -116,7 +122,7 @@ WalletView.prototype.render = function () { onClick: hideSidebar, }), - h('div.wallet-view__keyring-label.allcaps', isLoose ? this.props.t('imported') : ''), + h('div.wallet-view__keyring-label.allcaps', isLoose ? this.context.t('imported') : ''), h('div.flex-column.flex-center.wallet-view__name-container', { style: { margin: '0 auto' }, @@ -133,13 +139,13 @@ WalletView.prototype.render = function () { selectedIdentity.name, ]), - h('button.btn-clear.wallet-view__details-button.allcaps', this.props.t('details')), + h('button.btn-clear.wallet-view__details-button.allcaps', this.context.t('details')), ]), ]), h(Tooltip, { position: 'bottom', - title: this.state.hasCopied ? this.props.t('copiedExclamation') : this.props.t('copyToClipboard'), + title: this.state.hasCopied ? this.context.t('copiedExclamation') : this.context.t('copyToClipboard'), wrapperClassName: 'wallet-view__tooltip', }, [ h('button.wallet-view__address', { @@ -172,7 +178,7 @@ WalletView.prototype.render = function () { showAddTokenPage() hideSidebar() }, - }, this.props.t('addToken')), + }, this.context.t('addToken')), ]) } diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js index 03848f490..1070436c3 100644 --- a/ui/app/conf-tx.js +++ b/ui/app/conf-tx.js @@ -1,7 +1,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('./metamask-connect') +const connect = require('react-redux').connect const actions = require('./actions') const txHelper = require('../lib/tx-helper') diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js index c0c2d3ed0..4ab5f06c0 100644 --- a/ui/app/first-time/init-menu.js +++ b/ui/app/first-time/init-menu.js @@ -1,7 +1,8 @@ const inherits = require('util').inherits const EventEmitter = require('events').EventEmitter const Component = require('react').Component -const connect = require('../metamask-connect') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect const h = require('react-hyperscript') const Mascot = require('../components/mascot') const actions = require('../actions') @@ -12,8 +13,13 @@ const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums let isSubmitting = false +InitializeMenuScreen.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(InitializeMenuScreen) + inherits(InitializeMenuScreen, Component) function InitializeMenuScreen () { Component.call(this) @@ -59,7 +65,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: '#7F8082', marginBottom: 10, }, - }, this.props.t('appName')), + }, this.context.t('appName')), h('div', [ @@ -69,10 +75,10 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: '#7F8082', display: 'inline', }, - }, this.props.t('encryptNewDen')), + }, this.context.t('encryptNewDen')), h(Tooltip, { - title: this.props.t('denExplainer'), + title: this.context.t('denExplainer'), }, [ h('i.fa.fa-question-circle.pointer', { style: { @@ -92,7 +98,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: this.props.t('newPassword'), + placeholder: this.context.t('newPassword'), onInput: this.inputChanged.bind(this), style: { width: 260, @@ -104,7 +110,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box-confirm', - placeholder: this.props.t('confirmPassword'), + placeholder: this.context.t('confirmPassword'), onKeyPress: this.createVaultOnEnter.bind(this), onInput: this.inputChanged.bind(this), style: { @@ -119,7 +125,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { style: { margin: 12, }, - }, this.props.t('createDen')), + }, this.context.t('createDen')), h('.flex-row.flex-center.flex-grow', [ h('p.pointer', { @@ -129,7 +135,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: 'rgb(247, 134, 28)', textDecoration: 'underline', }, - }, this.props.t('importDen')), + }, this.context.t('importDen')), ]), h('.flex-row.flex-center.flex-grow', [ @@ -178,12 +184,12 @@ InitializeMenuScreen.prototype.createNewVaultAndKeychain = function () { var passwordConfirm = passwordConfirmBox.value if (password.length < 8) { - this.warning = this.props.t('passwordShort') + this.warning = this.context.t('passwordShort') this.props.dispatch(actions.displayWarning(this.warning)) return } if (password !== passwordConfirm) { - this.warning = this.props.t('passwordMismatch') + this.warning = this.context.t('passwordMismatch') this.props.dispatch(actions.displayWarning(this.warning)) return } diff --git a/ui/app/i18n-provider.js b/ui/app/i18n-provider.js new file mode 100644 index 000000000..57482985d --- /dev/null +++ b/ui/app/i18n-provider.js @@ -0,0 +1,37 @@ +const { Component } = require('react') +const connect = require('react-redux').connect +const h = require('react-hyperscript') +const PropTypes = require('prop-types') +const t = require('../i18n-helper').getMessage + +class I18nProvider extends Component { + getChildContext() { + const { localeMessages } = this.props + return { + t: t.bind(null, localeMessages), + } + } + + render() { + return h('div', [ this.props.children ]) + } +} + +I18nProvider.propTypes = { + localeMessages: PropTypes.object, + children: PropTypes.object, +} + +I18nProvider.childContextTypes = { + t: PropTypes.func, +} + +const mapStateToProps = state => { + const { localeMessages } = state + return { + localeMessages, + } +} + +module.exports = connect(mapStateToProps)(I18nProvider) + diff --git a/ui/app/keychains/hd/create-vault-complete.js b/ui/app/keychains/hd/create-vault-complete.js index 9d99eeb0d..5ab5d4c33 100644 --- a/ui/app/keychains/hd/create-vault-complete.js +++ b/ui/app/keychains/hd/create-vault-complete.js @@ -1,6 +1,6 @@ const inherits = require('util').inherits const Component = require('react').Component -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const h = require('react-hyperscript') const actions = require('../../actions') const exportAsFile = require('../../util').exportAsFile diff --git a/ui/app/keychains/hd/recover-seed/confirmation.js b/ui/app/keychains/hd/recover-seed/confirmation.js index f97ac66fe..02183f096 100644 --- a/ui/app/keychains/hd/recover-seed/confirmation.js +++ b/ui/app/keychains/hd/recover-seed/confirmation.js @@ -1,12 +1,17 @@ const inherits = require('util').inherits - const Component = require('react').Component -const connect = require('../../../metamask-connect') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect const h = require('react-hyperscript') const actions = require('../../../actions') +RevealSeedConfirmation.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(RevealSeedConfirmation) + inherits(RevealSeedConfirmation, Component) function RevealSeedConfirmation () { Component.call(this) @@ -49,13 +54,13 @@ RevealSeedConfirmation.prototype.render = function () { }, }, [ - h('h4', this.props.t('revealSeedWordsWarning')), + h('h4', this.context.t('revealSeedWordsWarning')), // confirmation h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: this.props.t('enterPasswordConfirm'), + placeholder: this.context.t('enterPasswordConfirm'), onKeyPress: this.checkConfirmation.bind(this), style: { width: 260, @@ -91,7 +96,7 @@ RevealSeedConfirmation.prototype.render = function () { ), props.inProgress && ( - h('span.in-progress-notification', this.props.t('generatingSeed')) + h('span.in-progress-notification', this.context.t('generatingSeed')) ), ]), ]) diff --git a/ui/app/keychains/hd/restore-vault.js b/ui/app/keychains/hd/restore-vault.js index f47a2641a..38ad14adb 100644 --- a/ui/app/keychains/hd/restore-vault.js +++ b/ui/app/keychains/hd/restore-vault.js @@ -1,11 +1,17 @@ const inherits = require('util').inherits +const PropTypes = require('prop-types') const PersistentForm = require('../../../lib/persistent-form') -const connect = require('../../metamask-connect') +const connect = require('react-redux').connect const h = require('react-hyperscript') const actions = require('../../actions') +RestoreVaultScreen.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(RestoreVaultScreen) + inherits(RestoreVaultScreen, PersistentForm) function RestoreVaultScreen () { PersistentForm.call(this) @@ -36,23 +42,23 @@ RestoreVaultScreen.prototype.render = function () { padding: 6, }, }, [ - this.props.t('restoreVault'), + this.context.t('restoreVault'), ]), // wallet seed entry - h('h3', this.props.t('walletSeed')), + h('h3', this.context.t('walletSeed')), h('textarea.twelve-word-phrase.letter-spacey', { dataset: { persistentFormId: 'wallet-seed', }, - placeholder: this.props.t('secretPhrase'), + placeholder: this.context.t('secretPhrase'), }), // password h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: this.props.t('newPassword8Chars'), + placeholder: this.context.t('newPassword8Chars'), dataset: { persistentFormId: 'password', }, @@ -66,7 +72,7 @@ RestoreVaultScreen.prototype.render = function () { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box-confirm', - placeholder: this.props.t('confirmPassword'), + placeholder: this.context.t('confirmPassword'), onKeyPress: this.createOnEnter.bind(this), dataset: { persistentFormId: 'password-confirmation', @@ -96,7 +102,7 @@ RestoreVaultScreen.prototype.render = function () { style: { textTransform: 'uppercase', }, - }, this.props.t('cancel')), + }, this.context.t('cancel')), // submit h('button.primary', { @@ -104,7 +110,7 @@ RestoreVaultScreen.prototype.render = function () { style: { textTransform: 'uppercase', }, - }, this.props.t('ok')), + }, this.context.t('ok')), ]), ]) ) @@ -135,13 +141,13 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () { var passwordConfirmBox = document.getElementById('password-box-confirm') var passwordConfirm = passwordConfirmBox.value if (password.length < 8) { - this.warning = this.props.t('passwordNotLongEnough') + this.warning = this.context.t('passwordNotLongEnough') this.props.dispatch(actions.displayWarning(this.warning)) return } if (password !== passwordConfirm) { - this.warning = this.props.t('passwordsDontMatch') + this.warning = this.context.t('passwordsDontMatch') this.props.dispatch(actions.displayWarning(this.warning)) return } @@ -151,18 +157,18 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () { // true if the string has more than a space between words. if (seed.split(' ').length > 1) { - this.warning = this.props.t('spaceBetween') + this.warning = this.context.t('spaceBetween') this.props.dispatch(actions.displayWarning(this.warning)) return } // true if seed contains a character that is not between a-z or a space if (!seed.match(/^[a-z ]+$/)) { - this.warning = this.props.t('loweCaseWords') + this.warning = this.context.t('loweCaseWords') this.props.dispatch(actions.displayWarning(this.warning)) return } if (seed.split(' ').length !== 12) { - this.warning = this.props.t('seedPhraseReq') + this.warning = this.context.t('seedPhraseReq') this.props.dispatch(actions.displayWarning(this.warning)) return } diff --git a/ui/app/new-keychain.js b/ui/app/new-keychain.js index 6337faa08..cc9633166 100644 --- a/ui/app/new-keychain.js +++ b/ui/app/new-keychain.js @@ -1,7 +1,7 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') -const connect = require('./metamask-connect') +const connect = require('react-redux').connect module.exports = connect(mapStateToProps)(NewKeychain) diff --git a/ui/app/root.js b/ui/app/root.js index 21d6d1829..58605a3d2 100644 --- a/ui/app/root.js +++ b/ui/app/root.js @@ -3,6 +3,7 @@ const Component = require('react').Component const Provider = require('react-redux').Provider const h = require('react-hyperscript') const SelectedApp = require('./select-app') +const I18nProvider = require('./i18n-provider') module.exports = Root @@ -15,7 +16,7 @@ Root.prototype.render = function () { h(Provider, { store: this.props.store, }, [ - h(SelectedApp), + h(I18nProvider, [ h(SelectedApp) ]), ]) ) diff --git a/ui/app/select-app.js b/ui/app/select-app.js index fca3decce..193c98353 100644 --- a/ui/app/select-app.js +++ b/ui/app/select-app.js @@ -1,6 +1,6 @@ const inherits = require('util').inherits const Component = require('react').Component -const connect = require('./metamask-connect') +const connect = require('react-redux').connect const h = require('react-hyperscript') const App = require('./app') const OldApp = require('../../old-ui/app/app') diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index 52b8bb273..910312b47 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -1,4 +1,5 @@ const { inherits } = require('util') +const PropTypes = require('prop-types') const PersistentForm = require('../lib/persistent-form') const h = require('react-hyperscript') @@ -29,6 +30,10 @@ const { } = require('./components/send/send-utils') const { isValidAddress } = require('./util') +SendTransactionScreen.contextTypes = { + t: PropTypes.func, +} + module.exports = SendTransactionScreen inherits(SendTransactionScreen, PersistentForm) @@ -188,9 +193,9 @@ SendTransactionScreen.prototype.renderHeader = function () { return h('div.page-container__header', [ - h('div.page-container__title', selectedToken ? this.props.t('sendTokens') : this.props.t('sendETH')), + h('div.page-container__title', selectedToken ? this.context.t('sendTokens') : this.context.t('sendETH')), - h('div.page-container__subtitle', this.props.t('onlySendToEtherAddress')), + h('div.page-container__subtitle', this.context.t('onlySendToEtherAddress')), h('div.page-container__header-close', { onClick: () => { @@ -261,11 +266,11 @@ SendTransactionScreen.prototype.handleToChange = function (to, nickname = '') { let toError = null if (!to) { - toError = this.props.t('required') + toError = this.context.t('required') } else if (!isValidAddress(to)) { - toError = this.props.t('invalidAddressRecipient') + toError = this.context.t('invalidAddressRecipient') } else if (to === from) { - toError = this.props.t('fromToSame') + toError = this.context.t('fromToSame') } updateSendTo(to, nickname) @@ -281,9 +286,9 @@ SendTransactionScreen.prototype.renderToRow = function () { h('div.send-v2__form-label', [ - this.props.t('to'), + this.context.t('to'), - this.renderErrorMessage(this.props.t('to')), + this.renderErrorMessage(this.context.t('to')), ]), @@ -384,11 +389,11 @@ SendTransactionScreen.prototype.validateAmount = function (value) { ) if (conversionRate && !sufficientBalance) { - amountError = this.props.t('insufficientFunds') + amountError = this.context.t('insufficientFunds') } else if (verifyTokenBalance && !sufficientTokens) { - amountError = this.props.t('insufficientTokens') + amountError = this.context.t('insufficientTokens') } else if (amountLessThanZero) { - amountError = this.props.t('negativeETH') + amountError = this.context.t('negativeETH') } updateSendErrors({ amount: amountError }) @@ -418,7 +423,7 @@ SendTransactionScreen.prototype.renderAmountRow = function () { setMaxModeTo(true) this.setAmountToMax() }, - }, [ !maxModeOn ? this.props.t('max') : '' ]), + }, [ !maxModeOn ? this.context.t('max') : '' ]), ]), h('div.send-v2__form-field', [ @@ -447,7 +452,7 @@ SendTransactionScreen.prototype.renderGasRow = function () { return h('div.send-v2__form-row', [ - h('div.send-v2__form-label', h('gasFee')), + h('div.send-v2__form-label', this.context.t('gasFee')), h('div.send-v2__form-field', [ @@ -517,11 +522,11 @@ SendTransactionScreen.prototype.renderFooter = function () { clearSend() goHome() }, - }, this.props.t('cancel')), + }, this.context.t('cancel')), h('button.btn-primary--lg.page-container__footer-button', { disabled: !noErrors || !gasTotal || missingTokenBalance, onClick: event => this.onSubmit(event), - }, this.props.t('next')), + }, this.context.t('next')), ]) } diff --git a/ui/app/settings.js b/ui/app/settings.js index 8764dcafe..e91ac7340 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -1,7 +1,7 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const connect = require('./metamask-connect') +const connect = require('react-redux').connect const actions = require('./actions') const infuraCurrencies = require('./infura-conversion.json') const validUrl = require('valid-url') @@ -55,8 +55,8 @@ class Settings extends Component { return h('div.settings__tabs', [ h(TabBar, { tabs: [ - { content: this.props.t('settings'), key: 'settings' }, - { content: this.props.t('info'), key: 'info' }, + { content: this.context.t('settings'), key: 'settings' }, + { content: this.context.t('info'), key: 'info' }, ], defaultTab: activeTab, tabSelected: key => this.setState({ activeTab: key }), @@ -69,7 +69,7 @@ class Settings extends Component { return h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', this.props.t('blockiesIdenticon')), + h('span', this.context.t('blockiesIdenticon')), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ @@ -89,13 +89,13 @@ class Settings extends Component { return h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', this.props.t('currentConversion')), + h('span', this.context.t('currentConversion')), h('span.settings__content-description', `Updated ${Date(conversionDate)}`), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h(SimpleDropdown, { - placeholder: this.props.t('selectCurrency'), + placeholder: this.context.t('selectCurrency'), options: getInfuraCurrencyOptions(), selectedOption: currentCurrency, onSelect: newCurrency => setCurrentCurrency(newCurrency), @@ -136,31 +136,31 @@ class Settings extends Component { switch (provider.type) { case 'mainnet': - title = this.props.t('currentNetwork') - value = this.props.t('mainnet') + title = this.context.t('currentNetwork') + value = this.context.t('mainnet') color = '#038789' break case 'ropsten': - title = this.props.t('currentNetwork') - value = this.props.t('ropsten') + title = this.context.t('currentNetwork') + value = this.context.t('ropsten') color = '#e91550' break case 'kovan': - title = this.props.t('currentNetwork') - value = this.props.t('kovan') + title = this.context.t('currentNetwork') + value = this.context.t('kovan') color = '#690496' break case 'rinkeby': - title = this.props.t('currentNetwork') - value = this.props.t('rinkeby') + title = this.context.t('currentNetwork') + value = this.context.t('rinkeby') color = '#ebb33f' break default: - title = this.props.t('currentRpc') + title = this.context.t('currentRpc') value = provider.rpcTarget } @@ -181,12 +181,12 @@ class Settings extends Component { return ( h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', this.props.t('newRPC')), + h('span', this.context.t('newRPC')), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('input.settings__input', { - placeholder: this.props.t('newRPC'), + placeholder: this.context.t('newRPC'), onChange: event => this.setState({ newRpc: event.target.value }), onKeyPress: event => { if (event.key === 'Enter') { @@ -199,7 +199,7 @@ class Settings extends Component { event.preventDefault() this.validateRpc(this.state.newRpc) }, - }, this.props.t('save')), + }, this.context.t('save')), ]), ]), ]) @@ -215,9 +215,9 @@ class Settings extends Component { const appendedRpc = `http://${newRpc}` if (validUrl.isWebUri(appendedRpc)) { - displayWarning(this.props.t('uriErrorMsg')) + displayWarning(this.context.t('uriErrorMsg')) } else { - displayWarning(this.props.t('invalidRPC')) + displayWarning(this.context.t('invalidRPC')) } } } @@ -226,10 +226,10 @@ class Settings extends Component { return ( h('div.settings__content-row', [ h('div.settings__content-item', [ - h('div', this.props.t('stateLogs')), + h('div', this.context.t('stateLogs')), h( 'div.settings__content-description', - this.props.t('stateLogsDescription') + this.context.t('stateLogsDescription') ), ]), h('div.settings__content-item', [ @@ -238,13 +238,13 @@ class Settings extends Component { onClick (event) { window.logStateString((err, result) => { if (err) { - this.state.dispatch(actions.displayWarning(this.props.t('stateLogError'))) + this.state.dispatch(actions.displayWarning(this.context.t('stateLogError'))) } else { exportAsFile('MetaMask State Logs.json', result) } }) }, - }, this.props.t('downloadStateLogs')), + }, this.context.t('downloadStateLogs')), ]), ]), ]) @@ -256,7 +256,7 @@ class Settings extends Component { return ( h('div.settings__content-row', [ - h('div.settings__content-item', this.props.t('revealSeedWords')), + h('div.settings__content-item', this.context.t('revealSeedWords')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('button.btn-primary--lg.settings__button--red', { @@ -264,7 +264,7 @@ class Settings extends Component { event.preventDefault() revealSeedConfirmation() }, - }, this.props.t('revealSeedWords')), + }, this.context.t('revealSeedWords')), ]), ]), ]) @@ -276,7 +276,7 @@ class Settings extends Component { return ( h('div.settings__content-row', [ - h('div.settings__content-item', this.props.t('useOldUI')), + h('div.settings__content-item', this.context.t('useOldUI')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('button.btn-primary--lg.settings__button--orange', { @@ -284,7 +284,7 @@ class Settings extends Component { event.preventDefault() setFeatureFlagToBeta() }, - }, this.props.t('useOldUI')), + }, this.context.t('useOldUI')), ]), ]), ]) @@ -295,7 +295,7 @@ class Settings extends Component { const { showResetAccountConfirmationModal } = this.props return h('div.settings__content-row', [ - h('div.settings__content-item', this.props.t('resetAccount')), + h('div.settings__content-item', this.context.t('resetAccount')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('button.btn-primary--lg.settings__button--orange', { @@ -303,7 +303,7 @@ class Settings extends Component { event.preventDefault() showResetAccountConfirmationModal() }, - }, this.props.t('resetAccount')), + }, this.context.t('resetAccount')), ]), ]), ]) @@ -339,13 +339,13 @@ class Settings extends Component { renderInfoLinks () { return ( h('div.settings__content-item.settings__content-item--without-height', [ - h('div.settings__info-link-header', this.props.t('links')), + h('div.settings__info-link-header', this.context.t('links')), h('div.settings__info-link-item', [ h('a', { href: 'https://metamask.io/privacy.html', target: '_blank', }, [ - h('span.settings__info-link', this.props.t('privacyMsg')), + h('span.settings__info-link', this.context.t('privacyMsg')), ]), ]), h('div.settings__info-link-item', [ @@ -353,7 +353,7 @@ class Settings extends Component { href: 'https://metamask.io/terms.html', target: '_blank', }, [ - h('span.settings__info-link', this.props.t('terms')), + h('span.settings__info-link', this.context.t('terms')), ]), ]), h('div.settings__info-link-item', [ @@ -361,7 +361,7 @@ class Settings extends Component { href: 'https://metamask.io/attributions.html', target: '_blank', }, [ - h('span.settings__info-link', this.props.t('attributions')), + h('span.settings__info-link', this.context.t('attributions')), ]), ]), h('hr.settings__info-separator'), @@ -370,7 +370,7 @@ class Settings extends Component { href: 'https://support.metamask.io', target: '_blank', }, [ - h('span.settings__info-link', this.props.t('supportCenter')), + h('span.settings__info-link', this.context.t('supportCenter')), ]), ]), h('div.settings__info-link-item', [ @@ -378,7 +378,7 @@ class Settings extends Component { href: 'https://metamask.io/', target: '_blank', }, [ - h('span.settings__info-link', this.props.t('visitWebSite')), + h('span.settings__info-link', this.context.t('visitWebSite')), ]), ]), h('div.settings__info-link-item', [ @@ -386,7 +386,7 @@ class Settings extends Component { target: '_blank', href: 'mailto:help@metamask.io?subject=Feedback', }, [ - h('span.settings__info-link', this.props.t('emailUs')), + h('span.settings__info-link', this.context.t('emailUs')), ]), ]), ]) @@ -408,7 +408,7 @@ class Settings extends Component { h('div.settings__info-item', [ h( 'div.settings__info-about', - this.props.t('builtInCalifornia') + this.context.t('builtInCalifornia') ), ]), ]), @@ -485,4 +485,9 @@ const mapDispatchToProps = dispatch => { } } +Settings.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(Settings) + diff --git a/ui/app/unlock.js b/ui/app/unlock.js index e8e1ba051..84d8b7e7c 100644 --- a/ui/app/unlock.js +++ b/ui/app/unlock.js @@ -1,7 +1,8 @@ const inherits = require('util').inherits const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') -const connect = require('./metamask-connect') +const connect = require('react-redux').connect const actions = require('./actions') const getCaretCoordinates = require('textarea-caret') const EventEmitter = require('events').EventEmitter @@ -10,8 +11,13 @@ const environmentType = require('../../app/scripts/lib/environment-type') const Mascot = require('./components/mascot') +UnlockScreen.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(UnlockScreen) + inherits(UnlockScreen, Component) function UnlockScreen () { Component.call(this) @@ -40,7 +46,7 @@ UnlockScreen.prototype.render = function () { textTransform: 'uppercase', color: '#7F8082', }, - }, this.props.t('appName')), + }, this.context.t('appName')), h('input.large-input', { type: 'password', @@ -66,7 +72,7 @@ UnlockScreen.prototype.render = function () { style: { margin: 10, }, - }, this.props.t('login')), + }, this.context.t('login')), h('p.pointer', { onClick: () => { @@ -80,7 +86,7 @@ UnlockScreen.prototype.render = function () { color: 'rgb(247, 134, 28)', textDecoration: 'underline', }, - }, this.props.t('restoreFromSeed')), + }, this.context.t('restoreFromSeed')), h('p.pointer', { onClick: () => { @@ -93,7 +99,7 @@ UnlockScreen.prototype.render = function () { textDecoration: 'underline', marginTop: '32px', }, - }, this.props.t('classicInterface')), + }, this.context.t('classicInterface')), ]) ) } From a4594f6838a9ff38a9a6f1998850b27beebb2fbb Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 29 Mar 2018 15:30:03 -0230 Subject: [PATCH 117/246] Show insufficient funds on confirm screen on first render. --- ui/app/components/pending-tx/confirm-send-ether.js | 12 ++++++++++++ ui/app/components/pending-tx/confirm-send-token.js | 10 +++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index c91911c3d..78dae266d 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -103,6 +103,18 @@ function ConfirmSendEther () { this.onSubmit = this.onSubmit.bind(this) } +ConfirmSendEther.prototype.componentWillMount = function () { + const { updateSendErrors } = this.props + const txMeta = this.gatherTxMeta() + const balanceIsSufficient = this.isBalanceSufficient(txMeta) + + updateSendErrors({ + insufficientFunds: balanceIsSufficient + ? false + : this.props.t('insufficientFunds') + }) +} + ConfirmSendEther.prototype.getAmount = function () { const { conversionRate, currentCurrency } = this.props const txMeta = this.gatherTxMeta() diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index dd115e890..ed0be601e 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -142,12 +142,20 @@ function ConfirmSendToken () { } ConfirmSendToken.prototype.componentWillMount = function () { - const { tokenContract, selectedAddress } = this.props + const { tokenContract, selectedAddress, updateSendErrors} = this.props + const txMeta = this.gatherTxMeta() + const balanceIsSufficient = this.isBalanceSufficient(txMeta) tokenContract && tokenContract .balanceOf(selectedAddress) .then(usersToken => { }) this.props.updateTokenExchangeRate() + + updateSendErrors({ + insufficientFunds: balanceIsSufficient + ? false + : this.props.t('insufficientFunds') + }) } ConfirmSendToken.prototype.getAmount = function () { From 011bdd2d6e0f5f70cbc2829fd07ecc748944d2e9 Mon Sep 17 00:00:00 2001 From: Nico <35919226+AKingUltra@users.noreply.github.com> Date: Thu, 29 Mar 2018 20:18:49 +0200 Subject: [PATCH 118/246] i18n - Update German Locale --- app/_locales/de/messages.json | 63 ++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 0bdce516c..5116764d1 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -14,9 +14,15 @@ "address": { "message": "Adresse" }, + "addCustomToken": { + "message": "Eigenen Token hinzufügen" + }, "addToken": { "message": "Token hinzufügen" }, + "addTokens": { + "message": "Token hinzufügen" + }, "amount": { "message": "Betrag" }, @@ -31,9 +37,15 @@ "message": "MetaMask", "description": "Der Name der Erweiterung" }, + "approved": { + "message": "Genehmigt" + }, "attemptingConnect": { "message": "Versuch mit der Blockchain zu verbinden." }, + "attributions": { + "message": "Was wir verwenden" + }, "available": { "message": "Verfügbar" }, @@ -43,6 +55,9 @@ "balance": { "message": "Guthaben:" }, + "balances": { + "message": "Deine Guthaben" + }, "balanceIsInsufficientGas": { "message": "Guthaben unzureichend für den aktuellen gesamten Gasbetrag" }, @@ -69,7 +84,7 @@ "message": "Auf Coinbase kaufen" }, "buyCoinbaseExplainer": { - "message": "Coinbase ist die weltweit bekannteste Möglichkeit bitcoin, ethereum und litecoin zu kaufen und verkaufen." + "message": "Coinbase ist die weltweit bekannteste Art und Weise um bitcoin, ethereum und litecoin zu kaufen und verkaufen." }, "ok": { "message": "Ok" @@ -105,7 +120,7 @@ "message": "Zu Coinbase fortfahren" }, "contractDeployment": { - "message": "Smart Contract ausführen" + "message": "Smart Contract Ausführung" }, "conversionProgress": { "message": "Umtausch in Arbeit" @@ -148,7 +163,7 @@ "description": "Börsentyp (Kryptowährungen)" }, "currentConversion": { - "message": "Aktueller Umtausch" + "message": "Aktuelle Tauschwährung" }, "currentNetwork": { "message": "Aktuelles Netzwerk" @@ -185,7 +200,7 @@ "description": "Teilt dem Benutzer mit welchen Token er beim Einzahlen mit Shapeshift ausgewählt hat" }, "depositEth": { - "message": "Eth einzahlen" + "message": "Eth kaufen" }, "depositEther": { "message": "Ether einzahlen" @@ -274,7 +289,7 @@ "message": "Folge uns auf Twitter" }, "from": { - "message": "von" + "message": "Von" }, "fromToSame": { "message": "Ziel- und Ursprungsadresse dürfen nicht identisch sein" @@ -347,14 +362,14 @@ "message": "Es erlaubt dir ether & Token zu halten und dient dir als Verbindung zu dezentralisierten Applikationen." }, "import": { - "message": "Import", + "message": "Importieren", "description": "Button um den Account aus einer ausgewählten Datei zu importieren" }, "importAccount": { "message": "Account importieren" }, "importAccountMsg": { - "message":" Importierte Accounts werden nicht mit der Seed Wörterfolge deines ursprünglichen MetaMask Accounts verknüpft. Erfahre mehr über importierte Accounts." + "message":" Importierte Accounts werden nicht mit der Seed-Wörterfolge deines ursprünglichen MetaMask Accounts verknüpft. Erfahre mehr über importierte Accounts." }, "importAnAccount": { "message": "Einen Account importieren" @@ -369,7 +384,7 @@ "infoHelp": { "message": "Info & Hilfe" }, - "insufficientFunds": { + "insufficientFunds": { "message": "Nicht genügend Guthaben." }, "insufficientTokens": { @@ -441,10 +456,10 @@ "message": "Frei" }, "loweCaseWords": { - "message": "Die Wörter der Seed Wörterfolgen sind alle kleingeschrieben" + "message": "Die Wörter der Seed-Wörterfolgen sind alle kleingeschrieben" }, "mainnet": { - "message": "Ethereum Hauptnetzwerk (Main Net)" + "message": "Ethereum Main Net" }, "message": { "message": "Nachricht" @@ -541,7 +556,7 @@ "description": "Für den Import eine Accounts mit Hilfe eines Private Keys" }, "pasteSeed": { - "message": "Füge deine Seed Wörterfolge hier ein!" + "message": "Füge deine Seed-Wörterfolge hier ein!" }, "personalAddressDetected": { "message": "Personalisierte Adresse identifiziert. Bitte füge die Token Contract Adresse ein." @@ -557,7 +572,7 @@ "description": "Wähle diesen Dateityp um damit einen Account zu importieren" }, "privateKeyWarning": { - "message": "Warnung: Niemals jemanden deinen Private Key mitteilen. Jeder der im Besitz deines Private Keys ist, kann jegliches Guthaben deines Accounts stehlen." + "message": "Warnung: Niemals jemanden deinen Private Key mitteilen. Jeder der im Besitz deines Private Keys ist, kann jegliches Guthaben deines Accounts stehlen." }, "privateNetwork": { "message": "Privates Netzwerk" @@ -566,7 +581,7 @@ "message": "QR Code anzeigen" }, "readdToken": { - "message": "Du kannst diesen Token zukünftig wieder hinzufügen indem du in den Menüpunkt \"Token hinzufügen\" in den Einstellungen deines Accounts gehst." + "message": "Du kannst diesen Token immer erneut hinzufügen, indem du in den Menüpunkt \"Token hinzufügen\" in den Einstellungen deines Accounts gehst." }, "readMore": { "message": "Hier mehr erfahren." @@ -590,7 +605,7 @@ "message": "Account zurücksetzten" }, "restoreFromSeed": { - "message": "Mit Hilfe der Seed Wörterfolge wiederherstellen." + "message": "Mit Hilfe der Seed-Wörterfolge wiederherstellen." }, "restoreVault": { "message": "Vault wiederherstellen" @@ -605,13 +620,13 @@ "message": "Wallet Seed" }, "revealSeedWords": { - "message": "Seed Wörterfolge anzeigen" + "message": "Seed-Wörterfolge anzeigen" }, "revealSeedWordsWarning": { - "message": "Bitte niemals deine Seed Wörterfolge an einem öffentlichen Ort kenntlich machen. Mit diesen Wörtern können alle deine Accounts gestohlen werden." + "message": "Bitte niemals deine Seed-Wörterfolge an einem öffentlichen Ort kenntlich machen. Mit diesen Wörtern können alle deine Accounts gestohlen werden." }, "revert": { - "message": "Zurück gehen" + "message": "Rückgängig machen" }, "rinkeby": { "message": "Rinkeby Testnetzwerk" @@ -623,7 +638,7 @@ "message": "Aktueller RPC" }, "connectingToMainnet": { - "message": "Verbinde zum Ethereum Hauptnetzwerk (Main Net)" + "message": "Verbinde zum Ethereum Main Net" }, "connectingToRopsten": { "message": " Verbinde zum Ropsten Testnetzwerk" @@ -649,7 +664,7 @@ "description": "Prozess des Exportieren eines Accounts" }, "saveSeedAsFile": { - "message": "Seed Wörterfolge als Datei speichern" + "message": "Seed-Wörterfolge als Datei speichern" }, "search": { "message": "Suche" @@ -661,7 +676,7 @@ "message": "Neues Passwort (min. 8 Zeichen)" }, "seedPhraseReq": { - "message": "Seed Wörterfolgen bestehen aus 12 Wörtern" + "message": "Seed-Wörterfolgen bestehen aus 12 Wörtern" }, "select": { "message": "Auswählen" @@ -685,7 +700,7 @@ "message": "Token senden" }, "onlySendToEtherAddress": { - "message": "ETH nur zu einer Ethereum Adresse senden." + "message": "ETH unbedingt nur zu einer Ethereum Adresse senden." }, "sendTokensAnywhere": { "message": "Token zu einer beliebigen Person mit einem Ethereumaccount senden" @@ -742,7 +757,7 @@ "message": "Einreichen" }, "submitted": { - "message": "Eingereicht" + "message": "Abgeschickt" }, "supportCenter": { "message": "Gehe zu unserem Support Center" @@ -782,7 +797,7 @@ "message": "Tokensymbol" }, "tokenWarning1": { - "message": "Behalte die Token die du mit deinem MetaMask Account gekauft hast im Auge. Wenn du Token mit einem anderen Account gekauft hast, werden diese hier nicht angezeigt." + "message": "Behalte die Token die du mit deinem MetaMask Account gekauft hast im Blick. Wenn du Token mit einem anderen Account gekauft hast, werden diese hier nicht angezeigt." }, "total": { "message": "Gesamt" @@ -853,7 +868,7 @@ "message": " Account einsehen" }, "visitWebSite": { - "message": "Gehe zu unsere Webseite" + "message": "Gehe zu unserer Webseite" }, "warning": { "message": "Warnung" From 830b232cb967ee986706e39aed50ef9a6d729a1e Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 11:59:13 -0700 Subject: [PATCH 119/246] test - e2e - prefer css selectors over xpath --- test/e2e/metamask.spec.js | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index c73ba2b41..a7d0a0efd 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -14,7 +14,7 @@ describe('Metamask popup page', function () { const extPath = path.resolve('dist/chrome') driver = buildWebDriver(extPath) await driver.get('chrome://extensions-frame') - const elems = await driver.findElements(By.className('extension-list-item-wrapper')) + const elems = await driver.findElements(By.css('.extension-list-item-wrapper')) const extensionId = await elems[1].getAttribute('id') await driver.get(`chrome-extension://${extensionId}/popup.html`) await delay(500) @@ -37,9 +37,7 @@ describe('Metamask popup page', function () { }) it('should show privacy notice', async () => { - const privacy = await driver.findElement(By.className( - 'terms-header' - )).getText() + const privacy = await driver.findElement(By.css('.terms-header')).getText() assert.equal(privacy, 'PRIVACY NOTICE', 'shows privacy notice') driver.findElement(By.css( 'button' @@ -48,9 +46,7 @@ describe('Metamask popup page', function () { it('should show terms of use', async () => { await delay(300) - const terms = await driver.findElement(By.className( - 'terms-header' - )).getText() + const terms = await driver.findElement(By.css('.terms-header')).getText() assert.equal(terms, 'TERMS OF USE', 'shows terms of use') }) @@ -87,16 +83,16 @@ describe('Metamask popup page', function () { it('should show value was created and seed phrase', async () => { await delay(700) - this.seedPhase = await driver.findElement(By.className('twelve-word-phrase')).getText() + this.seedPhase = await driver.findElement(By.css('.twelve-word-phrase')).getText() const continueAfterSeedPhrase = await driver.findElement(By.css('button')) await continueAfterSeedPhrase.click() }) it('should show lock account', async () => { await delay(300) - await driver.findElement(By.className('sandwich-expando')).click() + await driver.findElement(By.css('.sandwich-expando')).click() await delay(500) - await driver.findElement(By.xpath('//*[@id="app-content"]/div/div[3]/span/div/li[2]')).click() + await driver.findElement(By.css('#app-content > div > div > div:nth-child(3) > span > div > li:nth-child(3)')).click() }) it('should accept account password after lock', async () => { @@ -106,16 +102,16 @@ describe('Metamask popup page', function () { await delay(500) }) - it('should show QR code', async () => { + it('should show QR code option', async () => { await delay(300) - await driver.findElement(By.className('fa-ellipsis-h')).click() - await driver.findElement(By.xpath('//*[@id="app-content"]/div/div[4]/div/div/div[1]/flex-column/div[1]/div/span/i/div/div/li[2]')).click() + await driver.findElement(By.css('.fa-ellipsis-h')).click() + await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div:nth-child(1) > flex-column > div.name-label > div > span > i > div > div > li:nth-child(3)')).click() await delay(300) }) it('should show the account address', async () => { - this.accountAddress = await driver.findElement(By.className('ellip-address')).getText() - await driver.findElement(By.className('fa-arrow-left')).click() + this.accountAddress = await driver.findElement(By.css('.ellip-address')).getText() + await driver.findElement(By.css('.fa-arrow-left')).click() await delay(500) }) }) From 53172f1b5568e327782bde8cd34d963a8396782d Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 29 Mar 2018 12:06:23 -0700 Subject: [PATCH 120/246] Better delays and fix logout css selector --- test/e2e/metamask.spec.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index a7d0a0efd..b254d9a3c 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -42,12 +42,14 @@ describe('Metamask popup page', function () { driver.findElement(By.css( 'button' )).click() + await delay(300) }) it('should show terms of use', async () => { await delay(300) const terms = await driver.findElement(By.css('.terms-header')).getText() assert.equal(terms, 'TERMS OF USE', 'shows terms of use') + await delay(300) }) it('should be unable to continue without scolling throught the terms of use', async () => { @@ -59,6 +61,7 @@ describe('Metamask popup page', function () { 'Attributions' )) await driver.executeScript('arguments[0].scrollIntoView(true)', element) + await delay(300) }) it('should be able to continue when scrolled to the bottom of terms of use', async () => { @@ -67,10 +70,10 @@ describe('Metamask popup page', function () { await delay(500) assert.equal(buttonEnabled, true, 'enabled continue button') await button.click() + await delay(300) }) it('should accept password with length of eight', async () => { - await delay(300) const passwordBox = await driver.findElement(By.id('password-box')) const passwordBoxConfirm = await driver.findElement(By.id('password-box-confirm')) const button = driver.findElement(By.css('button')) @@ -86,13 +89,13 @@ describe('Metamask popup page', function () { this.seedPhase = await driver.findElement(By.css('.twelve-word-phrase')).getText() const continueAfterSeedPhrase = await driver.findElement(By.css('button')) await continueAfterSeedPhrase.click() + await delay(300) }) it('should show lock account', async () => { - await delay(300) await driver.findElement(By.css('.sandwich-expando')).click() await delay(500) - await driver.findElement(By.css('#app-content > div > div > div:nth-child(3) > span > div > li:nth-child(3)')).click() + await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)')).click() }) it('should accept account password after lock', async () => { From 4d2d3d443076e4b399c5e9266c62e3f09218d069 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 29 Mar 2018 12:28:50 -0700 Subject: [PATCH 121/246] Increase permitted safe gas limit Block gas limits have been incredibly stable lately: https://etherscan.io/chart/gaslimit And this validation has prevented Aragon's new beta from working: https://twitter.com/izqui9/status/979373309312815104 Fixes #3790 --- old-ui/app/components/pending-tx.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/old-ui/app/components/pending-tx.js b/old-ui/app/components/pending-tx.js index 720df2243..7f63d9fdf 100644 --- a/old-ui/app/components/pending-tx.js +++ b/old-ui/app/components/pending-tx.js @@ -62,8 +62,8 @@ PendingTx.prototype.render = function () { const gasBn = hexToBn(gas) // default to 8MM gas limit const gasLimit = new BN(parseInt(blockGasLimit) || '8000000') - const safeGasLimitBN = this.bnMultiplyByFraction(gasLimit, 19, 20) - const saferGasLimitBN = this.bnMultiplyByFraction(gasLimit, 18, 20) + const safeGasLimitBN = this.bnMultiplyByFraction(gasLimit, 99, 100) + const saferGasLimitBN = this.bnMultiplyByFraction(gasLimit, 98, 100) const safeGasLimit = safeGasLimitBN.toString(10) // Gas Price @@ -311,7 +311,7 @@ PendingTx.prototype.render = function () { style: { fontSize: '0.9em', }, - }, 'Gas limit set dangerously high. Approving this transaction is likely to fail.') + }, 'Gas limit set dangerously high. Approving this transaction is liable to fail.') : null, ]), From 4cd9c155dbbf01621816891c66eef3b37fb2df92 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 29 Mar 2018 12:31:10 -0700 Subject: [PATCH 122/246] Bump changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06cf51c14..bb9554a87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Current Master - Fix bug where the "Reset account" feature would not clear the network cache. +- Increase maximum gas limit, to allow very gas heavy transactions, since block gas limits have been stable. ## 4.4.0 Mon Mar 26 2018 From 2328b120da60e97ec5a636fd3a743a12a3309b96 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 13:49:54 -0700 Subject: [PATCH 123/246] test - e2e - generate artifacts on test failure --- .gitignore | 2 ++ test/e2e/metamask.spec.js | 30 ++++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index f2a678777..dee5ec220 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,8 @@ test/background.js test/bundle.js test/test-bundle.js +test-artifacts + #ignore css output and sourcemaps ui/app/css/output/ diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index a7d0a0efd..88a695adf 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -1,5 +1,8 @@ +const fs = require('fs') +const mkdirp = require('mkdirp') const path = require('path') const assert = require('assert') +const pify = require('pify') const webdriver = require('selenium-webdriver') const By = webdriver.By const { delay, buildWebDriver } = require('./func') @@ -20,6 +23,12 @@ describe('Metamask popup page', function () { await delay(500) }) + afterEach(async function () { + if (this.currentTest.state === 'failed') { + await verboseReportOnFailure(this.currentTest) + } + }) + after(async function () { await driver.quit() }) @@ -39,9 +48,7 @@ describe('Metamask popup page', function () { it('should show privacy notice', async () => { const privacy = await driver.findElement(By.css('.terms-header')).getText() assert.equal(privacy, 'PRIVACY NOTICE', 'shows privacy notice') - driver.findElement(By.css( - 'button' - )).click() + driver.findElement(By.css('button')).click() }) it('should show terms of use', async () => { @@ -51,9 +58,7 @@ describe('Metamask popup page', function () { }) it('should be unable to continue without scolling throught the terms of use', async () => { - const button = await driver.findElement(By.css( - 'button' - )).isEnabled() + const button = await driver.findElement(By.css('button')).isEnabled() assert.equal(button, false, 'disabled continue button') const element = driver.findElement(By.linkText( 'Attributions' @@ -115,4 +120,17 @@ describe('Metamask popup page', function () { await delay(500) }) }) + + async function verboseReportOnFailure(test) { + const artifactDir = `./test-artifacts/${test.title}` + const filepathBase = `${artifactDir}/test-failure` + await pify(mkdirp)(artifactDir) + // capture screenshot + const screenshot = await driver.takeScreenshot() + await pify(fs.writeFile)(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' }) + // capture dom source + const htmlSource = await driver.getPageSource() + await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource) + } + }) From 552fb1fabecd2f2de0c500aeee2fe633e69e7f5a Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 13:54:01 -0700 Subject: [PATCH 124/246] test - e2e - fix selector with extra div (?) --- test/e2e/metamask.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index 88a695adf..1ea8ffdf3 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -97,7 +97,7 @@ describe('Metamask popup page', function () { await delay(300) await driver.findElement(By.css('.sandwich-expando')).click() await delay(500) - await driver.findElement(By.css('#app-content > div > div > div:nth-child(3) > span > div > li:nth-child(3)')).click() + await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)')).click() }) it('should accept account password after lock', async () => { From f6f8cab5dc9ecf750f6e567d0effe0bacc2495d8 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 13:59:39 -0700 Subject: [PATCH 125/246] ci - upload e2e test artifacts --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 75819fc6e..ae6f44c8a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -141,6 +141,9 @@ jobs: - run: name: Test command: npm run test:e2e + - store_artifacts: + path: test-artifacts + destination: test-artifacts test-unit: docker: From ad603da2e72fbc64733836e1b3626627de81fa76 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 29 Mar 2018 20:16:45 -0230 Subject: [PATCH 126/246] Stopping wrapping provider children in div; stop wrapping old-ui in provider. --- ui/app/i18n-provider.js | 3 +-- ui/app/root.js | 3 +-- ui/app/select-app.js | 5 +++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/app/i18n-provider.js b/ui/app/i18n-provider.js index 57482985d..fe6d62c67 100644 --- a/ui/app/i18n-provider.js +++ b/ui/app/i18n-provider.js @@ -1,6 +1,5 @@ const { Component } = require('react') const connect = require('react-redux').connect -const h = require('react-hyperscript') const PropTypes = require('prop-types') const t = require('../i18n-helper').getMessage @@ -13,7 +12,7 @@ class I18nProvider extends Component { } render() { - return h('div', [ this.props.children ]) + return this.props.children } } diff --git a/ui/app/root.js b/ui/app/root.js index 58605a3d2..21d6d1829 100644 --- a/ui/app/root.js +++ b/ui/app/root.js @@ -3,7 +3,6 @@ const Component = require('react').Component const Provider = require('react-redux').Provider const h = require('react-hyperscript') const SelectedApp = require('./select-app') -const I18nProvider = require('./i18n-provider') module.exports = Root @@ -16,7 +15,7 @@ Root.prototype.render = function () { h(Provider, { store: this.props.store, }, [ - h(I18nProvider, [ h(SelectedApp) ]), + h(SelectedApp), ]) ) diff --git a/ui/app/select-app.js b/ui/app/select-app.js index 193c98353..101eb1cf6 100644 --- a/ui/app/select-app.js +++ b/ui/app/select-app.js @@ -7,6 +7,7 @@ const OldApp = require('../../old-ui/app/app') const { autoAddToBetaUI } = require('./selectors') const { setFeatureFlag, setNetworkEndpoints } = require('./actions') const { BETA_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums +const I18nProvider = require('./i18n-provider') function mapStateToProps (state) { return { @@ -62,7 +63,7 @@ SelectedApp.prototype.render = function () { // const Selected = betaUI || isMascara || firstTime ? App : OldApp const { betaUI, isMascara } = this.props - const Selected = betaUI || isMascara ? App : OldApp + const Selected = betaUI || isMascara ? h(I18nProvider, [ h(App) ]) : h(OldApp) - return h(Selected) + return Selected } From 0a48aa84ca45ce495f1c1a23b28876bcc0fb243b Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 29 Mar 2018 20:52:45 -0230 Subject: [PATCH 127/246] Add changelog entry for language selection. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb9554a87..5d5d3cc1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Fix bug where the "Reset account" feature would not clear the network cache. - Increase maximum gas limit, to allow very gas heavy transactions, since block gas limits have been stable. +- Allow user to select language on settings page ## 4.4.0 Mon Mar 26 2018 From 592c2e59484d94f2674ea2a9570436b664d94b0a Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 17:02:40 -0700 Subject: [PATCH 128/246] test - add auto screen shotter --- package.json | 6 +- test/screens/func.js | 18 +++++ test/screens/new.spec.js | 148 +++++++++++++++++++++++++++++++++++++++ test/screens/old.spec.js | 105 +++++++++++++++++++++++++++ 4 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 test/screens/func.js create mode 100644 test/screens/new.spec.js create mode 100644 test/screens/old.spec.js diff --git a/package.json b/package.json index 6cd8f7f4e..16c2d735d 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara", "test:integration:build": "gulp build:scss", "test:e2e": "METAMASK_ENV=test mocha test/e2e/metamask.spec --recursive", + "test:screens": "METAMASK_ENV=test mocha test/screens/new.spec --recursive", "test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload", "test:coveralls-upload": "if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi", "test:flat": "npm run test:flat:build && karma start test/flat.conf.js", @@ -219,6 +220,7 @@ "eslint-plugin-react": "^7.4.0", "eth-json-rpc-middleware": "^1.2.7", "fs-promise": "^2.0.3", + "gifencoder": "^1.1.0", "gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed", "gulp-babel": "^7.0.0", "gulp-eslint": "^4.0.0", @@ -234,6 +236,7 @@ "gulp-util": "^3.0.7", "gulp-watch": "^5.0.0", "gulp-zip": "^4.0.0", + "image-size": "^0.6.2", "isomorphic-fetch": "^2.2.1", "jsdom": "^11.2.0", "jsdom-global": "^3.0.2", @@ -252,14 +255,15 @@ "node-sass": "^4.7.2", "nyc": "^11.0.3", "open": "0.0.5", + "png-file-stream": "^1.0.0", "prompt": "^1.0.0", "qs": "^6.2.0", "qunitjs": "^2.4.1", "react-addons-test-utils": "^15.5.1", "react-test-renderer": "^15.6.2", "react-testutils-additions": "^15.2.0", - "selenium-webdriver": "^3.5.0", "redux-test-utils": "^0.2.2", + "selenium-webdriver": "^3.5.0", "sinon": "^5.0.0", "stylelint-config-standard": "^18.2.0", "tape": "^4.5.1", diff --git a/test/screens/func.js b/test/screens/func.js new file mode 100644 index 000000000..733225565 --- /dev/null +++ b/test/screens/func.js @@ -0,0 +1,18 @@ +require('chromedriver') +const webdriver = require('selenium-webdriver') + +exports.delay = function delay (time) { + return new Promise(resolve => setTimeout(resolve, time)) +} + + +exports.buildWebDriver = function buildWebDriver (extPath) { + return new webdriver.Builder() + .withCapabilities({ + chromeOptions: { + args: [`load-extension=${extPath}`], + }, + }) + .forBrowser('chrome') + .build() +} diff --git a/test/screens/new.spec.js b/test/screens/new.spec.js new file mode 100644 index 000000000..c5a8ef859 --- /dev/null +++ b/test/screens/new.spec.js @@ -0,0 +1,148 @@ +const path = require('path') +const fs = require('fs') +const pify = require('pify') +const mkdirp = require('mkdirp') +const webdriver = require('selenium-webdriver') +const endOfStream = require('end-of-stream') +const GIFEncoder = require('gifencoder') +const pngFileStream = require('png-file-stream') +const sizeOfPng = require('image-size/lib/types/png') +const By = webdriver.By +const { delay, buildWebDriver } = require('./func') + +captureAllScreens().catch(console.error) + +async function captureAllScreens() { + let screenshotCount = 0 + + // setup selenium and install extension + const extPath = path.resolve('dist/chrome') + const driver = buildWebDriver(extPath) + await driver.get('chrome://extensions-frame') + const elems = await driver.findElements(By.css('.extension-list-item-wrapper')) + const extensionId = await elems[1].getAttribute('id') + await driver.get(`chrome-extension://${extensionId}/popup.html`) + await delay(500) + const tabs = await driver.getAllWindowHandles() + await driver.switchTo().window(tabs[0]) + await delay(300) + + // common names + let button + + await captureScreenShot('start-old') + + // click try new ui + await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-center.flex-grow > p')).click() + await captureScreenShot('start-new') + await delay(300) + await captureScreenShot('start-new2') + await delay(300) + await captureScreenShot('start-new3') + await delay(300) + await captureScreenShot('start-new4') + await delay(300) + await captureScreenShot('start-new5') + + // exit early for dev + await generateGif() + await driver.quit() + return + + + await captureScreenShot('privacy') + + const privacy = await driver.findElement(By.css('.terms-header')).getText() + driver.findElement(By.css('button')).click() + await delay(300) + await captureScreenShot('terms') + + await delay(300) + const terms = await driver.findElement(By.css('.terms-header')).getText() + await delay(300) + const element = driver.findElement(By.linkText('Attributions')) + await driver.executeScript('arguments[0].scrollIntoView(true)', element) + await delay(300) + button = await driver.findElement(By.css('button')) + const buttonEnabled = await button.isEnabled() + await delay(500) + await captureScreenShot('terms-scrolled') + + await button.click() + await delay(300) + await captureScreenShot('choose-password') + + const passwordBox = await driver.findElement(By.id('password-box')) + const passwordBoxConfirm = await driver.findElement(By.id('password-box-confirm')) + button = driver.findElement(By.css('button')) + passwordBox.sendKeys('123456789') + passwordBoxConfirm.sendKeys('123456789') + await delay(500) + await captureScreenShot('choose-password-filled') + + await button.click() + await delay(700) + this.seedPhase = await driver.findElement(By.css('.twelve-word-phrase')).getText() + await captureScreenShot('seed phrase') + + const continueAfterSeedPhrase = await driver.findElement(By.css('button')) + await continueAfterSeedPhrase.click() + await delay(300) + await captureScreenShot('main screen') + + await driver.findElement(By.css('.sandwich-expando')).click() + await delay(500) + await captureScreenShot('menu') + + // await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)')).click() + // await captureScreenShot('main screen') + // it('should accept account password after lock', async () => { + // await delay(500) + // await driver.findElement(By.id('password-box')).sendKeys('123456789') + // await driver.findElement(By.css('button')).click() + // await delay(500) + // }) + // + // it('should show QR code option', async () => { + // await delay(300) + // await driver.findElement(By.css('.fa-ellipsis-h')).click() + // await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div:nth-child(1) > flex-column > div.name-label > div > span > i > div > div > li:nth-child(3)')).click() + // await delay(300) + // }) + // + // it('should show the account address', async () => { + // this.accountAddress = await driver.findElement(By.css('.ellip-address')).getText() + // await driver.findElement(By.css('.fa-arrow-left')).click() + // await delay(500) + // }) + + // cleanup + await driver.quit() + + async function captureScreenShot(label) { + const shotIndex = screenshotCount + screenshotCount++ + const artifactDir = `./test-artifacts/screens/` + await pify(mkdirp)(artifactDir) + // capture screenshot + const screenshot = await driver.takeScreenshot() + await pify(fs.writeFile)(`${artifactDir}/${shotIndex} - ${label}.png`, screenshot, { encoding: 'base64' }) + } + + async function generateGif(){ + // calculate screenshot size + const screenshot = await driver.takeScreenshot() + const pngBuffer = Buffer.from(screenshot, 'base64') + const size = sizeOfPng.calculate(pngBuffer) + + // read all pngs into gif + const encoder = new GIFEncoder(size.width, size.height) + const stream = pngFileStream('./test-artifacts/screens/*.png') + .pipe(encoder.createWriteStream({ repeat: -1, delay: 500, quality: 10 })) + .pipe(fs.createWriteStream('./test-artifacts/screens/walkthrough.gif')) + + // wait for end + await pify(endOfStream)(stream) + } + +} diff --git a/test/screens/old.spec.js b/test/screens/old.spec.js new file mode 100644 index 000000000..87399d4b5 --- /dev/null +++ b/test/screens/old.spec.js @@ -0,0 +1,105 @@ +const path = require('path') +const fs = require('fs') +const pify = require('pify') +const mkdirp = require('mkdirp') +const webdriver = require('selenium-webdriver') +const By = webdriver.By +const { delay, buildWebDriver } = require('./func') + +captureAllScreens().catch(console.error) + +async function captureAllScreens() { + // setup selenium and install extension + const extPath = path.resolve('dist/chrome') + const driver = buildWebDriver(extPath) + await driver.get('chrome://extensions-frame') + const elems = await driver.findElements(By.css('.extension-list-item-wrapper')) + const extensionId = await elems[1].getAttribute('id') + await driver.get(`chrome-extension://${extensionId}/popup.html`) + await delay(500) + const tabs = await driver.getAllWindowHandles() + await driver.switchTo().window(tabs[0]) + await delay(300) + + // common names + let button + + await captureScreenShot('privacy') + + const privacy = await driver.findElement(By.css('.terms-header')).getText() + driver.findElement(By.css('button')).click() + await delay(300) + await captureScreenShot('terms') + + await delay(300) + const terms = await driver.findElement(By.css('.terms-header')).getText() + await delay(300) + const element = driver.findElement(By.linkText('Attributions')) + await driver.executeScript('arguments[0].scrollIntoView(true)', element) + await delay(300) + button = await driver.findElement(By.css('button')) + const buttonEnabled = await button.isEnabled() + await delay(500) + await captureScreenShot('terms-scrolled') + + await button.click() + await delay(300) + await captureScreenShot('choose-password') + + const passwordBox = await driver.findElement(By.id('password-box')) + const passwordBoxConfirm = await driver.findElement(By.id('password-box-confirm')) + button = driver.findElement(By.css('button')) + passwordBox.sendKeys('123456789') + passwordBoxConfirm.sendKeys('123456789') + await delay(500) + await captureScreenShot('choose-password-filled') + + await button.click() + await delay(700) + this.seedPhase = await driver.findElement(By.css('.twelve-word-phrase')).getText() + await captureScreenShot('seed phrase') + + const continueAfterSeedPhrase = await driver.findElement(By.css('button')) + await continueAfterSeedPhrase.click() + await delay(300) + await captureScreenShot('main screen') + + await driver.findElement(By.css('.sandwich-expando')).click() + await delay(500) + await captureScreenShot('menu') + + // await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)')).click() + // await captureScreenShot('main screen') + // it('should accept account password after lock', async () => { + // await delay(500) + // await driver.findElement(By.id('password-box')).sendKeys('123456789') + // await driver.findElement(By.css('button')).click() + // await delay(500) + // }) + // + // it('should show QR code option', async () => { + // await delay(300) + // await driver.findElement(By.css('.fa-ellipsis-h')).click() + // await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div:nth-child(1) > flex-column > div.name-label > div > span > i > div > div > li:nth-child(3)')).click() + // await delay(300) + // }) + // + // it('should show the account address', async () => { + // this.accountAddress = await driver.findElement(By.css('.ellip-address')).getText() + // await driver.findElement(By.css('.fa-arrow-left')).click() + // await delay(500) + // }) + + // cleanup + await driver.quit() + + async function captureScreenShot(label) { + const artifactDir = `./test-artifacts/${label}` + const filepathBase = `${artifactDir}` + await pify(mkdirp)(artifactDir) + // capture screenshot + const screenshot = await driver.takeScreenshot() + await pify(fs.writeFile)(`${filepathBase}/screenshot.png`, screenshot, { encoding: 'base64' }) + } + +} From 7067f636274cc00254661bb28ae371c975664e3d Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 17:34:30 -0700 Subject: [PATCH 129/246] build - dev - run js tasks in parallel and set watch flag --- gulpfile.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index d6892cc7e..de3d5be11 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -254,6 +254,7 @@ function createTasksForBuildJsExtension({ buildJsFiles, taskPrefix, devMode, bun sourceMapDir: devMode ? './' : '../sourcemaps', minifyBuild: !devMode, buildWithFullPaths: devMode, + watch: devMode, }, bundleTaskOpts) createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1, buildPhase2 }) } @@ -268,6 +269,7 @@ function createTasksForBuildJsMascara({ taskPrefix, devMode, bundleTaskOpts = {} sourceMapDir: './', minifyBuild: !devMode, buildWithFullPaths: devMode, + watch: devMode, }, bundleTaskOpts) createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1 }) } @@ -277,7 +279,6 @@ function createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinatio const jsFiles = [].concat(buildPhase1, buildPhase2) jsFiles.forEach((jsFile) => { gulp.task(`${taskPrefix}:${jsFile}`, bundleTask(Object.assign({ - watch: false, label: jsFile, filename: `${jsFile}.js`, filepath: `${rootDir}/${jsFile}.js`, @@ -289,7 +290,7 @@ function createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinatio subtasks.push(gulp.parallel(buildPhase1.map(file => `${taskPrefix}:${file}`))) if (buildPhase2.length) subtasks.push(gulp.parallel(buildPhase2.map(file => `${taskPrefix}:${file}`))) - gulp.task(taskPrefix, gulp.series(subtasks)) + gulp.task(taskPrefix, gulp.parallel(subtasks)) } // disc bundle analyzer tasks @@ -324,9 +325,9 @@ gulp.task('apply-prod-environment', function(done) { gulp.task('dev', gulp.series( 'build:scss', - 'dev:js', 'copy', gulp.parallel( + 'dev:js', 'watch:scss', 'copy:dev', 'dev:reload' From 77d4a9a2bbd28c633cb6731cdbce47d3f79972a7 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 17:37:49 -0700 Subject: [PATCH 130/246] build - dev - fix js build order --- gulpfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gulpfile.js b/gulpfile.js index de3d5be11..0c16eb18e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -290,7 +290,7 @@ function createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinatio subtasks.push(gulp.parallel(buildPhase1.map(file => `${taskPrefix}:${file}`))) if (buildPhase2.length) subtasks.push(gulp.parallel(buildPhase2.map(file => `${taskPrefix}:${file}`))) - gulp.task(taskPrefix, gulp.parallel(subtasks)) + gulp.task(taskPrefix, gulp.series(subtasks)) } // disc bundle analyzer tasks From 4606a23c3fbfbbbd93ea59f3ca3e2e06766d3a04 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 21:28:35 -0700 Subject: [PATCH 131/246] build - refactor scss compilation into single config --- gulpfile.js | 81 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 0c16eb18e..4a4ab8ee0 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -109,7 +109,7 @@ function createCopyTasks(label, opts) { copyTask(copyTaskName, opts) copyTaskNames.push(copyTaskName) } - const copyDevTaskName = `copy:dev:${label}` + const copyDevTaskName = `dev:copy:${label}` copyTask(copyDevTaskName, Object.assign({ devMode: true }, opts)) copyDevTaskNames.push(copyDevTaskName) } @@ -168,7 +168,7 @@ gulp.task('copy', ) ) -gulp.task('copy:dev', +gulp.task('dev:copy', gulp.series( gulp.parallel(...copyDevTaskNames), 'manifest:chrome', @@ -199,17 +199,50 @@ gulp.task('lint:fix', function () { // scss compilation and autoprefixing tasks -gulp.task('build:scss', function () { - return gulp.src('ui/app/css/index.scss') - .pipe(sourcemaps.init()) - .pipe(sass().on('error', sass.logError)) - .pipe(sourcemaps.write()) - .pipe(autoprefixer()) - .pipe(gulp.dest('ui/app/css/output')) -}) -gulp.task('watch:scss', function() { - gulp.watch(['ui/app/css/**/*.scss'], gulp.series(['build:scss'])) -}) +// gulp.task('build:scss', function () { +// return gulp.src('ui/app/css/index.scss') +// .pipe(sourcemaps.init()) +// .pipe(sass().on('error', sass.logError)) +// .pipe(sourcemaps.write()) +// .pipe(autoprefixer()) +// .pipe(gulp.dest('ui/app/css/output')) +// }) +// gulp.task('dev:scss', function() { +// gulp.watch(['ui/app/css/**/*.scss'], gulp.parallel(['build:scss'])) +// }) + + + +gulp.task('build:scss', createScssBuildTask({ + src: 'ui/app/css/index.scss', + dest: 'ui/app/css/output', + devMode: false, +})) + +gulp.task('dev:scss', createScssBuildTask({ + src: 'ui/app/css/index.scss', + dest: 'ui/app/css/output', + devMode: true, + pattern: 'ui/app/css/**/*.scss', +})) + +function createScssBuildTask({ src, dest, devMode, pattern }) { + return function () { + if (devMode) { + watch(pattern, buildScss) + } + return buildScss() + } + + function buildScss() { + return gulp.src(src) + .pipe(sourcemaps.init()) + .pipe(sass().on('error', sass.logError)) + .pipe(sourcemaps.write()) + .pipe(autoprefixer()) + .pipe(gulp.dest(dest)) + } +} gulp.task('lint-scss', function() { return gulp @@ -321,15 +354,27 @@ gulp.task('apply-prod-environment', function(done) { }); // high level tasks +// +// gulp.task('dev', +// gulp.series( +// 'build:scss', +// 'copy', +// gulp.parallel( +// 'dev:js', +// 'dev:scss', +// 'dev:copy', +// 'dev:reload' +// ) +// ) +// ) gulp.task('dev', gulp.series( - 'build:scss', - 'copy', + 'clean', + 'dev:scss', gulp.parallel( 'dev:js', - 'watch:scss', - 'copy:dev', + 'dev:copy', 'dev:reload' ) ) @@ -341,7 +386,7 @@ gulp.task('build', 'build:scss', gulp.parallel( 'build:js:extension', - 'build:js:mascara', + // 'build:js:mascara', 'copy' ) ) From 2979de2e6bae809d53a34b9c981e4f27ab6580e5 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 30 Mar 2018 02:08:29 -0230 Subject: [PATCH 132/246] Adds integration tests for rendering of tx list items. --- development/states/tx-list-items.js | 128 ++++++++++++++++++++++++++ test/integration/lib/tx-list-items.js | 61 ++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 development/states/tx-list-items.js create mode 100644 test/integration/lib/tx-list-items.js diff --git a/development/states/tx-list-items.js b/development/states/tx-list-items.js new file mode 100644 index 000000000..d567e3fed --- /dev/null +++ b/development/states/tx-list-items.js @@ -0,0 +1,128 @@ +{ + "metamask": { + "isInitialized": true, + "isUnlocked": true, + "featureFlags": {"betaUI": true}, + "rpcTarget": "https://rawtestrpc.metamask.io/", + "identities": { + "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { + "address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", + "name": "Send Account 1" + }, + "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { + "address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb", + "name": "Send Account 2" + }, + "0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { + "address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d", + "name": "Send Account 3" + }, + "0xd85a4b6a394794842887b8284293d69163007bbb": { + "address": "0xd85a4b6a394794842887b8284293d69163007bbb", + "name": "Send Account 4" + } + }, + "currentCurrency": "USD", + "conversionRate": 1200.88200327, + "conversionDate": 1489013762, + "noActiveNotices": true, + "frequentRpcList": [], + "network": "1", + "accounts": { + "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { + "code": "0x", + "balance": "0x47c9d71831c76efe", + "nonce": "0x1b", + "address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" + }, + "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { + "code": "0x", + "balance": "0x37452b1315889f80", + "nonce": "0xa", + "address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb" + }, + "0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { + "code": "0x", + "balance": "0x30c9d71831c76efe", + "nonce": "0x1c", + "address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d" + }, + "0xd85a4b6a394794842887b8284293d69163007bbb": { + "code": "0x", + "balance": "0x0", + "nonce": "0x0", + "address": "0xd85a4b6a394794842887b8284293d69163007bbb" + } + }, + "addressBook": [ + { + "address": "0x06195827297c7a80a443b6894d3bdb8824b43896", + "name": "Address Book Account 1" + } + ], + "tokens": [], + "transactions": {}, + "selectedAddressTxList": [ + {"err":{"message":"Error: [ethjs-rpc] rpc error with payload {\"id\":8726092611900,\"jsonrpc\":\"2.0\",\"params\":[\"0xf8610384773594008094f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a052e5246c9a404f756a246b8cec545099741aeb4e6e0add935a5b7a366fa88f95a0538eaa2421e50377c534244dcdcd15ace00bf9c0adbd9eb162baae2b9e89a36f\"],\"method\":\"eth_sendRawTransaction\"} Error: intrinsic gas too low","stack":"Error: [ethjs-rpc] rpc error with payload {\"id\":8726092611900,\"jsonrpc\":\"2.0\",\"params\":[\"0xf8610384773594008094f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a052e5246c9a404f756a246b8cec545099741aeb4e6e0add935a5b7a366fa88f95a0538eaa2421e50377c534244dcdcd15ace00bf9c0adbd9eb162baae2b9e89a36f\"],\"method\":\"eth_sendRawTransaction\"} Error: intrinsic gas too low\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:72360:28\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103521:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27180:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27024:25)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:106691:25\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103501:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27033:9\n at eachLimit (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:26723:36)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:26937:16\n at end (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103498:5)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:106913:40"},"estimatedGas":"0xcf08","gasLimitSpecified":true,"gasPriceSpecified":true,"history":[{"id":4068311466147836,"loadingDefaults":true,"metamaskNetworkId":"1","status":"unapproved","time":1522378334455,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","gas":"0xcf08","gasPrice":"0x77359400","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0"}},[{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":true},{"op":"add","path":"/gasLimitSpecified","value":true},{"op":"add","path":"/estimatedGas","value":"0xcf08"}],[{"note":"confTx: user approved transaction","op":"replace","path":"/txParams/gas","value":"0x0"}],[{"note":"txStateManager: setting status to approved","op":"replace","path":"/status","value":"approved"}],[{"note":"transactions#approveTransaction","op":"add","path":"/txParams/nonce","value":"0x3"},{"op":"add","path":"/nonceDetails","value":{"local":{"details":{"highest":3,"startPoint":3},"name":"local","nonce":3},"network":{"details":{"baseCount":3},"name":"network","nonce":3},"params":{"highestLocalNonce":3,"highestSuggested":3,"nextNetworkNonce":3}}}],[{"note":"txStateManager: setting status to signed","op":"add","path":"/txParams/chainId","value":"0x3"},{"op":"replace","path":"/status","value":"signed"}],[{"note":"transactions#publishTransaction","op":"add","path":"/rawTx","value":"0xf8610384773594008094f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a052e5246c9a404f756a246b8cec545099741aeb4e6e0add935a5b7a366fa88f95a0538eaa2421e50377c534244dcdcd15ace00bf9c0adbd9eb162baae2b9e89a36f"}],[{"op":"add","path":"/err","value":{"message":"Error: [ethjs-rpc] rpc error with payload {\"id\":8726092611900,\"jsonrpc\":\"2.0\",\"params\":[\"0xf8610384773594008094f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a052e5246c9a404f756a246b8cec545099741aeb4e6e0add935a5b7a366fa88f95a0538eaa2421e50377c534244dcdcd15ace00bf9c0adbd9eb162baae2b9e89a36f\"],\"method\":\"eth_sendRawTransaction\"} Error: intrinsic gas too low","stack":"Error: [ethjs-rpc] rpc error with payload {\"id\":8726092611900,\"jsonrpc\":\"2.0\",\"params\":[\"0xf8610384773594008094f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a052e5246c9a404f756a246b8cec545099741aeb4e6e0add935a5b7a366fa88f95a0538eaa2421e50377c534244dcdcd15ace00bf9c0adbd9eb162baae2b9e89a36f\"],\"method\":\"eth_sendRawTransaction\"} Error: intrinsic gas too low\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:72360:28\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103521:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27180:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27024:25)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:106691:25\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103501:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27033:9\n at eachLimit (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:26723:36)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:26937:16\n at end (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103498:5)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:106913:40"}}]],"id":4068311466147836,"loadingDefaults":false,"metamaskNetworkId":"1","nonceDetails":{"local":{"details":{"highest":3,"startPoint":3},"name":"local","nonce":3},"network":{"details":{"baseCount":3},"name":"network","nonce":3},"params":{"highestLocalNonce":3,"highestSuggested":3,"nextNetworkNonce":3}},"rawTx":"0xf8610384773594008094f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a052e5246c9a404f756a246b8cec545099741aeb4e6e0add935a5b7a366fa88f95a0538eaa2421e50377c534244dcdcd15ace00bf9c0adbd9eb162baae2b9e89a36f","status":"failed","time":1522378334455,"txParams":{"chainId":"0x3","from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","gas":"0x0","gasPrice":"0x77359400","nonce":"0x3","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0"}}, + {"id":2315363930841933,"time":1522378572149,"status":"approved","metamaskNetworkId":"1","loadingDefaults":false,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0x0","gasPrice":"0x5f5e100"},"history":[{"id":2315363930841933,"time":1522378572149,"status":"unapproved","metamaskNetworkId":"1","loadingDefaults":true,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100"}},[{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":true},{"op":"add","path":"/gasLimitSpecified","value":true},{"op":"add","path":"/estimatedGas","value":"0xcf08"}],[{"op":"replace","path":"/txParams/gas","value":"0x0","note":"confTx: user approved transaction"}],[{"op":"replace","path":"/status","value":"approved","note":"txStateManager: setting status to approved"}]],"gasPriceSpecified":true,"gasLimitSpecified":true,"estimatedGas":"0xcf08"}, + {"estimatedGas":"8d41","firstRetryBlockNumber":"0x2cbc70","gasLimitSpecified":false,"gasPriceSpecified":false,"hash":"0xfbd997bf9bb85ca1598952ca23e7910502d527e06cb6ee1bbe7e7dd59d6909cd","history":[{"id":2079438776801906,"loadingDefaults":true,"metamaskNetworkId":"1","status":"unapproved","time":1522346270251,"txParams":{"data":"0xa9059cbb000000000000000000000000e7884118ee52ec3f4eef715cb022279d7d4181a9000000000000000000000000000000000000000000000000000000000000000b","from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0x66f30b996a7d345cd00badcfe75e81e25dc5e1eb"}},[{"op":"add","path":"/txParams/gasPrice","value":"0x37e11d600"},{"op":"add","path":"/txParams/value","value":"0x0"},{"op":"add","path":"/txParams/gas","value":"0xd3e1"},{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":false},{"op":"add","path":"/gasLimitSpecified","value":false},{"op":"add","path":"/estimatedGas","value":"8d41"}],[{"note":"confTx: user approved transaction","op":"replace","path":"/txParams/gasPrice","value":"0x5f5e100"}],[{"note":"txStateManager: setting status to approved","op":"replace","path":"/status","value":"approved"}],[{"note":"transactions#approveTransaction","op":"add","path":"/txParams/nonce","value":"0x2"},{"op":"add","path":"/nonceDetails","value":{"local":{"details":{"highest":2,"startPoint":2},"name":"local","nonce":2},"network":{"details":{"baseCount":2},"name":"network","nonce":2},"params":{"highestLocalNonce":2,"highestSuggested":2,"nextNetworkNonce":2}}}],[{"note":"txStateManager: setting status to signed","op":"add","path":"/txParams/chainId","value":"0x3"},{"op":"replace","path":"/status","value":"signed"}],[{"note":"transactions#publishTransaction","op":"add","path":"/rawTx","value":"0xf8a8028405f5e10082d3e19466f30b996a7d345cd00badcfe75e81e25dc5e1eb80b844a9059cbb000000000000000000000000e7884118ee52ec3f4eef715cb022279d7d4181a9000000000000000000000000000000000000000000000000000000000000000b2aa05cb38a3a68e49008da2e93839f6dedeb96b1630c2a73c4cf5eb3fcc74299a100a039f17c0807469bd101165fa0749dc7065832b4a7c3a382b6cf7e29228c2a683d"}],[{"note":"transactions#setTxHash","op":"add","path":"/hash","value":"0xfbd997bf9bb85ca1598952ca23e7910502d527e06cb6ee1bbe7e7dd59d6909cd"}],[{"note":"txStateManager - add submitted time stamp","op":"add","path":"/submittedTime","value":1522346282571}],[{"note":"txStateManager: setting status to submitted","op":"replace","path":"/status","value":"submitted"}],[{"note":"transactions/pending-tx-tracker#event: tx:block-update","op":"add","path":"/firstRetryBlockNumber","value":"0x2cbc70"}],[{"note":"txStateManager: setting status to confirmed","op":"replace","path":"/status","value":"confirmed"}]],"id":2079438776801906,"loadingDefaults":false,"metamaskNetworkId":"1","nonceDetails":{"local":{"details":{"highest":2,"startPoint":2},"name":"local","nonce":2},"network":{"details":{"baseCount":2},"name":"network","nonce":2},"params":{"highestLocalNonce":2,"highestSuggested":2,"nextNetworkNonce":2}},"rawTx":"0xf8a8028405f5e10082d3e19466f30b996a7d345cd00badcfe75e81e25dc5e1eb80b844a9059cbb000000000000000000000000e7884118ee52ec3f4eef715cb022279d7d4181a9000000000000000000000000000000000000000000000000000000000000000b2aa05cb38a3a68e49008da2e93839f6dedeb96b1630c2a73c4cf5eb3fcc74299a100a039f17c0807469bd101165fa0749dc7065832b4a7c3a382b6cf7e29228c2a683d","status":"confirmed","submittedTime":1522346282571,"time":1522346270251,"txParams":{"chainId":"0x3","data":"0xa9059cbb000000000000000000000000e7884118ee52ec3f4eef715cb022279d7d4181a9000000000000000000000000000000000000000000000000000000000000000b","from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","gas":"0xd3e1","gasPrice":"0x5f5e100","nonce":"0x2","to":"0x66f30b996a7d345cd00badcfe75e81e25dc5e1eb","value":"0x0"}}, + {"id":4087002078467524,"time":1522379587999,"status":"submitted","metamaskNetworkId":"1","loadingDefaults":false,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100","nonce":"0x3","chainId":"0x3"},"history":[{"id":4087002078467524,"time":1522379587999,"status":"unapproved","metamaskNetworkId":"1","loadingDefaults":true,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100"}},[{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":true},{"op":"add","path":"/gasLimitSpecified","value":true},{"op":"add","path":"/estimatedGas","value":"0xcf08"}],[],[{"op":"replace","path":"/status","value":"approved","note":"txStateManager: setting status to approved"}],[{"op":"add","path":"/txParams/nonce","value":"0x3","note":"transactions#approveTransaction"},{"op":"add","path":"/nonceDetails","value":{"params":{"highestLocalNonce":3,"highestSuggested":3,"nextNetworkNonce":3},"local":{"name":"local","nonce":3,"details":{"startPoint":3,"highest":3}},"network":{"name":"network","nonce":3,"details":{"baseCount":3}}}}],[{"op":"add","path":"/txParams/chainId","value":"0x3","note":"txStateManager: setting status to signed"},{"op":"replace","path":"/status","value":"signed"}],[{"op":"add","path":"/rawTx","value":"0xf863038405f5e10082cf0894f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a0d64ed427733ef67fe788fe85d3cfe51c43cfc83d07fa4ab8af5d3bc8c8199895a02699c131cc0ffcf842b54776ac611bdd165fdb87dd3ecff1554ec8da1bf3ff39","note":"transactions#publishTransaction"}],[{"op":"add","path":"/hash","value":"0x52f0929fc143d76f4e6255d95cebfc76b74f43726191bd4081a5ae9bd6c1fa4a","note":"transactions#setTxHash"}],[{"op":"add","path":"/submittedTime","value":1522379590158,"note":"txStateManager - add submitted time stamp"}],[{"op":"replace","path":"/status","value":"submitted","note":"txStateManager: setting status to submitted"}],[{"op":"add","path":"/firstRetryBlockNumber","value":"0x2cc718","note":"transactions/pending-tx-tracker#event: tx:block-update"}]],"gasPriceSpecified":true,"gasLimitSpecified":true,"estimatedGas":"0xcf08","nonceDetails":{"params":{"highestLocalNonce":3,"highestSuggested":3,"nextNetworkNonce":3},"local":{"name":"local","nonce":3,"details":{"startPoint":3,"highest":3}},"network":{"name":"network","nonce":3,"details":{"baseCount":3}}},"rawTx":"0xf863038405f5e10082cf0894f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a0d64ed427733ef67fe788fe85d3cfe51c43cfc83d07fa4ab8af5d3bc8c8199895a02699c131cc0ffcf842b54776ac611bdd165fdb87dd3ecff1554ec8da1bf3ff39","hash":"0x52f0929fc143d76f4e6255d95cebfc76b74f43726191bd4081a5ae9bd6c1fa4a","submittedTime":1522379590158,"firstRetryBlockNumber":"0x2cc718"}, + {"estimatedGas":"0x5208","gasLimitSpecified":false,"gasPriceSpecified":false,"history":[{"id":6301441591225658,"loadingDefaults":true,"metamaskNetworkId":"1","status":"unapproved","time":1522346051227,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0x81b7e08f65bdf5648606c89998a9cc8164397647","value":"0xde0b6b3a7640000"}},[{"op":"add","path":"/txParams/gasPrice","value":"0x4a817c800"},{"op":"add","path":"/txParams/gas","value":"0x5208"},{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":false},{"op":"add","path":"/gasLimitSpecified","value":false},{"op":"add","path":"/simpleSend","value":true},{"op":"add","path":"/estimatedGas","value":"0x5208"}],[{"note":"txStateManager: setting status to rejected","op":"replace","path":"/status","value":"rejected"}]],"id":6301441591225658,"loadingDefaults":false,"metamaskNetworkId":"1","simpleSend":true,"status":"rejected","time":1522346051227,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","gas":"0x5208","gasPrice":"0x4a817c800","to":"0x81b7e08f65bdf5648606c89998a9cc8164397647","value":"0xde0b6b3a7640000"}}, + {"id":2699829174766090,"time":1522381785750,"status":"unapproved","metamaskNetworkId":"1","loadingDefaults":false,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100"},"history":[{"id":2699829174766090,"time":1522381785750,"status":"unapproved","metamaskNetworkId":"1","loadingDefaults":true,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100"}},[{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":true},{"op":"add","path":"/gasLimitSpecified","value":true},{"op":"add","path":"/estimatedGas","value":"0xcf08"}]],"gasPriceSpecified":true,"gasLimitSpecified":true,"estimatedGas":"0xcf08"} + ], + "unapprovedTxs": {"2699829174766090":{"id":2699829174766090,"time":1522381785750,"status":"unapproved","metamaskNetworkId":"1","loadingDefaults":false,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100"},"history":[{"id":2699829174766090,"time":1522381785750,"status":"unapproved","metamaskNetworkId":"1","loadingDefaults":true,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100"}},[{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":true},{"op":"add","path":"/gasLimitSpecified","value":true},{"op":"add","path":"/estimatedGas","value":"0xcf08"}]],"gasPriceSpecified":true,"gasLimitSpecified":true,"estimatedGas":"0xcf08"}}, + "unapprovedMsgs": {"2315363930841932":{"id":2315363930841932,"msgParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","data":"0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0"},"time":1522378539686,"status":"unapproved","type":"eth_sign"}}, + "unapprovedMsgCount": 0, + "unapprovedPersonalMsgs": {}, + "unapprovedPersonalMsgCount": 0, + "keyringTypes": [ + "Simple Key Pair", + "HD Key Tree" + ], + "keyrings": [ + { + "type": "HD Key Tree", + "accounts": [ + "fdea65c8e26263f6d9a1b5de9555d2931a33b825", + "c5b8dbac4c1d3f152cdeb400e2313f309c410acb", + "2f8d4a878cfa04a6e60d46362f5644deab66572d" + ] + }, + { + "type": "Simple Key Pair", + "accounts": [ + "0xd85a4b6a394794842887b8284293d69163007bbb" + ] + } + ], + "selectedAddress": "0xd85a4b6a394794842887b8284293d69163007bbb", + "provider": { + "type": "testnet" + }, + "shapeShiftTxList": [{"depositAddress":"34vJ3AfmNcLiziA4VFgEVcQTwxVLD1qkke","depositType":"BTC","key":"shapeshift","response":{"status":"no_deposits","address":"34vJ3AfmNcLiziA4VFgEVcQTwxVLD1qkke"},"time":1522377459106}], + "lostAccounts": [], + "send": {}, + "currentLocale": "en" + }, + "appState": { + "menuOpen": false, + "currentView": { + "name": "confTx", + "detailView": null, + "context": 0 + }, + "accountDetail": { + "subview": "transactions" + }, + "modal": { + "modalState": {}, + "previousModalState": {} + }, + "transForward": true, + "isLoading": false, + "warning": null, + "scrollToBottom": false, + "forgottenPassword": null + }, + "identities": {} +} diff --git a/test/integration/lib/tx-list-items.js b/test/integration/lib/tx-list-items.js new file mode 100644 index 000000000..d0056eb94 --- /dev/null +++ b/test/integration/lib/tx-list-items.js @@ -0,0 +1,61 @@ +const reactTriggerChange = require('../../lib/react-trigger-change') +const { + timeout, + queryAsync, + findAsync, +} = require('../../lib/util') + +QUnit.module('tx list items') + +QUnit.test('renders list items successfully', (assert) => { + const done = assert.async() + runTxListItemsTest(assert).then(done).catch((err) => { + assert.notOk(err, `Error was thrown: ${err.stack}`) + done() + }) +}) + +async function runTxListItemsTest(assert, done) { + console.log('*** start runTxListItemsTest') + const selectState = await queryAsync($, 'select') + selectState.val('tx list items') + reactTriggerChange(selectState[0]) + + const metamaskLogo = await queryAsync($, '.left-menu-wrapper') + assert.ok(metamaskLogo[0], 'metamask logo present') + metamaskLogo[0].click() + + const txListItems = await queryAsync($, '.tx-list-item') + assert.equal(txListItems.length, 8, 'all tx list items are rendered') + + const unapprovedTx = txListItems[0] + assert.equal($(unapprovedTx).hasClass('tx-list-pending-item-container'), true, 'unapprovedTx has the correct class') + + const retryTx = txListItems[1] + const retryTxLink = await findAsync($(retryTx), '.tx-list-item-retry-link') + assert.equal(retryTxLink[0].textContent, 'Increase the gas price on your transaction', 'retryTx has expected link') + + const approvedTx = txListItems[2] + const approvedTxRenderedStatus = await findAsync($(approvedTx), '.tx-list-status') + assert.equal(approvedTxRenderedStatus[0].textContent, 'Approved', 'approvedTx has correct label') + + const unapprovedMsg = txListItems[3] + const unapprovedMsgDescription = await findAsync($(unapprovedMsg), '.tx-list-account') + assert.equal(unapprovedMsgDescription[0].textContent, 'Signature Request', 'unapprovedMsg has correct description') + + const failedTx = txListItems[4] + const failedTxRenderedStatus = await findAsync($(failedTx), '.tx-list-status') + assert.equal(failedTxRenderedStatus[0].textContent, 'Failed', 'failedTx has correct label') + + const shapeShiftTx = txListItems[5] + const shapeShiftTxStatus = await findAsync($(shapeShiftTx), '.flex-column div:eq(1)') + assert.equal(shapeShiftTxStatus[0].textContent, 'No deposits received', 'shapeShiftTx has correct status') + + const confirmedTokenTx = txListItems[6] + const confirmedTokenTxAddress = await findAsync($(confirmedTokenTx), '.tx-list-account') + assert.equal(confirmedTokenTxAddress[0].textContent, '0xe7884118...81a9', 'confirmedTokenTx has correct address') + + const rejectedTx = txListItems[7] + const rejectedTxRenderedStatus = await findAsync($(rejectedTx), '.tx-list-status') + assert.equal(rejectedTxRenderedStatus[0].textContent, 'Rejected', 'rejectedTx has correct label') +} From 2be6f8bae0e516d49c83776a06dcbf82971a0a19 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 30 Mar 2018 02:19:04 -0230 Subject: [PATCH 133/246] Fix lint and tests --- ui/app/components/pending-tx/confirm-send-ether.js | 4 ++-- ui/app/components/pending-tx/confirm-send-token.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index 68c56d243..2474516d4 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -117,7 +117,7 @@ ConfirmSendEther.prototype.componentWillMount = function () { updateSendErrors({ insufficientFunds: balanceIsSufficient ? false - : this.props.t('insufficientFunds') + : this.context.t('insufficientFunds'), }) } @@ -495,7 +495,7 @@ ConfirmSendEther.prototype.onSubmit = function (event) { if (valid && this.verifyGasParams() && balanceIsSufficient) { this.props.sendTransaction(txMeta, event) } else if (!balanceIsSufficient) { - updateSendErrors({ insufficientFunds: this.props.t('insufficientFunds') }) + updateSendErrors({ insufficientFunds: this.context.t('insufficientFunds') }) } else { updateSendErrors({ invalidGasParams: this.context.t('invalidGasParams') }) this.setState({ submitting: false }) diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index 503c2b19d..dd9fdc23f 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -160,7 +160,7 @@ ConfirmSendToken.prototype.componentWillMount = function () { updateSendErrors({ insufficientFunds: balanceIsSufficient ? false - : this.props.t('insufficientFunds') + : this.context.t('insufficientFunds'), }) } @@ -495,7 +495,7 @@ ConfirmSendToken.prototype.onSubmit = function (event) { if (valid && this.verifyGasParams() && balanceIsSufficient) { this.props.sendTransaction(txMeta, event) } else if (!balanceIsSufficient) { - updateSendErrors({ insufficientFunds: this.props.t('insufficientFunds') }) + updateSendErrors({ insufficientFunds: this.context.t('insufficientFunds') }) } else { updateSendErrors({ invalidGasParams: this.context.t('invalidGasParams') }) this.setState({ submitting: false }) From b2d0e9871c5004458ef9be4a83d08df8a39e6e48 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 21:53:38 -0700 Subject: [PATCH 134/246] build - fix copy devMode --- gulpfile.js | 63 ++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 4a4ab8ee0..c2e18395c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -114,6 +114,37 @@ function createCopyTasks(label, opts) { copyDevTaskNames.push(copyDevTaskName) } +function copyTask(taskName, opts){ + const source = opts.source + const destination = opts.destination + const destinations = opts.destinations || [destination] + const pattern = opts.pattern || '/**/*' + const devMode = opts.devMode + + return gulp.task(taskName, function () { + if (devMode) { + watch(source + pattern, (event) => { + livereload.changed(event.path) + performCopy() + }) + } + + return performCopy() + }) + + function performCopy() { + // stream from source + let stream = gulp.src(source + pattern, { base: source }) + + // copy to destinations + destinations.forEach(function(destination) { + stream = stream.pipe(gulp.dest(destination)) + }) + + return stream + } +} + // manifest tinkering gulp.task('manifest:chrome', function() { @@ -402,38 +433,6 @@ gulp.task('dist', // task generators -function copyTask(taskName, opts){ - const source = opts.source - const destination = opts.destination - const destinations = opts.destinations || [ destination ] - const pattern = opts.pattern || '/**/*' - const devMode = opts.devMode - - return gulp.task(taskName, performCopy) - - function performCopy(){ - // stream from source - let stream - if (devMode) { - stream = watch(source + pattern, { base: source }) - } else { - stream = gulp.src(source + pattern, { base: source }) - } - - // copy to destinations - destinations.forEach(function(destination) { - stream = stream.pipe(gulp.dest(destination)) - }) - - // trigger reload - if (devMode) { - stream.pipe(livereload()) - } - - return stream - } -} - function zipTask(target) { return () => { return gulp.src(`dist/${target}/**`) From 7b9b890aa94557c4665be00da8c0f2e24ba4ea1a Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 22:19:15 -0700 Subject: [PATCH 135/246] build - fix scss + js reload --- gulpfile.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index c2e18395c..5e7b5dc03 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -28,7 +28,8 @@ const stylefmt = require('gulp-stylefmt') const uglify = require('gulp-uglify-es').default const babel = require('gulp-babel') const debug = require('gulp-debug') - +const pify = require('pify') +const endOfStream = pify(require('end-of-stream')) const disableDebugTools = gutil.env.disableDebugTools const debugMode = gutil.env.debug @@ -260,7 +261,11 @@ gulp.task('dev:scss', createScssBuildTask({ function createScssBuildTask({ src, dest, devMode, pattern }) { return function () { if (devMode) { - watch(pattern, buildScss) + watch(pattern, async (event) => { + const stream = buildScss() + await endOfStream(stream) + livereload.changed(event.path) + }) } return buildScss() } @@ -454,7 +459,11 @@ function generateBundler(opts, performBundle) { if (opts.watch) { bundler = watchify(bundler) // on any file update, re-runs the bundler - bundler.on('update', performBundle) + bundler.on('update', async (ids) => { + const stream = performBundle() + await endOfStream(stream) + livereload.changed(`${ids}`) + }) } return bundler @@ -494,7 +503,6 @@ function bundleTask(opts) { return performBundle function performBundle(){ - let buildStream = bundler.bundle() // handle errors @@ -545,10 +553,6 @@ function bundleTask(opts) { buildStream = buildStream.pipe(gulp.dest(dest)) }) - // finally, trigger live reload - buildStream = buildStream - .pipe(gulpif(debugMode, livereload())) - return buildStream } From edd70bd13e514013073f75ff005bddf6f6a568a9 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 22:20:24 -0700 Subject: [PATCH 136/246] build - cleanup commented code --- gulpfile.js | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 5e7b5dc03..910441e4d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -231,20 +231,6 @@ gulp.task('lint:fix', function () { // scss compilation and autoprefixing tasks -// gulp.task('build:scss', function () { -// return gulp.src('ui/app/css/index.scss') -// .pipe(sourcemaps.init()) -// .pipe(sass().on('error', sass.logError)) -// .pipe(sourcemaps.write()) -// .pipe(autoprefixer()) -// .pipe(gulp.dest('ui/app/css/output')) -// }) -// gulp.task('dev:scss', function() { -// gulp.watch(['ui/app/css/**/*.scss'], gulp.parallel(['build:scss'])) -// }) - - - gulp.task('build:scss', createScssBuildTask({ src: 'ui/app/css/index.scss', dest: 'ui/app/css/output', @@ -390,19 +376,6 @@ gulp.task('apply-prod-environment', function(done) { }); // high level tasks -// -// gulp.task('dev', -// gulp.series( -// 'build:scss', -// 'copy', -// gulp.parallel( -// 'dev:js', -// 'dev:scss', -// 'dev:copy', -// 'dev:reload' -// ) -// ) -// ) gulp.task('dev', gulp.series( From 433bb0f01ae3631774191f8ed802eb7f2f04a552 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 22:34:59 -0700 Subject: [PATCH 137/246] build - split primary tasks into metamask + extension * dev + build --- gulpfile.js | 62 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 910441e4d..647abb6d2 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -69,7 +69,7 @@ createCopyTasks('images', { destinations: commonPlatforms.map(platform => `./dist/${platform}/images`), }) createCopyTasks('contractImages', { - source: `${require.resolve('eth-contract-metadata')}/images/`, + source: './node_modules/eth-contract-metadata/images/', destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contract`), }) createCopyTasks('fonts', { @@ -293,9 +293,10 @@ const buildJsFiles = [ ] // bundle tasks -createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'dev:js', devMode: true }) -createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'build:js:extension' }) -createTasksForBuildJsMascara({ taskPrefix: 'build:js:mascara' }) +createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'dev:extension:js', devMode: true }) +createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'build:extension:js' }) +createTasksForBuildJsMascara({ taskPrefix: 'build:mascara:js' }) +createTasksForBuildJsMascara({ taskPrefix: 'dev:mascara:js', devMode: true }) function createTasksForBuildJsExtension({ buildJsFiles, taskPrefix, devMode, bundleTaskOpts = {} }) { // inpage must be built before all other scripts: @@ -382,7 +383,32 @@ gulp.task('dev', 'clean', 'dev:scss', gulp.parallel( - 'dev:js', + 'dev:extension:js', + 'dev:mascara:js', + 'dev:copy', + 'dev:reload' + ) + ) +) + +gulp.task('dev:extension', + gulp.series( + 'clean', + 'dev:scss', + gulp.parallel( + 'dev:extension:js', + 'dev:copy', + 'dev:reload' + ) + ) +) + +gulp.task('dev:mascara', + gulp.series( + 'clean', + 'dev:scss', + gulp.parallel( + 'dev:mascara:js', 'dev:copy', 'dev:reload' ) @@ -394,8 +420,30 @@ gulp.task('build', 'clean', 'build:scss', gulp.parallel( - 'build:js:extension', - // 'build:js:mascara', + 'build:extension:js', + 'build:mascara:js', + 'copy' + ) + ) +) + +gulp.task('build:extension', + gulp.series( + 'clean', + 'build:scss', + gulp.parallel( + 'build:extension:js', + 'copy' + ) + ) +) + +gulp.task('build:mascara', + gulp.series( + 'clean', + 'build:scss', + gulp.parallel( + 'build:mascara:js', 'copy' ) ) From 8277c662deffea3c01496fc7d07ed3e9a9a97a50 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 22:58:26 -0700 Subject: [PATCH 138/246] npm scripts - rewrite default scripts to new task names --- package.json | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 2dd63c1d1..a852395b3 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,8 @@ "public": false, "private": true, "scripts": { - "start": "npm run dev", - "dev": "gulp dev --debug", - "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 ./", - "watch": "mocha watch --recursive \"test/unit/**/*.js\"", - "mascara": "gulp build && cross-env METAMASK_DEBUG=true node ./mascara/example/server", + "start": "gulp dev:extension", + "mascara": "gulp dev:mascara & cross-env METAMASK_DEBUG=true node ./mascara/example/server", "dist": "gulp dist", "test": "npm run test:unit && npm run test:integration && npm run lint", "test:unit": "cross-env METAMASK_ENV=test mocha --exit --require babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"", @@ -40,6 +36,9 @@ "sentry:upload:maps": "sentry-cli releases --org 'metamask' --project 'metamask' files $RELEASE upload-sourcemaps ./dist/sourcemaps/ --url-prefix 'sourcemaps' --rewrite", "lint": "gulp lint", "lint:fix": "gulp lint:fix", + "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 ./", + "watch": "mocha watch --recursive \"test/unit/**/*.js\"", "disc": "gulp disc --debug", "announce": "node development/announcer.js", "version:bump": "node development/run-version-bump.js", From 99e618d3f2fed0504e9dcc4647b8492440617162 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 23:06:01 -0700 Subject: [PATCH 139/246] mascara - server - serve bundles from dist --- gulpfile.js | 2 +- mascara/server/index.js | 13 ------------- mascara/src/{mascara.js => metamascara.js} | 0 3 files changed, 1 insertion(+), 14 deletions(-) rename mascara/src/{mascara.js => metamascara.js} (100%) diff --git a/gulpfile.js b/gulpfile.js index 647abb6d2..3ca0c65de 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -318,7 +318,7 @@ function createTasksForBuildJsExtension({ buildJsFiles, taskPrefix, devMode, bun function createTasksForBuildJsMascara({ taskPrefix, devMode, bundleTaskOpts = {} }) { // inpage must be built before all other scripts: const rootDir = './mascara/src/' - const buildPhase1 = ['ui', 'proxy', 'background'] + const buildPhase1 = ['ui', 'proxy', 'background', 'metamascara'] const destinations = ['./dist/mascara'] bundleTaskOpts = Object.assign({ buildSourceMaps: true, diff --git a/mascara/server/index.js b/mascara/server/index.js index 2bc2441d0..2f3a7a5ff 100644 --- a/mascara/server/index.js +++ b/mascara/server/index.js @@ -9,23 +9,10 @@ module.exports = createMetamascaraServer function createMetamascaraServer () { - // start bundlers - const metamascaraBundle = createBundle(path.join(__dirname, '/../src/mascara.js')) - const proxyBundle = createBundle(path.join(__dirname, '/../src/proxy.js')) - const uiBundle = createBundle(path.join(__dirname, '/../src/ui.js')) - const backgroundBuild = createBundle(path.join(__dirname, '/../src/background.js')) - // setup server const server = express() server.use(compression()) - // serve bundles - serveBundle(server, '/metamascara.js', metamascaraBundle) - serveBundle(server, '/scripts/ui.js', uiBundle) - serveBundle(server, '/scripts/proxy.js', proxyBundle) - // the serviceworker must be served from the root of the app - serveBundle(server, '/background.js', backgroundBuild) - // serve assets server.use(express.static(path.join(__dirname, '/../ui/'), { setHeaders: (res) => res.set('X-Frame-Options', 'DENY') })) server.use(express.static(path.join(__dirname, '/../../dist/mascara'))) diff --git a/mascara/src/mascara.js b/mascara/src/metamascara.js similarity index 100% rename from mascara/src/mascara.js rename to mascara/src/metamascara.js From 89e6baa3ba07cc46dcc62886fbe3f1906649ae77 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 29 Mar 2018 23:09:31 -0700 Subject: [PATCH 140/246] clean - mascara - remove unused code --- mascara/server/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/mascara/server/index.js b/mascara/server/index.js index 2f3a7a5ff..a30120438 100644 --- a/mascara/server/index.js +++ b/mascara/server/index.js @@ -1,7 +1,5 @@ const path = require('path') const express = require('express') -const createBundle = require('./util').createBundle -const serveBundle = require('./util').serveBundle const compression = require('compression') module.exports = createMetamascaraServer From 5945c8cf67201f651eb98b000fbe6702b8ec6a88 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 00:09:39 -0700 Subject: [PATCH 141/246] development - create selenium screen shotter --- package-lock.json | 168 +++++++++++++++++++++++++++++++++++++++ package.json | 1 + test/screens/new.spec.js | 122 +++++++++++++++++----------- 3 files changed, 246 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index f0f76919a..bc16f4780 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6674,6 +6674,12 @@ "which": "1.3.0" } }, + "find-index": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", + "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", + "dev": true + }, "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", @@ -8232,6 +8238,12 @@ "assert-plus": "1.0.0" } }, + "gifencoder": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gifencoder/-/gifencoder-1.1.0.tgz", + "integrity": "sha512-MVh++nximxsp8NaNRfS1+MmCviZ4wi7HhuvX8eHrfNn//1mqi8Eb03tKs6Z+lIIcSEySJ6PmS1VPZ+HdtEMlfg==", + "dev": true + }, "gl-mat4": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/gl-mat4/-/gl-mat4-1.1.4.tgz", @@ -8351,6 +8363,15 @@ "object.defaults": "1.1.0" } }, + "glob2base": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", + "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "dev": true, + "requires": { + "find-index": "0.1.1" + } + }, "global": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", @@ -10104,6 +10125,12 @@ "integrity": "sha1-rI9DbyI5td+2bV8NOpBKh6xnzF4=", "dev": true }, + "image-size": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.6.2.tgz", + "integrity": "sha512-pH3vDzpczdsKHdZ9xxR3O46unSjisgVx0IImay7Zz2EdhRVbCkj+nthx9OuuWEhakx9FAO+fNVGrF0rZ2oMOvw==", + "dev": true + }, "immediate": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.2.3.tgz", @@ -16691,6 +16718,147 @@ "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", "dev": true }, + "png-file-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-file-stream/-/png-file-stream-1.0.0.tgz", + "integrity": "sha1-4IPQ/lbgl6XL0NNBoThzeQUsrTU=", + "dev": true, + "requires": { + "glob-stream": "3.1.18", + "png-js": "0.1.1", + "through2": "0.2.3" + }, + "dependencies": { + "glob": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", + "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", + "dev": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "2.0.10", + "once": "1.4.0" + } + }, + "glob-stream": { + "version": "3.1.18", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", + "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", + "dev": true, + "requires": { + "glob": "4.5.3", + "glob2base": "0.0.12", + "minimatch": "2.0.10", + "ordered-read-streams": "0.1.0", + "through2": "0.6.5", + "unique-stream": "1.0.0" + }, + "dependencies": { + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": "1.0.34", + "xtend": "4.0.1" + } + } + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", + "dev": true + }, + "ordered-read-streams": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", + "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "through2": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", + "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", + "dev": true, + "requires": { + "readable-stream": "1.1.14", + "xtend": "2.1.2" + }, + "dependencies": { + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "dev": true, + "requires": { + "object-keys": "0.4.0" + } + } + } + }, + "unique-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", + "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", + "dev": true + } + } + }, + "png-js": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/png-js/-/png-js-0.1.1.tgz", + "integrity": "sha1-HMfCEjA6yr50Jj7DrHgAlYAkLZM=", + "dev": true + }, "pojo-migrator": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pojo-migrator/-/pojo-migrator-2.1.0.tgz", diff --git a/package.json b/package.json index 16c2d735d..5b24a0fd6 100644 --- a/package.json +++ b/package.json @@ -263,6 +263,7 @@ "react-test-renderer": "^15.6.2", "react-testutils-additions": "^15.2.0", "redux-test-utils": "^0.2.2", + "rimraf": "^2.6.2", "selenium-webdriver": "^3.5.0", "sinon": "^5.0.0", "stylelint-config-standard": "^18.2.0", diff --git a/test/screens/new.spec.js b/test/screens/new.spec.js index c5a8ef859..f17781d7a 100644 --- a/test/screens/new.spec.js +++ b/test/screens/new.spec.js @@ -2,6 +2,7 @@ const path = require('path') const fs = require('fs') const pify = require('pify') const mkdirp = require('mkdirp') +const rimraf = require('rimraf') const webdriver = require('selenium-webdriver') const endOfStream = require('end-of-stream') const GIFEncoder = require('gifencoder') @@ -15,84 +16,111 @@ captureAllScreens().catch(console.error) async function captureAllScreens() { let screenshotCount = 0 + // common names + let button + let tabs + let element + + await cleanScreenShotDir() + // setup selenium and install extension const extPath = path.resolve('dist/chrome') const driver = buildWebDriver(extPath) await driver.get('chrome://extensions-frame') const elems = await driver.findElements(By.css('.extension-list-item-wrapper')) const extensionId = await elems[1].getAttribute('id') - await driver.get(`chrome-extension://${extensionId}/popup.html`) + await driver.get(`chrome-extension://${extensionId}/home.html`) await delay(500) - const tabs = await driver.getAllWindowHandles() + tabs = await driver.getAllWindowHandles() await driver.switchTo().window(tabs[0]) await delay(300) - // common names - let button - await captureScreenShot('start-old') // click try new ui await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-center.flex-grow > p')).click() - await captureScreenShot('start-new') - await delay(300) - await captureScreenShot('start-new2') await delay(300) - await captureScreenShot('start-new3') + + // close metamask homepage and extra home.html + tabs = await driver.getAllWindowHandles() + await driver.switchTo().window(tabs[2]) + driver.close() + await driver.switchTo().window(tabs[1]) + driver.close() + await driver.switchTo().window(tabs[0]) await delay(300) - await captureScreenShot('start-new4') + await captureScreenShot('welcome-new-ui') + + // setup account + await delay(1000) + await driver.findElement(By.css('body')).click() await delay(300) - await captureScreenShot('start-new5') + await captureScreenShot('welcome') - // exit early for dev - await generateGif() - await driver.quit() - return + await driver.findElement(By.css('button')).click() + await captureScreenShot('create password') + + const passwordBox = await driver.findElement(By.css('input[type=password]:nth-of-type(1)')) + const passwordBoxConfirm = await driver.findElement(By.css('input[type=password]:nth-of-type(2)')) + passwordBox.sendKeys('123456789') + passwordBoxConfirm.sendKeys('123456789') + await delay(500) + await captureScreenShot('choose-password-filled') + await driver.findElement(By.css('button')).click() + await delay(500) + await captureScreenShot('unique account image') - await captureScreenShot('privacy') + await driver.findElement(By.css('button')).click() + await delay(500) + await captureScreenShot('privacy note') - const privacy = await driver.findElement(By.css('.terms-header')).getText() - driver.findElement(By.css('button')).click() + await driver.findElement(By.css('button')).click() await delay(300) await captureScreenShot('terms') await delay(300) - const terms = await driver.findElement(By.css('.terms-header')).getText() - await delay(300) - const element = driver.findElement(By.linkText('Attributions')) + element = driver.findElement(By.linkText('Attributions')) await driver.executeScript('arguments[0].scrollIntoView(true)', element) await delay(300) - button = await driver.findElement(By.css('button')) - const buttonEnabled = await button.isEnabled() - await delay(500) await captureScreenShot('terms-scrolled') - await button.click() + await driver.findElement(By.css('button')).click() await delay(300) - await captureScreenShot('choose-password') + await captureScreenShot('secret backup phrase') - const passwordBox = await driver.findElement(By.id('password-box')) - const passwordBoxConfirm = await driver.findElement(By.id('password-box-confirm')) - button = driver.findElement(By.css('button')) - passwordBox.sendKeys('123456789') - passwordBoxConfirm.sendKeys('123456789') - await delay(500) - await captureScreenShot('choose-password-filled') + await driver.findElement(By.css('button')).click() + await delay(300) + await captureScreenShot('secret backup phrase') - await button.click() - await delay(700) - this.seedPhase = await driver.findElement(By.css('.twelve-word-phrase')).getText() - await captureScreenShot('seed phrase') + await driver.findElement(By.css('.backup-phrase__reveal-button')).click() + await delay(300) + await captureScreenShot('secret backup phrase - reveal') - const continueAfterSeedPhrase = await driver.findElement(By.css('button')) - await continueAfterSeedPhrase.click() + await driver.findElement(By.css('button')).click() await delay(300) - await captureScreenShot('main screen') + await captureScreenShot('confirm secret backup phrase') - await driver.findElement(By.css('.sandwich-expando')).click() - await delay(500) - await captureScreenShot('menu') + // finish up + console.log('building gif...') + await generateGif() + await driver.quit() + return + + // + // await button.click() + // await delay(700) + // this.seedPhase = await driver.findElement(By.css('.twelve-word-phrase')).getText() + // await captureScreenShot('seed phrase') + // + // const continueAfterSeedPhrase = await driver.findElement(By.css('button')) + // await continueAfterSeedPhrase.click() + // await delay(300) + // await captureScreenShot('main screen') + // + // await driver.findElement(By.css('.sandwich-expando')).click() + // await delay(500) + // await captureScreenShot('menu') // await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)')).click() // await captureScreenShot('main screen') @@ -119,8 +147,12 @@ async function captureAllScreens() { // cleanup await driver.quit() + async function cleanScreenShotDir() { + await pify(rimraf)(`./test-artifacts/screens/`) + } + async function captureScreenShot(label) { - const shotIndex = screenshotCount + const shotIndex = screenshotCount.toString().padStart(4, '0') screenshotCount++ const artifactDir = `./test-artifacts/screens/` await pify(mkdirp)(artifactDir) @@ -138,7 +170,7 @@ async function captureAllScreens() { // read all pngs into gif const encoder = new GIFEncoder(size.width, size.height) const stream = pngFileStream('./test-artifacts/screens/*.png') - .pipe(encoder.createWriteStream({ repeat: -1, delay: 500, quality: 10 })) + .pipe(encoder.createWriteStream({ repeat: -1, delay: 1000, quality: 10 })) .pipe(fs.createWriteStream('./test-artifacts/screens/walkthrough.gif')) // wait for end From fcdfd48057db83801d37bc54b1a04c0a328ab24c Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 00:48:37 -0700 Subject: [PATCH 142/246] development - screenshotter - capture screens across all locales --- test/screens/new.spec.js | 43 ++++++++++++++++++++++++++++------------ ui/index.js | 5 +++++ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/test/screens/new.spec.js b/test/screens/new.spec.js index f17781d7a..83b960c58 100644 --- a/test/screens/new.spec.js +++ b/test/screens/new.spec.js @@ -10,6 +10,7 @@ const pngFileStream = require('png-file-stream') const sizeOfPng = require('image-size/lib/types/png') const By = webdriver.By const { delay, buildWebDriver } = require('./func') +const localesIndex = require('../../app/_locales/index.json') captureAllScreens().catch(console.error) @@ -49,62 +50,62 @@ async function captureAllScreens() { driver.close() await driver.switchTo().window(tabs[0]) await delay(300) - await captureScreenShot('welcome-new-ui') + await captureLanguageScreenShots('welcome-new-ui') // setup account await delay(1000) await driver.findElement(By.css('body')).click() await delay(300) - await captureScreenShot('welcome') + await captureLanguageScreenShots('welcome') await driver.findElement(By.css('button')).click() - await captureScreenShot('create password') + await captureLanguageScreenShots('create password') const passwordBox = await driver.findElement(By.css('input[type=password]:nth-of-type(1)')) const passwordBoxConfirm = await driver.findElement(By.css('input[type=password]:nth-of-type(2)')) passwordBox.sendKeys('123456789') passwordBoxConfirm.sendKeys('123456789') await delay(500) - await captureScreenShot('choose-password-filled') + await captureLanguageScreenShots('choose-password-filled') await driver.findElement(By.css('button')).click() await delay(500) - await captureScreenShot('unique account image') + await captureLanguageScreenShots('unique account image') await driver.findElement(By.css('button')).click() await delay(500) - await captureScreenShot('privacy note') + await captureLanguageScreenShots('privacy note') await driver.findElement(By.css('button')).click() await delay(300) - await captureScreenShot('terms') + await captureLanguageScreenShots('terms') await delay(300) element = driver.findElement(By.linkText('Attributions')) await driver.executeScript('arguments[0].scrollIntoView(true)', element) await delay(300) - await captureScreenShot('terms-scrolled') + await captureLanguageScreenShots('terms-scrolled') await driver.findElement(By.css('button')).click() await delay(300) - await captureScreenShot('secret backup phrase') + await captureLanguageScreenShots('secret backup phrase') await driver.findElement(By.css('button')).click() await delay(300) - await captureScreenShot('secret backup phrase') + await captureLanguageScreenShots('secret backup phrase') await driver.findElement(By.css('.backup-phrase__reveal-button')).click() await delay(300) - await captureScreenShot('secret backup phrase - reveal') + await captureLanguageScreenShots('secret backup phrase - reveal') await driver.findElement(By.css('button')).click() await delay(300) - await captureScreenShot('confirm secret backup phrase') + await captureLanguageScreenShots('confirm secret backup phrase') // finish up console.log('building gif...') await generateGif() - await driver.quit() + // await driver.quit() return // @@ -144,6 +145,22 @@ async function captureAllScreens() { // await delay(500) // }) + async function captureLanguageScreenShots(label) { + const nonEnglishLocales = localesIndex.filter(localeMeta => localeMeta.code !== 'en') + for (let localeMeta of nonEnglishLocales) { + // set locale + await setLocale(localeMeta.code) + await delay(300) + await captureScreenShot(`${label} (${localeMeta.code})`) + } + await setLocale('en') + await delay(300) + } + + async function setLocale(code) { + await driver.executeScript('setLocale(arguments[0])', code) + } + // cleanup await driver.quit() diff --git a/ui/index.js b/ui/index.js index 1e0e9f1cc..8fb000d85 100644 --- a/ui/index.js +++ b/ui/index.js @@ -69,6 +69,11 @@ async function startApp (metamaskState, accountManager, opts) { store.dispatch(actions.updateMetamaskState(metamaskState)) }) + // used by screenshotter tooling + global.setLocale = (key) => { + store.dispatch(actions.updateCurrentLocale(key)) + } + // start app render( h(Root, { From 0d27d27efa31f614973e6e5cbc8f53cc85aa0bc2 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 00:59:16 -0700 Subject: [PATCH 143/246] development - screenshotter - capture en locale and build gif from only en --- test/screens/new.spec.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/test/screens/new.spec.js b/test/screens/new.spec.js index 83b960c58..14daac1c1 100644 --- a/test/screens/new.spec.js +++ b/test/screens/new.spec.js @@ -36,8 +36,6 @@ async function captureAllScreens() { await driver.switchTo().window(tabs[0]) await delay(300) - await captureScreenShot('start-old') - // click try new ui await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-center.flex-grow > p')).click() await delay(300) @@ -105,7 +103,7 @@ async function captureAllScreens() { // finish up console.log('building gif...') await generateGif() - // await driver.quit() + await driver.quit() return // @@ -147,12 +145,15 @@ async function captureAllScreens() { async function captureLanguageScreenShots(label) { const nonEnglishLocales = localesIndex.filter(localeMeta => localeMeta.code !== 'en') + // take english shot + await captureScreenShot(`${label} (en)`) for (let localeMeta of nonEnglishLocales) { - // set locale + // set locale and take shot await setLocale(localeMeta.code) await delay(300) await captureScreenShot(`${label} (${localeMeta.code})`) } + // return locale to english await setLocale('en') await delay(300) } @@ -184,11 +185,11 @@ async function captureAllScreens() { const pngBuffer = Buffer.from(screenshot, 'base64') const size = sizeOfPng.calculate(pngBuffer) - // read all pngs into gif + // read only the english pngs into gif const encoder = new GIFEncoder(size.width, size.height) - const stream = pngFileStream('./test-artifacts/screens/*.png') + const stream = pngFileStream('./test-artifacts/screens/* (en).png') .pipe(encoder.createWriteStream({ repeat: -1, delay: 1000, quality: 10 })) - .pipe(fs.createWriteStream('./test-artifacts/screens/walkthrough.gif')) + .pipe(fs.createWriteStream('./test-artifacts/screens/walkthrough (en).gif')) // wait for end await pify(endOfStream)(stream) From b2f02300a3ba098c84b385523aeaf1f09fe22f8e Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 01:01:16 -0700 Subject: [PATCH 144/246] ci - run screenshotter --- .circleci/config.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index ae6f44c8a..ef08d4c48 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,6 +19,10 @@ workflows: requires: - prep-build - prep-deps-npm + - test-screens: + requires: + - prep-build + - prep-deps-npm - test-unit: requires: - prep-deps-npm @@ -45,6 +49,7 @@ workflows: - test-lint - test-unit - test-e2e + - test-screens - test-integration-mascara-chrome - test-integration-mascara-firefox - test-integration-flat-chrome @@ -145,6 +150,22 @@ jobs: path: test-artifacts destination: test-artifacts + test-screens: + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: dependency-cache-{{ checksum "package-lock.json" }} + - restore_cache: + key: build-cache-{{ .Revision }} + - run: + name: Test + command: npm run test:screens + - store_artifacts: + path: test-artifacts + destination: test-artifacts + test-unit: docker: - image: circleci/node:8-browsers From 5f1f345a5d7f428c939a6ab3cbf9d5ac56cb58ed Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 10:59:39 -0700 Subject: [PATCH 145/246] network - use providerType for localhost --- ui/app/actions.js | 5 +++-- ui/app/components/dropdowns/network-dropdown.js | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ui/app/actions.js b/ui/app/actions.js index 58240054d..ad4270cef 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -1300,7 +1300,7 @@ function retryTransaction (txId) { function setProviderType (type) { return (dispatch) => { - log.debug(`background.setProviderType`) + log.debug(`background.setProviderType`, type) background.setProviderType(type, (err, result) => { if (err) { log.error(err) @@ -1321,13 +1321,14 @@ function updateProviderType (type) { } function setRpcTarget (newRpc) { - log.debug(`background.setRpcTarget: ${newRpc}`) return (dispatch) => { + log.debug(`background.setRpcTarget: ${newRpc}`) background.setCustomRpc(newRpc, (err, result) => { if (err) { log.error(err) return dispatch(self.displayWarning('Had a problem changing networks!')) } + dispatch(actions.setSelectedToken()) }) } } diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index 94e5d967b..9e47f38ef 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -203,18 +203,18 @@ NetworkDropdown.prototype.render = function () { { key: 'default', closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => props.setRpcTarget('http://localhost:8545'), + onClick: () => props.setProviderType('localhost'), style: dropdownMenuItemStyle, }, [ - activeNetwork === 'http://localhost:8545' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), + providerType === 'localhost' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), h(NetworkDropdownIcon, { - isSelected: activeNetwork === 'http://localhost:8545', + isSelected: providerType === 'localhost', innerBorder: '1px solid #9b9b9b', }), h('span.network-name-item', { style: { - color: activeNetwork === 'http://localhost:8545' ? '#ffffff' : '#9b9b9b', + color: providerType === 'localhost' ? '#ffffff' : '#9b9b9b', }, }, this.context.t('localhost')), ] From b014133fdc14ca4fe83b9cb59d181a7745af8de7 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 11:16:08 -0700 Subject: [PATCH 146/246] development - screens - use localhost for network --- test/screens/new.spec.js | 15 ++++++++++++--- ui/index.js | 11 ++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/test/screens/new.spec.js b/test/screens/new.spec.js index 14daac1c1..2af891060 100644 --- a/test/screens/new.spec.js +++ b/test/screens/new.spec.js @@ -35,6 +35,7 @@ async function captureAllScreens() { tabs = await driver.getAllWindowHandles() await driver.switchTo().window(tabs[0]) await delay(300) + await setProviderType('localhost') // click try new ui await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-center.flex-grow > p')).click() @@ -42,8 +43,12 @@ async function captureAllScreens() { // close metamask homepage and extra home.html tabs = await driver.getAllWindowHandles() - await driver.switchTo().window(tabs[2]) - driver.close() + console.log(tabs) + // metamask homepage is opened on prod, not dev + if (tabs.length > 2) { + await driver.switchTo().window(tabs[2]) + driver.close() + } await driver.switchTo().window(tabs[1]) driver.close() await driver.switchTo().window(tabs[0]) @@ -159,7 +164,11 @@ async function captureAllScreens() { } async function setLocale(code) { - await driver.executeScript('setLocale(arguments[0])', code) + await driver.executeScript('window.metamask.updateCurrentLocale(arguments[0])', code) + } + + async function setProviderType(type) { + await driver.executeScript('window.metamask.setProviderType(arguments[0])', type) } // cleanup diff --git a/ui/index.js b/ui/index.js index 8fb000d85..746e28eab 100644 --- a/ui/index.js +++ b/ui/index.js @@ -69,9 +69,14 @@ async function startApp (metamaskState, accountManager, opts) { store.dispatch(actions.updateMetamaskState(metamaskState)) }) - // used by screenshotter tooling - global.setLocale = (key) => { - store.dispatch(actions.updateCurrentLocale(key)) + // global metamask api - used by tooling + global.metamask = { + updateCurrentLocale: (code) => { + store.dispatch(actions.updateCurrentLocale(code)) + }, + setProviderType: (type) => { + store.dispatch(actions.setProviderType(type)) + }, } // start app From 43c402227d470a201125f4f4e2613a6a00bafbd9 Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 30 Mar 2018 11:51:51 -0700 Subject: [PATCH 147/246] Ganache:start script with seed phrase --- package.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5b24a0fd6..4e618f563 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,8 @@ "test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js", "test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara", "test:integration:build": "gulp build:scss", - "test:e2e": "METAMASK_ENV=test mocha test/e2e/metamask.spec --recursive", - "test:screens": "METAMASK_ENV=test mocha test/screens/new.spec --recursive", + "test:e2e": "cross-env METAMASK_ENV=test mocha test/e2e/metamask.spec --recursive", + "test:screens": "cross-env METAMASK_ENV=test npm run ganache:start & mocha test/screens/new.spec --recursive || kill $!", "test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload", "test:coveralls-upload": "if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi", "test:flat": "npm run test:flat:build && karma start test/flat.conf.js", @@ -33,6 +33,7 @@ "test:mascara:build:locales": "mkdirp dist/chrome && cp -R app/_locales dist/chrome/_locales", "test:mascara:build:background": "browserify mascara/src/background.js -o dist/mascara/background.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'", "sentry": "export RELEASE=`cat app/manifest.json| jq -r .version` && npm run sentry:release && npm run sentry:upload", "sentry:release": "npm run sentry:release:new && npm run sentry:release:clean", "sentry:release:new": "sentry-cli releases --org 'metamask' --project 'metamask' new $RELEASE", @@ -220,6 +221,7 @@ "eslint-plugin-react": "^7.4.0", "eth-json-rpc-middleware": "^1.2.7", "fs-promise": "^2.0.3", + "ganache-cli": "^6.1.0", "gifencoder": "^1.1.0", "gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed", "gulp-babel": "^7.0.0", From 37acf5ff4f47a2eb62e3dc3bcffb9d2894ea624d Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 30 Mar 2018 12:26:23 -0700 Subject: [PATCH 148/246] Update package-lock --- package-lock.json | 1959 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 1889 insertions(+), 70 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc16f4780..0f4f02f79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -224,6 +224,12 @@ } } }, + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "dev": true + }, "@sinonjs/formatio": { "version": "2.0.0", "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", @@ -571,6 +577,12 @@ "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", "dev": true }, + "any-observable": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.2.0.tgz", + "integrity": "sha1-xnhwBYADV5AJCD9UrAq6+1wz0kI=", + "dev": true + }, "any-promise": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-0.1.0.tgz", @@ -2816,6 +2828,29 @@ } } }, + "cacheable-request": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", + "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "dev": true, + "requires": { + "clone-response": "1.0.2", + "get-stream": "3.0.0", + "http-cache-semantics": "3.8.1", + "keyv": "3.0.0", + "lowercase-keys": "1.0.0", + "normalize-url": "2.0.1", + "responselike": "1.0.2" + }, + "dependencies": { + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=", + "dev": true + } + } + }, "cached-path-relative": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz", @@ -3120,6 +3155,47 @@ "restore-cursor": "2.0.0" } }, + "cli-spinners": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz", + "integrity": "sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw=", + "dev": true + }, + "cli-table": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", + "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "dev": true, + "requires": { + "colors": "1.0.3" + }, + "dependencies": { + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + } + } + }, + "cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "dev": true, + "requires": { + "slice-ansi": "0.0.4", + "string-width": "1.0.2" + }, + "dependencies": { + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + } + } + }, "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", @@ -3160,6 +3236,15 @@ "is-supported-regexp-flag": "1.0.0" } }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "1.0.0" + } + }, "clone-stats": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", @@ -3957,6 +4042,12 @@ "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=" }, + "dargs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-5.1.0.tgz", + "integrity": "sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk=", + "dev": true + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -3972,6 +4063,12 @@ "dev": true, "optional": true }, + "date-fns": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz", + "integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==", + "dev": true + }, "date-format": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", @@ -4043,6 +4140,15 @@ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "1.0.0" + } + }, "deep-diff": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz", @@ -4251,6 +4357,12 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "detect-conflict": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/detect-conflict/-/detect-conflict-1.0.1.tgz", + "integrity": "sha1-CIZXpmqWHAUBnbfEIwiDsca0F24=", + "dev": true + }, "detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", @@ -4629,6 +4741,12 @@ } } }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, "duplexify": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.1.tgz", @@ -4658,6 +4776,12 @@ "jsbn": "0.1.1" } }, + "editions": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", + "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==", + "dev": true + }, "editorconfig": { "version": "0.13.3", "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.13.3.tgz", @@ -4687,6 +4811,12 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "ejs": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.8.tgz", + "integrity": "sha512-QIDZL54fyV8MDcAsO91BMH1ft2qGGaHIJsJIA/+t+7uvXol1dm413fPcUgUb4k8F/9457rx4/KFE4XfDifrQxQ==", + "dev": true + }, "electron-releases": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/electron-releases/-/electron-releases-2.1.0.tgz", @@ -4700,6 +4830,12 @@ "electron-releases": "2.1.0" } }, + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "dev": true + }, "elliptic": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", @@ -4934,6 +5070,16 @@ "prr": "1.0.1" } }, + "error": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", + "dev": true, + "requires": { + "string-template": "0.2.1", + "xtend": "4.0.1" + } + }, "error-ex": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", @@ -6274,6 +6420,12 @@ "integrity": "sha1-BmDjUlouidnkRhKUQMJy7foktSk=", "dev": true }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, "expand-braces": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", @@ -7109,6 +7261,12 @@ "resolved": "https://registry.npmjs.org/flatten/-/flatten-0.0.1.tgz", "integrity": "sha1-VURAdm2goNYDmZ9DNFP2wvxqdcE=" }, + "flow-parser": { + "version": "0.69.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.69.0.tgz", + "integrity": "sha1-N4tRKNbQtVSosvFqTKPhq5ZJ8A4=", + "dev": true + }, "flush-write-stream": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.2.tgz", @@ -7208,6 +7366,16 @@ "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", "dev": true }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, "fs-access": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", @@ -8145,6 +8313,33 @@ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.2.0.tgz", "integrity": "sha1-8ESOgGmFW/Kj5oPNwdMg5+KgfvQ=" }, + "ganache-cli": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.1.0.tgz", + "integrity": "sha512-FdTeyk4uLRHGeFiMe+Qnh4Hc5KiTVqvRVVvLDFJEVVKC1P1yHhEgZeh9sp1KhuvxSrxToxgJS25UapYQwH4zHw==", + "dev": true, + "requires": { + "source-map-support": "0.5.4", + "webpack-cli": "2.0.13" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.4.tgz", + "integrity": "sha512-PETSPG6BjY1AHs2t64vS2aqAgu6dMIMXJULWFBGbh2Gr8nVLbCFDo6i/RMMvviIQ2h1Z8+5gQhVKSn2je9nmdg==", + "dev": true, + "requires": { + "source-map": "0.6.1" + } + } + } + }, "gather-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gather-stream/-/gather-stream-1.0.0.tgz", @@ -8238,12 +8433,85 @@ "assert-plus": "1.0.0" } }, + "gh-got": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-6.0.0.tgz", + "integrity": "sha512-F/mS+fsWQMo1zfgG9MD8KWvTWPPzzhuVwY++fhQ5Ggd+0P+CAMHtzMZhNxG+TqGfHDChJKsbh6otfMGqO2AKBw==", + "dev": true, + "requires": { + "got": "7.1.0", + "is-plain-obj": "1.1.0" + }, + "dependencies": { + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "dev": true, + "requires": { + "decompress-response": "3.3.0", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "is-plain-obj": "1.1.0", + "is-retry-allowed": "1.1.0", + "is-stream": "1.1.0", + "isurl": "1.0.0", + "lowercase-keys": "1.0.1", + "p-cancelable": "0.3.0", + "p-timeout": "1.2.1", + "safe-buffer": "5.1.1", + "timed-out": "4.0.1", + "url-parse-lax": "1.0.0", + "url-to-options": "1.0.1" + } + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", + "dev": true + }, + "p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", + "dev": true, + "requires": { + "p-finally": "1.0.0" + } + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "1.0.4" + } + } + } + }, "gifencoder": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/gifencoder/-/gifencoder-1.1.0.tgz", "integrity": "sha512-MVh++nximxsp8NaNRfS1+MmCviZ4wi7HhuvX8eHrfNn//1mqi8Eb03tKs6Z+lIIcSEySJ6PmS1VPZ+HdtEMlfg==", "dev": true }, + "github-username": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/github-username/-/github-username-4.1.0.tgz", + "integrity": "sha1-y+KABBiDIG2kISrp5LXxacML9Bc=", + "dev": true, + "requires": { + "gh-got": "6.0.0" + } + }, "gl-mat4": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/gl-mat4/-/gl-mat4-1.1.4.tgz", @@ -8452,6 +8720,31 @@ "sparkles": "1.0.0" } }, + "got": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.0.tgz", + "integrity": "sha512-kBNy/S2CGwrYgDSec5KTWGKUvupwkkTVAjIsVFF2shXO13xpZdFP4d4kxa//CLX2tN/rV0aYwK8vY6UKWGn2vQ==", + "dev": true, + "requires": { + "@sindresorhus/is": "0.7.0", + "cacheable-request": "2.1.4", + "decompress-response": "3.3.0", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "into-stream": "3.1.0", + "is-retry-allowed": "1.1.0", + "isurl": "1.0.0", + "lowercase-keys": "1.0.1", + "mimic-response": "1.0.0", + "p-cancelable": "0.4.0", + "p-timeout": "2.0.1", + "pify": "3.0.0", + "safe-buffer": "5.1.1", + "timed-out": "4.0.1", + "url-parse-lax": "3.0.0", + "url-to-options": "1.0.1" + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -8463,6 +8756,15 @@ "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", "dev": true }, + "grouped-queue": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-0.3.3.tgz", + "integrity": "sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, "growl": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", @@ -9588,6 +9890,12 @@ } } }, + "has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", + "dev": true + }, "has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", @@ -9607,11 +9915,26 @@ "sparkles": "1.0.0" } }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true + }, "has-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "1.4.2" + } + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -9934,6 +10257,12 @@ "readable-stream": "2.3.3" } }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, "http-errors": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", @@ -10373,6 +10702,16 @@ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" }, + "into-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "dev": true, + "requires": { + "from2": "2.3.0", + "p-is-promise": "1.1.0" + } + }, "invariant": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", @@ -10630,6 +10969,29 @@ "integrity": "sha1-8mWrian0RQNO9q/xWo8AsA9VF5k=", "dev": true }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, + "is-observable": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-0.2.0.tgz", + "integrity": "sha1-s2ExHYPG5dcmyr9eJQsCNxBvWuI=", + "dev": true, + "requires": { + "symbol-observable": "0.2.4" + }, + "dependencies": { + "symbol-observable": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-0.2.4.tgz", + "integrity": "sha1-lag9smGG1q9+ehjb2XYKL4bQj0A=", + "dev": true + } + } + }, "is-odd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-1.0.0.tgz", @@ -10738,6 +11100,21 @@ "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.1.tgz", "integrity": "sha512-y5CXYbzvB3jTnWAZH1Nl7ykUWb6T3BcTs56HUruwBf8MhF56n1HWqhDWnVFo8GHrUPDgvUUNVhrc2U8W7iqz5g==" }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "dev": true + }, + "is-scoped": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-scoped/-/is-scoped-1.0.0.tgz", + "integrity": "sha1-RJypgpnnEwOCViieyytUDcQ3yzA=", + "dev": true, + "requires": { + "scoped-regex": "1.0.0" + } + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -10861,6 +11238,16 @@ "textextensions": "1.0.2" } }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "requires": { + "has-to-string-tag-x": "1.4.1", + "is-object": "1.0.1" + } + }, "jazzicon": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/jazzicon/-/jazzicon-1.5.0.tgz", @@ -10918,6 +11305,106 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, + "jscodeshift": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.5.0.tgz", + "integrity": "sha512-JAcQINNMFpdzzpKJN8k5xXjF3XDuckB1/48uScSzcnNyK199iWEc9AxKL9OoX5144M2w5zEx9Qs4/E/eBZZUlw==", + "dev": true, + "requires": { + "babel-plugin-transform-flow-strip-types": "6.22.0", + "babel-preset-es2015": "6.24.1", + "babel-preset-stage-1": "6.24.1", + "babel-register": "6.26.0", + "babylon": "7.0.0-beta.42", + "colors": "1.2.1", + "flow-parser": "0.69.0", + "lodash": "4.17.4", + "micromatch": "2.3.11", + "neo-async": "2.5.0", + "node-dir": "0.1.8", + "nomnom": "1.8.1", + "recast": "0.14.7", + "temp": "0.8.3", + "write-file-atomic": "1.3.4" + }, + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "dev": true + }, + "ast-types": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.3.tgz", + "integrity": "sha512-XA5o5dsNw8MhyW0Q7MWXJWc4oOzZKbdsEJq45h7c8q/d9DwWZ5F2ugUc1PuMLPGsUnphCt/cNDHu8JeBbxf1qA==", + "dev": true + }, + "babylon": { + "version": "7.0.0-beta.42", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.42.tgz", + "integrity": "sha512-h6E/OkkvcBw/JimbL0p8dIaxrcuQn3QmIYGC/GtJlRYif5LTKBYPHXYwqluJpfS/kOXoz0go+9mkmOVC0M+zWw==", + "dev": true + }, + "chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "dev": true, + "requires": { + "ansi-styles": "1.0.0", + "has-color": "0.1.7", + "strip-ansi": "0.1.1" + } + }, + "colors": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.1.tgz", + "integrity": "sha512-s8+wktIuDSLffCywiwSxQOMqtPxML11a/dtHE17tMn4B1MSWw/C22EKf7M2KGUBcDaVFEGT+S8N02geDXeuNKg==", + "dev": true + }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "dev": true, + "requires": { + "chalk": "0.4.0", + "underscore": "1.6.0" + } + }, + "recast": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.14.7.tgz", + "integrity": "sha512-/nwm9pkrcWagN40JeJhkPaRxiHXBRkXyRh/hgU088Z/v+qCy+zIHHY6bC6o7NaKAxPqtE6nD8zBH1LfU0/Wx6A==", + "dev": true, + "requires": { + "ast-types": "0.11.3", + "esprima": "4.0.0", + "private": "0.1.8", + "source-map": "0.6.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", + "dev": true + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + } + } + }, "jsdom": { "version": "11.5.1", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.5.1.tgz", @@ -11009,11 +11496,23 @@ "text-table": "0.2.0" } }, - "json-loader": { - "version": "0.5.7", + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-loader": { + "version": "0.5.7", "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==" }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, "json-rpc-engine": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.6.1.tgz", @@ -11633,6 +12132,15 @@ "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", "dev": true }, + "keyv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -11976,6 +12484,132 @@ "resolve": "1.4.0" } }, + "listr": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.13.0.tgz", + "integrity": "sha1-ILsLowuuZg7oTMBQPfS+PVYjiH0=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-truncate": "0.2.1", + "figures": "1.7.0", + "indent-string": "2.1.0", + "is-observable": "0.2.0", + "is-promise": "2.1.0", + "is-stream": "1.1.0", + "listr-silent-renderer": "1.1.1", + "listr-update-renderer": "0.4.0", + "listr-verbose-renderer": "0.4.1", + "log-symbols": "1.0.2", + "log-update": "1.0.2", + "ora": "0.2.3", + "p-map": "1.2.0", + "rxjs": "5.5.8", + "stream-to-observable": "0.2.0", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + } + } + }, + "listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", + "dev": true + }, + "listr-update-renderer": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz", + "integrity": "sha1-NE2YDaLKLosUW6MFkI8yrj9MyKc=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-truncate": "0.2.1", + "elegant-spinner": "1.0.1", + "figures": "1.7.0", + "indent-string": "3.2.0", + "log-symbols": "1.0.2", + "log-update": "1.0.2", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + } + } + }, + "listr-verbose-renderer": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", + "integrity": "sha1-ggb0z21S3cWCfl/RSYng6WWTOjU=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "date-fns": "1.29.0", + "figures": "1.7.0" + }, + "dependencies": { + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "1.0.1" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } + } + } + }, "livereload-js": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz", @@ -12017,6 +12651,24 @@ "object-assign": "4.1.1" } }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, "lodash": { "version": "4.17.4", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", @@ -12268,6 +12920,49 @@ "chalk": "1.1.3" } }, + "log-update": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz", + "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "cli-cursor": "1.0.2" + }, + "dependencies": { + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "1.0.1" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } + } + } + }, "log4js": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.5.3.tgz", @@ -12535,6 +13230,12 @@ "signal-exit": "3.0.2" } }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, "lru-cache": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", @@ -12635,6 +13336,15 @@ } } }, + "make-dir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz", + "integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==", + "dev": true, + "requires": { + "pify": "3.0.0" + } + }, "make-error": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", @@ -13039,6 +13749,108 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "1.1.0" + } + }, + "mem-fs": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/mem-fs/-/mem-fs-1.1.3.tgz", + "integrity": "sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw=", + "dev": true, + "requires": { + "through2": "2.0.3", + "vinyl": "1.2.0", + "vinyl-file": "2.0.0" + }, + "dependencies": { + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "dev": true + }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "dev": true + }, + "vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", + "dev": true, + "requires": { + "clone": "1.0.4", + "clone-stats": "0.0.1", + "replace-ext": "0.0.1" + } + } + } + }, + "mem-fs-editor": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-3.0.2.tgz", + "integrity": "sha1-3Qpuryu4prN3QAZ6pUnrUwEFr58=", + "dev": true, + "requires": { + "commondir": "1.0.1", + "deep-extend": "0.4.2", + "ejs": "2.5.8", + "glob": "7.1.2", + "globby": "6.1.0", + "mkdirp": "0.5.1", + "multimatch": "2.1.0", + "rimraf": "2.6.2", + "through2": "2.0.3", + "vinyl": "2.1.0" + }, + "dependencies": { + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "deep-extend": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", + "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=", + "dev": true + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, "memdown": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/memdown/-/memdown-1.4.1.tgz", @@ -13262,6 +14074,12 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=" }, + "mimic-response": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz", + "integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=", + "dev": true + }, "min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", @@ -13681,6 +14499,12 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, + "neo-async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.0.tgz", + "integrity": "sha512-nJmSswG4As/MkRq7QZFuH/sf/yuv8ODdMZrY4Bedjp77a5MK4A6s7YbBB64c9u79EBUOfXUXBvArmvzTD0X+6g==", + "dev": true + }, "netmask": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", @@ -13694,6 +14518,12 @@ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, + "nice-try": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", + "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==", + "dev": true + }, "nise": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/nise/-/nise-1.3.2.tgz", @@ -13777,6 +14607,12 @@ } } }, + "node-dir": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.8.tgz", + "integrity": "sha1-VfuN62mQcHB/tn+RpGDwRIKUx30=", + "dev": true + }, "node-fetch": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", @@ -14197,6 +15033,17 @@ "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=", "dev": true }, + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "dev": true, + "requires": { + "prepend-http": "2.0.0", + "query-string": "5.1.1", + "sort-keys": "2.0.0" + } + }, "now-and-later": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.0.tgz", @@ -16217,6 +17064,45 @@ "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", "dev": true }, + "ora": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", + "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-spinners": "0.1.2", + "object-assign": "4.1.1" + }, + "dependencies": { + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "1.0.1" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } + } + } + }, "ordered-read-streams": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", @@ -16266,18 +17152,84 @@ "shell-quote": "1.6.1" } }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "p-cancelable": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.0.tgz", + "integrity": "sha512-/AodqPe1y/GYbhSlnMjxukLGQfQIgsmjSy2CXCNB96kg4ozKvmlovuHEKICToOO/yS3LLWgrWI1dFtFfrePS1g==", "dev": true }, - "p-map": { - "version": "1.2.0", + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "dev": true + }, + "p-lazy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-lazy/-/p-lazy-1.0.0.tgz", + "integrity": "sha1-7FPIAvLuOsKPFmzILQsrAt4nqDU=", + "dev": true + }, + "p-limit": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", + "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "dev": true, + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.2.0" + } + }, + "p-map": { + "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", "dev": true }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "dev": true, + "requires": { + "p-finally": "1.0.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, "pac-proxy-agent": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-1.1.0.tgz", @@ -17176,11 +18128,23 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, "preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" }, + "prettier": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.11.1.tgz", + "integrity": "sha512-T/KD65Ot0PB97xTrG8afQ46x3oiVhnfGjGESSI9NWYcG92+OUPZKkwHqGWXH2t9jK1crnQjubECW0FuOth+hxw==", + "dev": true + }, "pretty-bytes": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-0.1.2.tgz", @@ -17406,6 +18370,17 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "0.2.0", + "object-assign": "4.1.1", + "strict-uri-encode": "1.1.0" + } + }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -17886,6 +18861,16 @@ "mute-stream": "0.0.7" } }, + "read-chunk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz", + "integrity": "sha1-agTAkoAF7Z1C4aasVgDhnLx/9lU=", + "dev": true, + "requires": { + "pify": "3.0.0", + "safe-buffer": "5.1.1" + } + }, "read-file-stdin": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/read-file-stdin/-/read-file-stdin-0.2.1.tgz", @@ -18369,6 +19354,23 @@ "path-parse": "1.0.5" } }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, "resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", @@ -18402,6 +19404,15 @@ "integrity": "sha1-2ksXzHaEyYyWK+tNlfZoyNytCdU=", "dev": true }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "1.0.1" + } + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -18497,6 +19508,23 @@ "rx-lite": "4.0.8" } }, + "rxjs": { + "version": "5.5.8", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.8.tgz", + "integrity": "sha512-Bz7qou7VAIoGiglJZbzbXa4vpX5BmTTN2Dj/se6+SwADtw4SihqBIiEa7VmTXJ8pynvq0iFr5Gx9VLyye1rIxQ==", + "dev": true, + "requires": { + "symbol-observable": "1.0.1" + }, + "dependencies": { + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + } + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -18586,6 +19614,12 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "scoped-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/scoped-regex/-/scoped-regex-1.0.0.tgz", + "integrity": "sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=", + "dev": true + }, "script-injector": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/script-injector/-/script-injector-1.0.0.tgz", @@ -18861,6 +19895,17 @@ "jsonify": "0.0.0" } }, + "shelljs": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.1.tgz", + "integrity": "sha512-YA/iYtZpzFe5HyWVGrb02FjPxc4EMCfpoU/Phg9fQoyMC72u9598OUBrsU8IrtwAKG0tO8IYaqbaLIw+k3IRGA==", + "dev": true, + "requires": { + "glob": "7.1.2", + "interpret": "1.1.0", + "rechoir": "0.6.2" + } + }, "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", @@ -18940,6 +19985,12 @@ } } }, + "slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "dev": true + }, "smart-buffer": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", @@ -19313,6 +20364,15 @@ } } }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "1.1.0" + } + }, "source-list-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", @@ -19835,6 +20895,15 @@ } } }, + "stream-to-observable": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/stream-to-observable/-/stream-to-observable-0.2.0.tgz", + "integrity": "sha1-WdbqOT2HwsDdrBCqDVYbxrpvDhA=", + "dev": true, + "requires": { + "any-observable": "0.2.0" + } + }, "streamroller": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", @@ -19858,6 +20927,12 @@ } } }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, "string-length": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", @@ -19867,6 +20942,12 @@ "strip-ansi": "3.0.1" } }, + "string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "dev": true + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -20686,6 +21767,24 @@ "inherits": "2.0.3" } }, + "temp": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", + "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2", + "rimraf": "2.2.8" + }, + "dependencies": { + "rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "dev": true + } + } + }, "ternary-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-2.0.1.tgz", @@ -20970,6 +22069,12 @@ "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, "timers-browserify": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", @@ -21577,6 +22682,12 @@ } } }, + "untildify": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.2.tgz", + "integrity": "sha1-fx8wIFWz/qDz6B3HjrNnZstl4/E=", + "dev": true + }, "upath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.0.tgz", @@ -21616,6 +22727,21 @@ } } }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "2.0.0" + } + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true + }, "use": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/use/-/use-2.0.2.tgz", @@ -21772,6 +22898,12 @@ "dev": true, "optional": true }, + "v8-compile-cache": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz", + "integrity": "sha512-ejdrifsIydN1XDH7EuR2hn8ZrkRKUYF7tUcBjBy/lhrCvs2K+zRlbW9UHc0IQ9RsYFZJFqJrieoIHfkCa0DBRA==", + "dev": true + }, "v8flags": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.2.tgz", @@ -22422,79 +23554,479 @@ } } }, - "webpack-sources": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", - "integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==", + "webpack-addons": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/webpack-addons/-/webpack-addons-1.1.5.tgz", + "integrity": "sha512-MGO0nVniCLFAQz1qv22zM02QPjcpAoJdy7ED0i3Zy7SY1IecgXCm460ib7H/Wq7e9oL5VL6S2BxaObxwIcag0g==", + "dev": true, "requires": { - "source-list-map": "2.0.0", - "source-map": "0.6.1" + "jscodeshift": "0.4.1" }, "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "dev": true + }, + "ast-types": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.10.1.tgz", + "integrity": "sha512-UY7+9DPzlJ9VM8eY0b2TUZcZvF+1pO0hzMtAyjBYKhOmnvRlqYNYnWdtsMj0V16CGaMlpL0G1jnLbLo4AyotuQ==", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "dev": true, + "requires": { + "ansi-styles": "1.0.0", + "has-color": "0.1.7", + "strip-ansi": "0.1.1" + } + }, + "colors": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.1.tgz", + "integrity": "sha512-s8+wktIuDSLffCywiwSxQOMqtPxML11a/dtHE17tMn4B1MSWw/C22EKf7M2KGUBcDaVFEGT+S8N02geDXeuNKg==", + "dev": true + }, + "jscodeshift": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.4.1.tgz", + "integrity": "sha512-iOX6If+hsw0q99V3n31t4f5VlD1TQZddH08xbT65ZqA7T4Vkx68emrDZMUOLVvCEAJ6NpAk7DECe3fjC/t52AQ==", + "dev": true, + "requires": { + "async": "1.5.2", + "babel-plugin-transform-flow-strip-types": "6.22.0", + "babel-preset-es2015": "6.24.1", + "babel-preset-stage-1": "6.24.1", + "babel-register": "6.26.0", + "babylon": "6.18.0", + "colors": "1.2.1", + "flow-parser": "0.69.0", + "lodash": "4.17.4", + "micromatch": "2.3.11", + "node-dir": "0.1.8", + "nomnom": "1.8.1", + "recast": "0.12.9", + "temp": "0.8.3", + "write-file-atomic": "1.3.4" + } + }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "dev": true, + "requires": { + "chalk": "0.4.0", + "underscore": "1.6.0" + } + }, + "recast": { + "version": "0.12.9", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.12.9.tgz", + "integrity": "sha512-y7ANxCWmMW8xLOaiopiRDlyjQ9ajKRENBH+2wjntIbk3A6ZR1+BLQttkmSHMY7Arl+AAZFwJ10grg2T6f1WI8A==", + "dev": true, + "requires": { + "ast-types": "0.10.1", + "core-js": "2.5.3", + "esprima": "4.0.0", + "private": "0.1.8", + "source-map": "0.6.1" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", + "dev": true + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true } } }, - "websocket-driver": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", - "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", - "dev": true, - "requires": { - "http-parser-js": "0.4.9", - "websocket-extensions": "0.1.3" - } - }, - "websocket-extensions": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz", - "integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.19" - } - }, - "whatwg-fetch": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz", - "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=" - }, - "whatwg-url": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.4.0.tgz", - "integrity": "sha512-Z0CVh/YE217Foyb488eo+iBv+r7eAQ0wSTyApi9n06jhcA3z6Nidg/EGvl0UFkg7kMdKxfBzzr+o9JF+cevgMg==", - "dev": true, - "requires": { - "lodash.sortby": "4.7.0", - "tr46": "1.0.1", - "webidl-conversions": "4.0.2" - } - }, - "when": { - "version": "3.7.8", - "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", - "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", + "webpack-cli": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-2.0.13.tgz", + "integrity": "sha512-0lnOi3yla8FsZVuMsbfnNRB/8DlfuDugKdekC+4ykydZG0+UOidMi5J5LLWN4c0VJ8PqC19yMXXkYyCq78OuqA==", "dev": true, - "optional": true - }, - "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "requires": { - "isexe": "2.0.0" - } - }, - "which-module": { + "chalk": "2.3.2", + "cross-spawn": "6.0.5", + "diff": "3.5.0", + "enhanced-resolve": "4.0.0", + "glob-all": "3.1.0", + "global-modules": "1.0.0", + "got": "8.3.0", + "inquirer": "5.2.0", + "interpret": "1.1.0", + "jscodeshift": "0.5.0", + "listr": "0.13.0", + "loader-utils": "1.1.0", + "lodash": "4.17.5", + "log-symbols": "2.2.0", + "mkdirp": "0.5.1", + "p-each-series": "1.0.0", + "p-lazy": "1.0.0", + "prettier": "1.11.1", + "resolve-cwd": "2.0.0", + "supports-color": "5.3.0", + "v8-compile-cache": "1.1.2", + "webpack-addons": "1.1.5", + "yargs": "11.0.0", + "yeoman-environment": "2.0.5", + "yeoman-generator": "2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "cliui": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.0.0.tgz", + "integrity": "sha512-nY3W5Gu2racvdDk//ELReY+dHjb9PlIcVDFXP72nVIhq2Gy3LuVXYwJoPVudwQnv1shtohpgkdCKT2YaKY0CKw==", + "dev": true, + "requires": { + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "1.0.4", + "path-key": "2.0.1", + "semver": "5.5.0", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "enhanced-resolve": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz", + "integrity": "sha512-jox/62b2GofV1qTUQTMPEJSDIGycS43evqYzD/KVtEb9OCoki9cnacUPxCrZa7JfPzZSYOCZhu9O9luaMxAX8g==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "memory-fs": "0.4.1", + "tapable": "1.0.0" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "inquirer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", + "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", + "dev": true, + "requires": { + "ansi-escapes": "3.0.0", + "chalk": "2.3.2", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.1.0", + "figures": "2.0.0", + "lodash": "4.17.5", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rxjs": "5.5.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "loader-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", + "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1" + } + }, + "lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "2.3.2" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + }, + "tapable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz", + "integrity": "sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg==", + "dev": true + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "yargs": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz", + "integrity": "sha512-Rjp+lMYQOWtgqojx1dEWorjCofi1YN7AoFvYV7b1gx/7dAAeuI4kN5SZiEvr0ZmsZTOpDRcCqrpI10L31tFkBw==", + "dev": true, + "requires": { + "cliui": "4.0.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "9.0.2" + } + }, + "yargs-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "dev": true, + "requires": { + "camelcase": "4.1.0" + } + } + } + }, + "webpack-sources": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", + "integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==", + "requires": { + "source-list-map": "2.0.0", + "source-map": "0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "websocket-driver": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "dev": true, + "requires": { + "http-parser-js": "0.4.9", + "websocket-extensions": "0.1.3" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz", + "integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.19" + } + }, + "whatwg-fetch": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz", + "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=" + }, + "whatwg-url": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.4.0.tgz", + "integrity": "sha512-Z0CVh/YE217Foyb488eo+iBv+r7eAQ0wSTyApi9n06jhcA3z6Nidg/EGvl0UFkg7kMdKxfBzzr+o9JF+cevgMg==", + "dev": true, + "requires": { + "lodash.sortby": "4.7.0", + "tr46": "1.0.1", + "webidl-conversions": "4.0.2" + } + }, + "when": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", + "dev": true, + "optional": true + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" @@ -22574,6 +24106,17 @@ "mkdirp": "0.5.1" } }, + "write-file-atomic": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", + "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + }, "write-file-stdout": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/write-file-stdout/-/write-file-stdout-0.0.2.tgz", @@ -22743,6 +24286,282 @@ "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", "dev": true + }, + "yeoman-environment": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.0.5.tgz", + "integrity": "sha512-6/W7/B54OPHJXob0n0+pmkwFsirC8cokuQkPSmT/D0lCcSxkKtg/BA6ZnjUBIwjuGqmw3DTrT4en++htaUju5g==", + "dev": true, + "requires": { + "chalk": "2.3.2", + "debug": "3.1.0", + "diff": "3.3.1", + "escape-string-regexp": "1.0.5", + "globby": "6.1.0", + "grouped-queue": "0.3.3", + "inquirer": "3.3.0", + "is-scoped": "1.0.0", + "lodash": "4.17.4", + "log-symbols": "2.2.0", + "mem-fs": "1.1.3", + "text-table": "0.2.0", + "untildify": "3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "2.3.2" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "yeoman-generator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/yeoman-generator/-/yeoman-generator-2.0.3.tgz", + "integrity": "sha512-mODmrZ26a94djmGZZuIiomSGlN4wULdou29ZwcySupb2e9FdvoCl7Ps2FqHFjEHio3kOl/iBeaNqrnx3C3NwWg==", + "dev": true, + "requires": { + "async": "2.6.0", + "chalk": "2.3.2", + "cli-table": "0.3.1", + "cross-spawn": "5.1.0", + "dargs": "5.1.0", + "dateformat": "3.0.3", + "debug": "3.1.0", + "detect-conflict": "1.0.1", + "error": "7.0.2", + "find-up": "2.1.0", + "github-username": "4.1.0", + "istextorbinary": "2.2.1", + "lodash": "4.17.4", + "make-dir": "1.2.0", + "mem-fs-editor": "3.0.2", + "minimist": "1.2.0", + "pretty-bytes": "4.0.2", + "read-chunk": "2.1.0", + "read-pkg-up": "3.0.0", + "rimraf": "2.6.2", + "run-async": "2.3.0", + "shelljs": "0.8.1", + "text-table": "0.2.0", + "through2": "2.0.3", + "yeoman-environment": "2.0.5" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "binaryextensions": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.1.tgz", + "integrity": "sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA==", + "dev": true + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "istextorbinary": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz", + "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==", + "dev": true, + "requires": { + "binaryextensions": "2.1.1", + "editions": "1.3.4", + "textextensions": "2.2.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "4.0.0", + "pify": "3.0.0", + "strip-bom": "3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "1.3.1", + "json-parse-better-errors": "1.0.2" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "3.0.0" + } + }, + "pretty-bytes": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz", + "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "4.0.0", + "normalize-package-data": "2.4.0", + "path-type": "3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + }, + "textextensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.2.0.tgz", + "integrity": "sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA==", + "dev": true + } + } } } } From 2997067ca04a7a8853875d24d0efe25451600c2c Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 13:48:46 -0700 Subject: [PATCH 149/246] ci - e2e+screens - use shell-parallel to run ganache --- package-lock.json | 214 +++++++++++++++++++++++++++++++++++++++++++--- package.json | 8 +- 2 files changed, 205 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f4f02f79..8baaf00a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4341,6 +4341,36 @@ "escope": "3.6.0", "through2": "2.0.3", "yargs": "6.6.0" + }, + "dependencies": { + "yargs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", + "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "4.2.1" + } + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "requires": { + "camelcase": "3.0.0" + } + } } }, "des.js": { @@ -19883,6 +19913,16 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, + "shell-parallel": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shell-parallel/-/shell-parallel-1.0.2.tgz", + "integrity": "sha512-GTAfqAiy37hu+H5Wd4Pz0LfjY0qs/xfLNMxAuCZAuSAVHHj+eGB8QgiC0oNWurhsG/KGliIA4GsLVP2NWoi/bA==", + "dev": true, + "requires": { + "once": "1.4.0", + "yargs": "11.0.0" + } + }, "shell-quote": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", @@ -23551,6 +23591,58 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + }, + "yargs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", + "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "4.2.1" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + } + } + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "requires": { + "camelcase": "3.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + } + } } } }, @@ -24236,31 +24328,125 @@ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" }, "yargs": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", - "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz", + "integrity": "sha512-Rjp+lMYQOWtgqojx1dEWorjCofi1YN7AoFvYV7b1gx/7dAAeuI4kN5SZiEvr0ZmsZTOpDRcCqrpI10L31tFkBw==", + "dev": true, "requires": { - "camelcase": "3.0.0", - "cliui": "3.2.0", + "cliui": "4.0.0", "decamelize": "1.2.0", + "find-up": "2.1.0", "get-caller-file": "1.0.2", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", + "os-locale": "2.1.0", "require-directory": "2.1.1", "require-main-filename": "1.0.1", "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", "y18n": "3.2.1", - "yargs-parser": "4.2.1" + "yargs-parser": "9.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "cliui": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.0.0.tgz", + "integrity": "sha512-nY3W5Gu2racvdDk//ELReY+dHjb9PlIcVDFXP72nVIhq2Gy3LuVXYwJoPVudwQnv1shtohpgkdCKT2YaKY0CKw==", + "dev": true, + "requires": { + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + } } }, "yargs-parser": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", - "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "dev": true, "requires": { - "camelcase": "3.0.0" + "camelcase": "4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } } }, "yauzl": { diff --git a/package.json b/package.json index 4e618f563..6bb934eec 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,10 @@ "test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js", "test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara", "test:integration:build": "gulp build:scss", - "test:e2e": "cross-env METAMASK_ENV=test mocha test/e2e/metamask.spec --recursive", - "test:screens": "cross-env METAMASK_ENV=test npm run ganache:start & mocha test/screens/new.spec --recursive || kill $!", + "test:e2e": "shell-parallel -s 'npm run ganache:start' -x 'npm run test:e2e:run'", + "test:e2e:run": "mocha test/e2e/metamask.spec --recursive", + "test:screens": "shell-parallel -s 'npm run ganache:start' -x 'npm run test:screens:run'", + "test:screens:run": "mocha test/screens/new.spec --recursive", "test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload", "test:coveralls-upload": "if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi", "test:flat": "npm run test:flat:build && karma start test/flat.conf.js", @@ -144,7 +146,6 @@ "number-to-bn": "^1.7.0", "obj-multiplex": "^1.0.0", "obs-store": "^3.0.0", - "once": "^1.3.3", "percentile": "^1.2.0", "pify": "^3.0.0", "ping-pong-stream": "^1.0.0", @@ -267,6 +268,7 @@ "redux-test-utils": "^0.2.2", "rimraf": "^2.6.2", "selenium-webdriver": "^3.5.0", + "shell-parallel": "^1.0.2", "sinon": "^5.0.0", "stylelint-config-standard": "^18.2.0", "tape": "^4.5.1", From a9391ea2eff65be7f70d3d83d185750759b01528 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 13:50:19 -0700 Subject: [PATCH 150/246] ci - e2e+screens - add sleep to make sure ganache is ready --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6bb934eec..2a8c122e1 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,9 @@ "test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js", "test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara", "test:integration:build": "gulp build:scss", - "test:e2e": "shell-parallel -s 'npm run ganache:start' -x 'npm run test:e2e:run'", + "test:e2e": "shell-parallel -s 'npm run ganache:start' -x 'sleep 3 && npm run test:e2e:run'", "test:e2e:run": "mocha test/e2e/metamask.spec --recursive", - "test:screens": "shell-parallel -s 'npm run ganache:start' -x 'npm run test:screens:run'", + "test:screens": "shell-parallel -s 'npm run ganache:start' -x 'sleep 3 && npm run test:screens:run'", "test:screens:run": "mocha test/screens/new.spec --recursive", "test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload", "test:coveralls-upload": "if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi", From 32bb09bcb9dd5f9db86967128f7d0fe154fe9922 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 13:52:42 -0700 Subject: [PATCH 151/246] test - e2e - set network to localhost --- test/e2e/metamask.spec.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index ff5bdb51b..20e23e2ea 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -38,6 +38,8 @@ describe('Metamask popup page', function () { const tabs = await driver.getAllWindowHandles() await driver.switchTo().window(tabs[0]) await delay(300) + await setProviderType('localhost') + await delay(300) }) it('should match title', async () => { @@ -124,6 +126,10 @@ describe('Metamask popup page', function () { }) }) + async function setProviderType(type) { + await driver.executeScript('window.metamask.setProviderType(arguments[0])', type) + } + async function verboseReportOnFailure(test) { const artifactDir = `./test-artifacts/${test.title}` const filepathBase = `${artifactDir}/test-failure` From d05a2ca96895195e30c0987bf042c079b4caeadf Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 14:39:43 -0700 Subject: [PATCH 152/246] development - screens - screenshot on failure --- test/screens/new.spec.js | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/test/screens/new.spec.js b/test/screens/new.spec.js index 2af891060..71b3c53ac 100644 --- a/test/screens/new.spec.js +++ b/test/screens/new.spec.js @@ -12,7 +12,17 @@ const By = webdriver.By const { delay, buildWebDriver } = require('./func') const localesIndex = require('../../app/_locales/index.json') -captureAllScreens().catch(console.error) +let driver + +captureAllScreens().catch((err) => { + try { + verboseReportOnFailure() + console.error(err) + driver.quit() + } finally { + process.exit(1) + } +}) async function captureAllScreens() { let screenshotCount = 0 @@ -26,7 +36,7 @@ async function captureAllScreens() { // setup selenium and install extension const extPath = path.resolve('dist/chrome') - const driver = buildWebDriver(extPath) + driver = buildWebDriver(extPath) await driver.get('chrome://extensions-frame') const elems = await driver.findElements(By.css('.extension-list-item-wrapper')) const extensionId = await elems[1].getAttribute('id') @@ -34,7 +44,7 @@ async function captureAllScreens() { await delay(500) tabs = await driver.getAllWindowHandles() await driver.switchTo().window(tabs[0]) - await delay(300) + await delay(500) await setProviderType('localhost') // click try new ui @@ -43,7 +53,6 @@ async function captureAllScreens() { // close metamask homepage and extra home.html tabs = await driver.getAllWindowHandles() - console.log(tabs) // metamask homepage is opened on prod, not dev if (tabs.length > 2) { await driver.switchTo().window(tabs[2]) @@ -204,4 +213,16 @@ async function captureAllScreens() { await pify(endOfStream)(stream) } + async function verboseReportOnFailure(test) { + const artifactDir = `./test-artifacts/${test.title}` + const filepathBase = `${artifactDir}/test-failure` + await pify(mkdirp)(artifactDir) + // capture screenshot + const screenshot = await driver.takeScreenshot() + await pify(fs.writeFile)(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' }) + // capture dom source + const htmlSource = await driver.getPageSource() + await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource) + } + } From 7a406d51c375247242d8b3c752bd1f9341215430 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 14:48:41 -0700 Subject: [PATCH 153/246] development - screens - fix screenshot on failure --- test/screens/new.spec.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/screens/new.spec.js b/test/screens/new.spec.js index 71b3c53ac..43490226b 100644 --- a/test/screens/new.spec.js +++ b/test/screens/new.spec.js @@ -16,12 +16,13 @@ let driver captureAllScreens().catch((err) => { try { - verboseReportOnFailure() console.error(err) + verboseReportOnFailure() driver.quit() - } finally { - process.exit(1) + } catch (err) { + console.error(err) } + process.exit(1) }) async function captureAllScreens() { From a3f7cd1cfc38308983b81a60b9c6e7e325d1acfb Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 15:03:49 -0700 Subject: [PATCH 154/246] development - ci-screens - remove mocha wrapper that was losing exit code --- package.json | 2 +- test/screens/{new.spec.js => new-ui.js} | 22 ++--- test/screens/old.spec.js | 105 ------------------------ 3 files changed, 12 insertions(+), 117 deletions(-) rename test/screens/{new.spec.js => new-ui.js} (93%) delete mode 100644 test/screens/old.spec.js diff --git a/package.json b/package.json index 51f481b36..72abebba0 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "test:e2e": "shell-parallel -s 'npm run ganache:start' -x 'sleep 3 && npm run test:e2e:run'", "test:e2e:run": "mocha test/e2e/metamask.spec --recursive", "test:screens": "shell-parallel -s 'npm run ganache:start' -x 'sleep 3 && npm run test:screens:run'", - "test:screens:run": "mocha test/screens/new.spec --recursive", + "test:screens:run": "node test/screens/new-ui.js", "test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload", "test:coveralls-upload": "if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi", "test:flat": "npm run test:flat:build && karma start test/flat.conf.js", diff --git a/test/screens/new.spec.js b/test/screens/new-ui.js similarity index 93% rename from test/screens/new.spec.js rename to test/screens/new-ui.js index 43490226b..b23260a7c 100644 --- a/test/screens/new.spec.js +++ b/test/screens/new-ui.js @@ -214,16 +214,16 @@ async function captureAllScreens() { await pify(endOfStream)(stream) } - async function verboseReportOnFailure(test) { - const artifactDir = `./test-artifacts/${test.title}` - const filepathBase = `${artifactDir}/test-failure` - await pify(mkdirp)(artifactDir) - // capture screenshot - const screenshot = await driver.takeScreenshot() - await pify(fs.writeFile)(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' }) - // capture dom source - const htmlSource = await driver.getPageSource() - await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource) - } +} +async function verboseReportOnFailure(test) { + const artifactDir = `./test-artifacts/${test.title}` + const filepathBase = `${artifactDir}/test-failure` + await pify(mkdirp)(artifactDir) + // capture screenshot + const screenshot = await driver.takeScreenshot() + await pify(fs.writeFile)(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' }) + // capture dom source + const htmlSource = await driver.getPageSource() + await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource) } diff --git a/test/screens/old.spec.js b/test/screens/old.spec.js deleted file mode 100644 index 87399d4b5..000000000 --- a/test/screens/old.spec.js +++ /dev/null @@ -1,105 +0,0 @@ -const path = require('path') -const fs = require('fs') -const pify = require('pify') -const mkdirp = require('mkdirp') -const webdriver = require('selenium-webdriver') -const By = webdriver.By -const { delay, buildWebDriver } = require('./func') - -captureAllScreens().catch(console.error) - -async function captureAllScreens() { - // setup selenium and install extension - const extPath = path.resolve('dist/chrome') - const driver = buildWebDriver(extPath) - await driver.get('chrome://extensions-frame') - const elems = await driver.findElements(By.css('.extension-list-item-wrapper')) - const extensionId = await elems[1].getAttribute('id') - await driver.get(`chrome-extension://${extensionId}/popup.html`) - await delay(500) - const tabs = await driver.getAllWindowHandles() - await driver.switchTo().window(tabs[0]) - await delay(300) - - // common names - let button - - await captureScreenShot('privacy') - - const privacy = await driver.findElement(By.css('.terms-header')).getText() - driver.findElement(By.css('button')).click() - await delay(300) - await captureScreenShot('terms') - - await delay(300) - const terms = await driver.findElement(By.css('.terms-header')).getText() - await delay(300) - const element = driver.findElement(By.linkText('Attributions')) - await driver.executeScript('arguments[0].scrollIntoView(true)', element) - await delay(300) - button = await driver.findElement(By.css('button')) - const buttonEnabled = await button.isEnabled() - await delay(500) - await captureScreenShot('terms-scrolled') - - await button.click() - await delay(300) - await captureScreenShot('choose-password') - - const passwordBox = await driver.findElement(By.id('password-box')) - const passwordBoxConfirm = await driver.findElement(By.id('password-box-confirm')) - button = driver.findElement(By.css('button')) - passwordBox.sendKeys('123456789') - passwordBoxConfirm.sendKeys('123456789') - await delay(500) - await captureScreenShot('choose-password-filled') - - await button.click() - await delay(700) - this.seedPhase = await driver.findElement(By.css('.twelve-word-phrase')).getText() - await captureScreenShot('seed phrase') - - const continueAfterSeedPhrase = await driver.findElement(By.css('button')) - await continueAfterSeedPhrase.click() - await delay(300) - await captureScreenShot('main screen') - - await driver.findElement(By.css('.sandwich-expando')).click() - await delay(500) - await captureScreenShot('menu') - - // await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)')).click() - // await captureScreenShot('main screen') - // it('should accept account password after lock', async () => { - // await delay(500) - // await driver.findElement(By.id('password-box')).sendKeys('123456789') - // await driver.findElement(By.css('button')).click() - // await delay(500) - // }) - // - // it('should show QR code option', async () => { - // await delay(300) - // await driver.findElement(By.css('.fa-ellipsis-h')).click() - // await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div:nth-child(1) > flex-column > div.name-label > div > span > i > div > div > li:nth-child(3)')).click() - // await delay(300) - // }) - // - // it('should show the account address', async () => { - // this.accountAddress = await driver.findElement(By.css('.ellip-address')).getText() - // await driver.findElement(By.css('.fa-arrow-left')).click() - // await delay(500) - // }) - - // cleanup - await driver.quit() - - async function captureScreenShot(label) { - const artifactDir = `./test-artifacts/${label}` - const filepathBase = `${artifactDir}` - await pify(mkdirp)(artifactDir) - // capture screenshot - const screenshot = await driver.takeScreenshot() - await pify(fs.writeFile)(`${filepathBase}/screenshot.png`, screenshot, { encoding: 'base64' }) - } - -} From 80839eebe4ac720855ab5fadd70da6e59bae3c91 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 15:09:25 -0700 Subject: [PATCH 155/246] build - properly set GULP_METAMASK_DEBUG on dev --- gulpfile.js | 11 +++++------ package.json | 1 - 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 3ca0c65de..1eb0a974b 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -16,7 +16,6 @@ const eslint = require('gulp-eslint') const fs = require('fs') const path = require('path') const manifest = require('./app/manifest.json') -const gulpif = require('gulp-if') const replace = require('gulp-replace') const mkdirp = require('mkdirp') const asyncEach = require('async/each') @@ -31,8 +30,6 @@ const debug = require('gulp-debug') const pify = require('pify') const endOfStream = pify(require('end-of-stream')) -const disableDebugTools = gutil.env.disableDebugTools -const debugMode = gutil.env.debug const browserPlatforms = [ 'firefox', @@ -181,12 +178,12 @@ gulp.task('manifest:production', function() { ],{base: './dist/'}) // Exclude chromereload script in production: - .pipe(gulpif(!debugMode,jsoneditor(function(json) { + .pipe(jsoneditor(function(json) { json.background.scripts = json.background.scripts.filter((script) => { return !script.includes('chromereload') }) return json - }))) + })) .pipe(gulp.dest('./dist/', { overwrite: true })) }) @@ -311,6 +308,7 @@ function createTasksForBuildJsExtension({ buildJsFiles, taskPrefix, devMode, bun minifyBuild: !devMode, buildWithFullPaths: devMode, watch: devMode, + devMode, }, bundleTaskOpts) createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1, buildPhase2 }) } @@ -326,6 +324,7 @@ function createTasksForBuildJsMascara({ taskPrefix, devMode, bundleTaskOpts = {} minifyBuild: !devMode, buildWithFullPaths: devMode, watch: devMode, + devMode, }, bundleTaskOpts) createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1 }) } @@ -541,7 +540,7 @@ function bundleTask(opts) { // convert bundle stream to gulp vinyl stream .pipe(source(opts.filename)) // inject variables into bundle - .pipe(replace('\'GULP_METAMASK_DEBUG\'', debugMode)) + .pipe(replace('\'GULP_METAMASK_DEBUG\'', opts.devMode)) // buffer file contents (?) .pipe(buffer()) diff --git a/package.json b/package.json index a852395b3..24796b083 100644 --- a/package.json +++ b/package.json @@ -221,7 +221,6 @@ "gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed", "gulp-babel": "^7.0.0", "gulp-eslint": "^4.0.0", - "gulp-if": "^2.0.2", "gulp-json-editor": "^2.2.1", "gulp-livereload": "^3.8.1", "gulp-replace": "^0.6.1", From 5ec4286966d5e7087b2f9943bf0432c07497e85f Mon Sep 17 00:00:00 2001 From: frankiebee Date: Fri, 30 Mar 2018 15:24:32 -0700 Subject: [PATCH 156/246] deps - bump proviedr-engine --- package-lock.json | 24 ++++++++++++------------ package.json | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 504f2f1d3..18d49971e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5747,7 +5747,7 @@ "ethereumjs-vm": "2.3.2", "through2": "2.0.3", "treeify": "1.1.0", - "web3-provider-engine": "13.6.0" + "web3-provider-engine": "13.8.0" } }, "ethereum-common": { @@ -19306,9 +19306,9 @@ } }, "solc": { - "version": "0.4.20", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.20.tgz", - "integrity": "sha512-LrP3Jp4FS3y8sduIR67y8Ss1riR3fggk5sMnx4OSCcU88Ro0e51+KVXyfH3NP6ghLo7COrLx/lGUaDDugCzdgA==", + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.21.tgz", + "integrity": "sha512-8lJmimVjOG9AJOQRWS2ph4rSctPMsPGZ4H360HLs5iI+euUlt7iAvUxSLeFZZzwk0kas4Qta7HmlMXNU3yYwhw==", "requires": { "fs-extra": "0.30.0", "memorystream": "0.3.1", @@ -22309,9 +22309,9 @@ } }, "web3-provider-engine": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-13.6.0.tgz", - "integrity": "sha512-iCsAlAeLWHxgx6EXuBm5GNg5VBqKtzmnrhEOfJBv8Cetukush7yOvo4RPjDZIynKxg9jfAlMmWqCk6wLxA6coQ==", + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz", + "integrity": "sha512-fZXhX5VWwWpoFfrfocslyg6P7cN3YWPG/ASaevNfeO80R+nzgoPUBXcWQekSGSsNDkeRTis4aMmpmofYf1TNtQ==", "requires": { "async": "2.6.0", "clone": "2.1.1", @@ -22319,7 +22319,7 @@ "eth-sig-util": "1.4.2", "ethereumjs-block": "1.7.0", "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "5.1.4", + "ethereumjs-util": "5.1.5", "ethereumjs-vm": "2.3.2", "fetch-ponyfill": "4.1.0", "json-rpc-error": "2.0.0", @@ -22328,16 +22328,16 @@ "readable-stream": "2.3.3", "request": "2.83.0", "semaphore": "1.1.0", - "solc": "0.4.20", + "solc": "0.4.21", "tape": "4.8.0", "xhr": "2.4.1", "xtend": "4.0.1" }, "dependencies": { "ethereumjs-util": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.4.tgz", - "integrity": "sha512-wbeTc5prEzIWFSQUcEsCAZbqubtJKy6yS+oZMY1cGG6GLYzLjm4YhC2RNrWIg8hRYnclWpnZmx2zkiufQkmd3w==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.5.tgz", + "integrity": "sha512-xPaSEATYJpMTCGowIt0oMZwFP4R1bxd6QsWgkcDvFL0JtXsr39p32WEcD14RscCjfP41YXZPCVWA4yAg0nrJmw==", "requires": { "bn.js": "4.11.8", "create-hash": "1.1.3", diff --git a/package.json b/package.json index a852395b3..cce7e31e0 100644 --- a/package.json +++ b/package.json @@ -185,7 +185,7 @@ "valid-url": "^1.0.9", "vreme": "^3.0.2", "web3": "^0.20.1", - "web3-provider-engine": "^13.5.6", + "web3-provider-engine": "^13.8.0", "web3-stream-provider": "^3.0.1", "xtend": "^4.0.1" }, From 86c768dfb098e5e0166ec3a007871597476d6cf2 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 15:36:22 -0700 Subject: [PATCH 157/246] ci - build:announce - rewrite github comment to include walkthrough gif --- .circleci/config.yml | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 737fc3398..5512bf4c9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -114,16 +114,30 @@ jobs: command: | CIRCLE_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}" SHORT_SHA1=$(echo $CIRCLE_SHA1 | cut -c 1-7) - BUILD_LINK_BASE="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0/builds" + BUILD_LINK_BASE="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0" VERSION=$(node -p 'require("./dist/chrome/manifest.json").version') - MASCARA="$BUILD_LINK_BASE/mascara/home.html" - CHROME="$BUILD_LINK_BASE/metamask-chrome-$VERSION.zip" - FIREFOX="$BUILD_LINK_BASE/metamask-firefox-$VERSION.zip" - OPERA="$BUILD_LINK_BASE/metamask-opera-$VERSION.zip" - EDGE="$BUILD_LINK_BASE/metamask-edge-$VERSION.zip" - COMMENT_MAIN="Builds ready [$SHORT_SHA1]: [mascara][mascara], [chrome][chrome], [firefox][firefox], [edge][edge], [opera][opera]" - COMMENT_LINKS="[mascara]:$MASCARA\n[chrome]:$CHROME\n[firefox]:$FIREFOX\n[opera]:$OPERA\n[edge]:$EDGE\n" - COMMENT_BODY="$COMMENT_MAIN\n\n$COMMENT_LINKS" + + MASCARA="$BUILD_LINK_BASE/builds/mascara/home.html" + CHROME="$BUILD_LINK_BASE/builds/metamask-chrome-$VERSION.zip" + FIREFOX="$BUILD_LINK_BASE/builds/metamask-firefox-$VERSION.zip" + EDGE="$BUILD_LINK_BASE/builds/metamask-edge-$VERSION.zip" + OPERA="$BUILD_LINK_BASE/builds/metamask-opera-$VERSION.zip" + WALKTHROUGH="$BUILD_LINK_BASE/test-artifacts/screens/walkthrough%20%28en%29.gif" + + read -d '' COMMENT_BODY < + + Builds ready [$SHORT_SHA1]: + mascara, + chrome, + firefox, + edge, + opera + + + + EOF + JSON_PAYLOAD="{\"body\":\"$COMMENT_BODY\"}" POST_COMMENT_URI="https://api.github.com/repos/metamask/metamask-extension/issues/$CIRCLE_PR_NUMBER/comments" echo "Announcement:\n$COMMENT_BODY" From 03b123a85d2ce693980b83eef7adb8939737bff8 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Fri, 30 Mar 2018 15:25:13 -0700 Subject: [PATCH 158/246] transactions - put the origing on the txMeta to help with debugging --- app/scripts/controllers/transactions.js | 4 +++- app/scripts/metamask-controller.js | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 7e2cc15da..458bf912b 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -161,9 +161,11 @@ module.exports = class TransactionController extends EventEmitter { this.emit(`${txMeta.id}:unapproved`, txMeta) } - async newUnapprovedTransaction (txParams) { + async newUnapprovedTransaction (txParams, opts = {origin: 'metamask'}) { log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`) const initialTxMeta = await this.addUnapprovedTransaction(txParams) + initialTxMeta.origin = opts.origin + this.txStateManager.updateTx(initialTxMeta, '#newUnapprovedTransaction - adding the origin') // listen for tx completion (success, fail) return new Promise((resolve, reject) => { this.txStateManager.once(`${initialTxMeta.id}:finished`, (finishedTxMeta) => { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 4422a5cf3..b96acc9da 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -57,7 +57,6 @@ module.exports = class MetamaskController extends EventEmitter { this.defaultMaxListeners = 20 this.sendUpdate = debounce(this.privateSendUpdate.bind(this), 200) - this.opts = opts const initState = opts.initState || {} this.recordFirstTimeInfo(initState) @@ -242,6 +241,11 @@ module.exports = class MetamaskController extends EventEmitter { static: { eth_syncing: false, web3_clientVersion: `MetaMask/v${version}`, + eth_sendTransaction: (payload, next, end) => { + const origin = payload.origin + const txParams = payload.params[0] + nodeify(this.txController.newUnapprovedTransaction, this.txController)(txParams, { origin }, end) + }, }, // account mgmt getAccounts: (cb) => { @@ -256,7 +260,6 @@ module.exports = class MetamaskController extends EventEmitter { cb(null, result) }, // tx signing - processTransaction: nodeify(async (txParams) => await this.txController.newUnapprovedTransaction(txParams), this), // old style msg signing processMessage: this.newUnsignedMessage.bind(this), // personal_sign msg signing From 213496f19008f922300b21cd04a48b09bd021173 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 15:53:45 -0700 Subject: [PATCH 159/246] ci - build:announce - break out into shell script --- .circleci/config.yml | 33 +--------------------- development/metamaskbot-build-announce.sh | 34 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 32 deletions(-) create mode 100755 development/metamaskbot-build-announce.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 5512bf4c9..2ba5b8e12 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -111,38 +111,7 @@ jobs: destination: builds - run: name: build:announce - command: | - CIRCLE_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}" - SHORT_SHA1=$(echo $CIRCLE_SHA1 | cut -c 1-7) - BUILD_LINK_BASE="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0" - VERSION=$(node -p 'require("./dist/chrome/manifest.json").version') - - MASCARA="$BUILD_LINK_BASE/builds/mascara/home.html" - CHROME="$BUILD_LINK_BASE/builds/metamask-chrome-$VERSION.zip" - FIREFOX="$BUILD_LINK_BASE/builds/metamask-firefox-$VERSION.zip" - EDGE="$BUILD_LINK_BASE/builds/metamask-edge-$VERSION.zip" - OPERA="$BUILD_LINK_BASE/builds/metamask-opera-$VERSION.zip" - WALKTHROUGH="$BUILD_LINK_BASE/test-artifacts/screens/walkthrough%20%28en%29.gif" - - read -d '' COMMENT_BODY < - - Builds ready [$SHORT_SHA1]: - mascara, - chrome, - firefox, - edge, - opera - - - - EOF - - JSON_PAYLOAD="{\"body\":\"$COMMENT_BODY\"}" - POST_COMMENT_URI="https://api.github.com/repos/metamask/metamask-extension/issues/$CIRCLE_PR_NUMBER/comments" - echo "Announcement:\n$COMMENT_BODY" - echo "Posting to $POST_COMMENT_URI" - curl -d "$JSON_PAYLOAD" -H "Authorization: token $GITHUB_COMMENT_TOKEN" $POST_COMMENT_URI + command: ./development/metamaskbot-build-announce prep-scss: docker: diff --git a/development/metamaskbot-build-announce.sh b/development/metamaskbot-build-announce.sh new file mode 100755 index 000000000..7b244addd --- /dev/null +++ b/development/metamaskbot-build-announce.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +CIRCLE_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}" +SHORT_SHA1=$(echo $CIRCLE_SHA1 | cut -c 1-7) +BUILD_LINK_BASE="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0" +VERSION=$(node -p 'require("./dist/chrome/manifest.json").version') + +MASCARA="$BUILD_LINK_BASE/builds/mascara/home.html" +CHROME="$BUILD_LINK_BASE/builds/metamask-chrome-$VERSION.zip" +FIREFOX="$BUILD_LINK_BASE/builds/metamask-firefox-$VERSION.zip" +EDGE="$BUILD_LINK_BASE/builds/metamask-edge-$VERSION.zip" +OPERA="$BUILD_LINK_BASE/builds/metamask-opera-$VERSION.zip" +WALKTHROUGH="$BUILD_LINK_BASE/test-artifacts/screens/walkthrough%20%28en%29.gif" + +read -d '' COMMENT_BODY < + + Builds ready [$SHORT_SHA1]: + mascara, + chrome, + firefox, + edge, + opera + + + +EOF + +JSON_PAYLOAD="{\"body\":\"$COMMENT_BODY\"}" +POST_COMMENT_URI="https://api.github.com/repos/metamask/metamask-extension/issues/$CIRCLE_PR_NUMBER/comments" +echo "Announcement:" +echo "$COMMENT_BODY" +echo "Posting to $POST_COMMENT_URI" +curl -d "$JSON_PAYLOAD" -H "Authorization: token $GITHUB_COMMENT_TOKEN" $POST_COMMENT_URI From 3def45004a0024c4f48b06618f73f19ffa4ffd6b Mon Sep 17 00:00:00 2001 From: frankiebee Date: Fri, 30 Mar 2018 16:00:11 -0700 Subject: [PATCH 160/246] transactions#newUnapprovedTransaction - dont default origin to metamask --- app/scripts/controllers/transactions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 458bf912b..a18a2d2e2 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -161,7 +161,7 @@ module.exports = class TransactionController extends EventEmitter { this.emit(`${txMeta.id}:unapproved`, txMeta) } - async newUnapprovedTransaction (txParams, opts = {origin: 'metamask'}) { + async newUnapprovedTransaction (txParams, opts = {}) { log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`) const initialTxMeta = await this.addUnapprovedTransaction(txParams) initialTxMeta.origin = opts.origin From f13733c79059a8ee928c92c1e5c1abe206e303ef Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 16:03:54 -0700 Subject: [PATCH 161/246] ci - build:announce - fix shell script path --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2ba5b8e12..3c41c5054 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -111,7 +111,7 @@ jobs: destination: builds - run: name: build:announce - command: ./development/metamaskbot-build-announce + command: ./development/metamaskbot-build-announce.sh prep-scss: docker: From f5cf39b94069db4c017158c080a8ac2d89aef4cb Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 16:12:13 -0700 Subject: [PATCH 162/246] ci - build:announce - fix json escaping --- development/metamaskbot-build-announce.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/development/metamaskbot-build-announce.sh b/development/metamaskbot-build-announce.sh index 7b244addd..ee7c570bf 100755 --- a/development/metamaskbot-build-announce.sh +++ b/development/metamaskbot-build-announce.sh @@ -16,13 +16,13 @@ read -d '' COMMENT_BODY < Builds ready [$SHORT_SHA1]: - mascara, - chrome, - firefox, - edge, - opera + mascara, + chrome, + firefox, + edge, + opera - + EOF From 662b1957f46ec105d60993b2a681cea634f8076c Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 16:25:22 -0700 Subject: [PATCH 163/246] ci - build:announce - fix json escaping --- development/metamaskbot-build-announce.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/development/metamaskbot-build-announce.sh b/development/metamaskbot-build-announce.sh index ee7c570bf..52dd24c93 100755 --- a/development/metamaskbot-build-announce.sh +++ b/development/metamaskbot-build-announce.sh @@ -16,13 +16,13 @@ read -d '' COMMENT_BODY < Builds ready [$SHORT_SHA1]: - mascara, - chrome, - firefox, - edge, - opera + mascara, + chrome, + firefox, + edge, + opera - + EOF From bc1a456264266191742db829989be27ee569df34 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 17:20:48 -0700 Subject: [PATCH 164/246] ci - build:announce - replace bash qith js because of string escaping nightmare --- development/metamaskbot-build-announce.js | 52 +++++++++++++++++++++++ development/metamaskbot-build-announce.sh | 34 --------------- 2 files changed, 52 insertions(+), 34 deletions(-) create mode 100755 development/metamaskbot-build-announce.js delete mode 100755 development/metamaskbot-build-announce.sh diff --git a/development/metamaskbot-build-announce.js b/development/metamaskbot-build-announce.js new file mode 100755 index 000000000..e867d797e --- /dev/null +++ b/development/metamaskbot-build-announce.js @@ -0,0 +1,52 @@ +#!/usr/bin/env node +const request = require('request-promise') +const { version } = require('../dist/chrome/manifest.json') + +const GITHUB_COMMENT_TOKEN = process.env.GITHUB_COMMENT_TOKEN +console.log('GITHUB_COMMENT_TOKEN', GITHUB_COMMENT_TOKEN) +const CIRCLE_PULL_REQUEST = process.env.CIRCLE_PULL_REQUEST +console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST) +const CIRCLE_SHA1 = process.env.CIRCLE_SHA1 +console.log('CIRCLE_SHA1', CIRCLE_SHA1) +const CIRCLE_BUILD_NUM = process.env.CIRCLE_BUILD_NUM +console.log('CIRCLE_BUILD_NUM', CIRCLE_BUILD_NUM) + +const CIRCLE_PR_NUMBER = CIRCLE_PULL_REQUEST.split('/').pop() +const SHORT_SHA1 = CIRCLE_SHA1.slice(0,7) +const BUILD_LINK_BASE = `https://${CIRCLE_BUILD_NUM}-42009758-gh.circle-artifacts.com/0` + +const MASCARA = `${BUILD_LINK_BASE}/builds/mascara/home.html` +const CHROME = `${BUILD_LINK_BASE}/builds/metamask-chrome-${version}.zip` +const FIREFOX = `${BUILD_LINK_BASE}/builds/metamask-firefox-${version}.zip` +const EDGE = `${BUILD_LINK_BASE}/builds/metamask-edge-${version}.zip` +const OPERA = `${BUILD_LINK_BASE}/builds/metamask-opera-${version}.zip` +const WALKTHROUGH = `${BUILD_LINK_BASE}/test-artifacts/screens/walkthrough%20%28en%29.gif` + +const commentBody = ` +
+ + Builds ready [${SHORT_SHA1}]: + mascara, + chrome, + firefox, + edge, + opera + + +
+` + +const JSON_PAYLOAD = JSON.stringify({ body: commentBody }) +const POST_COMMENT_URI = `https://api.github.com/repos/metamask/metamask-extension/issues/${CIRCLE_PR_NUMBER}/comments` +console.log(`Announcement:\n${commentBody}`) +console.log(`Posting to: ${POST_COMMENT_URI}`) + +request({ + method: 'POST', + uri: POST_COMMENT_URI, + body: JSON_PAYLOAD, + headers: { + 'User-Agent': 'metamaskbot', + 'Authorization': `token ${GITHUB_COMMENT_TOKEN}`, + }, +}) diff --git a/development/metamaskbot-build-announce.sh b/development/metamaskbot-build-announce.sh deleted file mode 100755 index 52dd24c93..000000000 --- a/development/metamaskbot-build-announce.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -CIRCLE_PR_NUMBER="${CIRCLE_PR_NUMBER:-${CIRCLE_PULL_REQUEST##*/}}" -SHORT_SHA1=$(echo $CIRCLE_SHA1 | cut -c 1-7) -BUILD_LINK_BASE="https://$CIRCLE_BUILD_NUM-42009758-gh.circle-artifacts.com/0" -VERSION=$(node -p 'require("./dist/chrome/manifest.json").version') - -MASCARA="$BUILD_LINK_BASE/builds/mascara/home.html" -CHROME="$BUILD_LINK_BASE/builds/metamask-chrome-$VERSION.zip" -FIREFOX="$BUILD_LINK_BASE/builds/metamask-firefox-$VERSION.zip" -EDGE="$BUILD_LINK_BASE/builds/metamask-edge-$VERSION.zip" -OPERA="$BUILD_LINK_BASE/builds/metamask-opera-$VERSION.zip" -WALKTHROUGH="$BUILD_LINK_BASE/test-artifacts/screens/walkthrough%20%28en%29.gif" - -read -d '' COMMENT_BODY < - - Builds ready [$SHORT_SHA1]: - mascara, - chrome, - firefox, - edge, - opera - - - -EOF - -JSON_PAYLOAD="{\"body\":\"$COMMENT_BODY\"}" -POST_COMMENT_URI="https://api.github.com/repos/metamask/metamask-extension/issues/$CIRCLE_PR_NUMBER/comments" -echo "Announcement:" -echo "$COMMENT_BODY" -echo "Posting to $POST_COMMENT_URI" -curl -d "$JSON_PAYLOAD" -H "Authorization: token $GITHUB_COMMENT_TOKEN" $POST_COMMENT_URI From 6d6fc7df1ccb02f53ca9920da8e08a20a2f868c7 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 17:27:33 -0700 Subject: [PATCH 165/246] ci - build:announce - fix script path --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3c41c5054..b0bd97ef0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -111,7 +111,7 @@ jobs: destination: builds - run: name: build:announce - command: ./development/metamaskbot-build-announce.sh + command: ./development/metamaskbot-build-announce.js prep-scss: docker: From 69ff600c747c588cfe2c6792367e091b7f648d8d Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 17:36:43 -0700 Subject: [PATCH 166/246] ci - screens - add delay after setting network --- test/screens/new-ui.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/screens/new-ui.js b/test/screens/new-ui.js index b23260a7c..ecd45cf9b 100644 --- a/test/screens/new-ui.js +++ b/test/screens/new-ui.js @@ -47,6 +47,7 @@ async function captureAllScreens() { await driver.switchTo().window(tabs[0]) await delay(500) await setProviderType('localhost') + await delay(300) // click try new ui await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-center.flex-grow > p')).click() From 6d3da95a95790361aec4409eb67b4ec2649c4455 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 17:59:15 -0700 Subject: [PATCH 167/246] ci - breakout announce job to upload builds and screenshots --- .circleci/config.yml | 48 ++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b0bd97ef0..14d693d7d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,12 +17,17 @@ workflows: - prep-deps-npm - test-e2e: requires: - - prep-build - prep-deps-npm - - test-screens: + - prep-build + - job-screens: requires: + - prep-deps-npm - prep-build + - job-announce: + requires: - prep-deps-npm + - prep-build + - job-screens - test-unit: requires: - prep-deps-npm @@ -49,7 +54,7 @@ workflows: - test-lint - test-unit - test-e2e - - test-screens + - job-screens - test-integration-mascara-chrome - test-integration-mascara-firefox - test-integration-flat-chrome @@ -103,15 +108,7 @@ jobs: key: build-cache-{{ .Revision }} paths: - dist - - store_artifacts: - path: dist/mascara - destination: builds/mascara - - store_artifacts: - path: builds - destination: builds - - run: - name: build:announce - command: ./development/metamaskbot-build-announce.js + - builds prep-scss: docker: @@ -159,7 +156,7 @@ jobs: path: test-artifacts destination: test-artifacts - test-screens: + job-screens: docker: - image: circleci/node:8-browsers steps: @@ -171,9 +168,34 @@ jobs: - run: name: Test command: npm run test:screens + - save_cache: + key: job-screens-{{ .Revision }} + paths: + - test-artifacts + + job-announce: + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: dependency-cache-{{ checksum "package-lock.json" }} + - restore_cache: + key: build-cache-{{ .Revision }} + - restore_cache: + key: job-screens-{{ .Revision }} + - store_artifacts: + path: dist/mascara + destination: builds/mascara + - store_artifacts: + path: builds + destination: builds - store_artifacts: path: test-artifacts destination: test-artifacts + - run: + name: build:announce + command: ./development/metamaskbot-build-announce.js test-unit: docker: From 8db097d8d9307bc7a0bbb0cd802ad30ad0fc2740 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 18:14:26 -0700 Subject: [PATCH 168/246] ci - screens - increase delay before setting provider type --- test/screens/new-ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/screens/new-ui.js b/test/screens/new-ui.js index ecd45cf9b..f7d7ea20f 100644 --- a/test/screens/new-ui.js +++ b/test/screens/new-ui.js @@ -45,7 +45,7 @@ async function captureAllScreens() { await delay(500) tabs = await driver.getAllWindowHandles() await driver.switchTo().window(tabs[0]) - await delay(500) + await delay(1000) await setProviderType('localhost') await delay(300) From 9f7b63bb6a03d79a00a8e47b7b8866bbba7bb810 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 21:45:49 -0700 Subject: [PATCH 169/246] identicon - set blockies height and width to identicon diameter --- ui/app/components/identicon.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index 7cc5a4de0..dce9b0449 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -105,9 +105,8 @@ IdenticonComponent.prototype.componentDidUpdate = function () { function _generateBlockie (container, address, diameter) { const img = new Image() img.src = toDataUrl(address) - const dia = !diameter || diameter < 50 ? 50 : diameter - img.height = dia * 1.25 - img.width = dia * 1.25 + img.height = diameter + img.width = diameter container.appendChild(img) } From bd6f5547667bdae00e8990551f3a0ea39ab8d971 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 30 Mar 2018 22:19:02 -0700 Subject: [PATCH 170/246] build - use uglifyify and gulp-multi-process for better performance --- gulpfile.js | 29 ++++++----- package-lock.json | 123 +++++++++++++++++++++++++++------------------- package.json | 3 +- 3 files changed, 91 insertions(+), 64 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 1eb0a974b..3a3725c0a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -28,8 +28,14 @@ const uglify = require('gulp-uglify-es').default const babel = require('gulp-babel') const debug = require('gulp-debug') const pify = require('pify') +const gulpMultiProcess = require('gulp-multi-process') const endOfStream = pify(require('end-of-stream')) +function gulpParallel (...args) { + return function spawnGulpChildProcess(cb) { + return gulpMultiProcess(args, cb, true) + } +} const browserPlatforms = [ 'firefox', @@ -418,7 +424,7 @@ gulp.task('build', gulp.series( 'clean', 'build:scss', - gulp.parallel( + gulpParallel( 'build:extension:js', 'build:mascara:js', 'copy' @@ -476,6 +482,16 @@ function generateBundler(opts, performBundle) { let bundler = browserify(browserifyOpts) + // Minification + if (opts.minifyBuild) { + bundler.transform('uglifyify', { + global: true, + mangle: { + reserved: [ 'MetamaskInpageProvider' ] + }, + }) + } + if (opts.watch) { bundler = watchify(bundler) // on any file update, re-runs the bundler @@ -544,7 +560,6 @@ function bundleTask(opts) { // buffer file contents (?) .pipe(buffer()) - // Initialize Source Maps if (opts.buildSourceMaps) { buildStream = buildStream @@ -552,16 +567,6 @@ function bundleTask(opts) { .pipe(sourcemaps.init({ loadMaps: true })) } - // Minification - if (opts.minifyBuild) { - buildStream = buildStream - .pipe(uglify({ - mangle: { - reserved: [ 'MetamaskInpageProvider' ] - }, - })) - } - // Finalize Source Maps (writes .map file) if (opts.buildSourceMaps) { buildStream = buildStream diff --git a/package-lock.json b/package-lock.json index 18d49971e..591e45f91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -907,6 +907,65 @@ "async-done": "1.2.4" } }, + "async.queue": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.queue/-/async.queue-0.5.2.tgz", + "integrity": "sha1-jV2QgS4UgQZrwJBOjMFxKxfDvXw=", + "dev": true, + "requires": { + "async.util.queue": "0.5.2" + } + }, + "async.util.arrayeach": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.arrayeach/-/async.util.arrayeach-0.5.2.tgz", + "integrity": "sha1-WMTpgCjVXWm/sFrrOvROClVagpw=", + "dev": true + }, + "async.util.isarray": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.isarray/-/async.util.isarray-0.5.2.tgz", + "integrity": "sha1-5i2sjyY29lh13PdSHC0k0N+yu98=", + "dev": true + }, + "async.util.map": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.map/-/async.util.map-0.5.2.tgz", + "integrity": "sha1-5YjvhuCzq18CfZevTWg10FXKadY=", + "dev": true + }, + "async.util.noop": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.noop/-/async.util.noop-0.5.2.tgz", + "integrity": "sha1-vdYrl8sKo/YLWGrRSEaGmJdeWLk=", + "dev": true + }, + "async.util.onlyonce": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.onlyonce/-/async.util.onlyonce-0.5.2.tgz", + "integrity": "sha1-uOb8AErckjFk154y8oE+5GXCT/I=", + "dev": true + }, + "async.util.queue": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.queue/-/async.util.queue-0.5.2.tgz", + "integrity": "sha1-V/Zavho83yc9MavSirlUJfgiLuU=", + "dev": true, + "requires": { + "async.util.arrayeach": "0.5.2", + "async.util.isarray": "0.5.2", + "async.util.map": "0.5.2", + "async.util.noop": "0.5.2", + "async.util.onlyonce": "0.5.2", + "async.util.setimmediate": "0.5.2" + } + }, + "async.util.setimmediate": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.setimmediate/-/async.util.setimmediate-0.5.2.tgz", + "integrity": "sha1-KBLrq/KlgCd1jUvHeT0cz68QJV8=", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -7148,12 +7207,6 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, - "fork-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", - "integrity": "sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=", - "dev": true - }, "form-data": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", @@ -8683,17 +8736,6 @@ "gulp-util": "3.0.8" } }, - "gulp-if": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/gulp-if/-/gulp-if-2.0.2.tgz", - "integrity": "sha1-pJe351cwBQQcqivIt92jyARE1ik=", - "dev": true, - "requires": { - "gulp-match": "1.0.3", - "ternary-stream": "2.0.1", - "through2": "2.0.3" - } - }, "gulp-json-editor": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/gulp-json-editor/-/gulp-json-editor-2.2.1.tgz", @@ -8845,13 +8887,13 @@ } } }, - "gulp-match": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/gulp-match/-/gulp-match-1.0.3.tgz", - "integrity": "sha1-kcfA1/Kb7NZgbVfYCn+Hdqh6uo4=", + "gulp-multi-process": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/gulp-multi-process/-/gulp-multi-process-1.3.1.tgz", + "integrity": "sha512-okxYy3mxUkekM0RNjkBg8OPuzpnD2yXMAdnGOaQPSJ2wzBdE9R9pkTV+tzPZ65ORK7b57YUc6s+gROA4+EIOLg==", "dev": true, "requires": { - "minimatch": "3.0.4" + "async.queue": "0.5.2" } }, "gulp-replace": { @@ -13247,15 +13289,6 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, - "merge-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", - "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", - "dev": true, - "requires": { - "readable-stream": "2.3.3" - } - }, "merkle-patricia-tree": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.0.tgz", @@ -20753,18 +20786,6 @@ "inherits": "2.0.3" } }, - "ternary-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-2.0.1.tgz", - "integrity": "sha1-Bk5Im0tb9gumpre8fy9cJ07Pgmk=", - "dev": true, - "requires": { - "duplexify": "3.5.1", - "fork-stream": "0.0.4", - "merge-stream": "1.0.1", - "through2": "2.0.3" - } - }, "testem": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/testem/-/testem-2.0.0.tgz", @@ -21415,19 +21436,19 @@ "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g==" }, "uglify-es": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.4.tgz", - "integrity": "sha512-vDOyDaf7LcABZI5oJt8bin5FD8kYONux5jd8FY6SsV2SfD+MMXaPeGUotysbycSxdu170y5IQ8FvlKzU/TUryw==", + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", + "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", "dev": true, "requires": { - "commander": "2.12.2", + "commander": "2.13.0", "source-map": "0.6.1" }, "dependencies": { "commander": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz", - "integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", "dev": true }, "source-map": { @@ -21454,7 +21475,7 @@ "extend": "1.3.0", "minimatch": "3.0.4", "through": "2.3.8", - "uglify-es": "3.3.4" + "uglify-es": "3.3.9" }, "dependencies": { "extend": { diff --git a/package.json b/package.json index 62d703c90..0c8c9de54 100644 --- a/package.json +++ b/package.json @@ -223,6 +223,7 @@ "gulp-eslint": "^4.0.0", "gulp-json-editor": "^2.2.1", "gulp-livereload": "^3.8.1", + "gulp-multi-process": "^1.3.1", "gulp-replace": "^0.6.1", "gulp-sourcemaps": "^2.6.0", "gulp-stylefmt": "^1.1.0", @@ -262,7 +263,7 @@ "stylelint-config-standard": "^18.2.0", "tape": "^4.5.1", "testem": "^2.0.0", - "uglifyify": "^4.0.2", + "uglifyify": "^4.0.5", "vinyl-buffer": "^1.0.1", "vinyl-source-stream": "^2.0.0", "watchify": "^3.9.0" From 0d591d8da264dd0056442a5033a1112013cba3e0 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 11:10:43 -0700 Subject: [PATCH 171/246] Update translating-guide.md --- docs/translating-guide.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/translating-guide.md b/docs/translating-guide.md index ae2dfecd3..8b2bc1785 100644 --- a/docs/translating-guide.md +++ b/docs/translating-guide.md @@ -6,9 +6,12 @@ The MetaMask browser extension supports new translations added in the form of ne ## Adding a new Language -Each supported language is represented by a folder in `app/_locales` whose name is that language's subtag ([look up a language subtag using this tool](https://r12a.github.io/app-subtags/)). +- Each supported language is represented by a folder in `app/_locales` whose name is that language's subtag (example: `app/_locales/es/`). (look up a language subtag using the [r12a "Find" tool](https://r12a.github.io/app-subtags/) or this [wikipedia list](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)). +- Inside that folder there should be a `messages.json`. +- An easy way to start your translation is to first **make a copy** of `app/_locales/en/messages.json` (the english translation), and then **translate the `message` key** for each in-app message. +- **The `description` key** is just to add context for what the translation is about, it **does not need to be translated**. +- Add the language to the [locales index](https://github.com/MetaMask/metamask-extension/blob/master/app/_locales/index.json) `app/_locales/index.json` -Inside that folder there should be a `messages.json` file that follows the specified format. An easy way to start your translation is to first duplicate `app/_locales/en/messages.json` (the english translation), and then update the `message` key for each in-app message. That's it! When MetaMask is loaded on a computer with that language set as the system language, they will see your translation instead of the default one. @@ -20,7 +23,7 @@ To automatically see if you are missing any phrases to translate, we have a scri node development/verify-locale-strings.js $YOUR_LOCALE ``` -Where `$YOUR_LOCALE` is your [locale string](https://r12a.github.io/app-subtags/), i.e. the name of your language folder. +Where `$YOUR_LOCALE` is your locale string (example: `es`), i.e. the name of your language folder. To verify that your translation works in the app, you will need to [build a local copy](https://github.com/MetaMask/metamask-extension#building-locally) of MetaMask. You will need to change your browser language, your operating system language, and restart your browser (sorry it's so much work!). From 04d85fd79e378dc4830719ce3b742feb9d5de6a3 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 11:50:22 -0700 Subject: [PATCH 172/246] deps - bump package-lock.json --- package-lock.json | 47 ----------------------------------------------- 1 file changed, 47 deletions(-) diff --git a/package-lock.json b/package-lock.json index 18d49971e..fe47f8cf9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7148,12 +7148,6 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, - "fork-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", - "integrity": "sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=", - "dev": true - }, "form-data": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", @@ -8683,17 +8677,6 @@ "gulp-util": "3.0.8" } }, - "gulp-if": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/gulp-if/-/gulp-if-2.0.2.tgz", - "integrity": "sha1-pJe351cwBQQcqivIt92jyARE1ik=", - "dev": true, - "requires": { - "gulp-match": "1.0.3", - "ternary-stream": "2.0.1", - "through2": "2.0.3" - } - }, "gulp-json-editor": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/gulp-json-editor/-/gulp-json-editor-2.2.1.tgz", @@ -8845,15 +8828,6 @@ } } }, - "gulp-match": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/gulp-match/-/gulp-match-1.0.3.tgz", - "integrity": "sha1-kcfA1/Kb7NZgbVfYCn+Hdqh6uo4=", - "dev": true, - "requires": { - "minimatch": "3.0.4" - } - }, "gulp-replace": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-0.6.1.tgz", @@ -13247,15 +13221,6 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, - "merge-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", - "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", - "dev": true, - "requires": { - "readable-stream": "2.3.3" - } - }, "merkle-patricia-tree": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.0.tgz", @@ -20753,18 +20718,6 @@ "inherits": "2.0.3" } }, - "ternary-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-2.0.1.tgz", - "integrity": "sha1-Bk5Im0tb9gumpre8fy9cJ07Pgmk=", - "dev": true, - "requires": { - "duplexify": "3.5.1", - "fork-stream": "0.0.4", - "merge-stream": "1.0.1", - "through2": "2.0.3" - } - }, "testem": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/testem/-/testem-2.0.0.tgz", From 1dc3c51b5445996e9111cabe863fb0eef65dcfc5 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 2 Apr 2018 16:26:19 -0230 Subject: [PATCH 173/246] UpdateSendErrors only called when balance defined, recalled if balance updates. --- .../pending-tx/confirm-send-ether.js | 37 +- .../pending-tx/confirm-send-token.js | 38 +- yarn.lock | 559 ++++++++---------- 3 files changed, 291 insertions(+), 343 deletions(-) diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index 2474516d4..eae70b279 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -109,16 +109,37 @@ function ConfirmSendEther () { this.onSubmit = this.onSubmit.bind(this) } -ConfirmSendEther.prototype.componentWillMount = function () { - const { updateSendErrors } = this.props +ConfirmSendEther.prototype.updateComponentSendErrors = function (prevProps) { + const { + balance: oldBalance, + conversionRate: oldConversionRate, + } = prevProps + const { + updateSendErrors, + balance, + conversionRate, + } = this.props const txMeta = this.gatherTxMeta() - const balanceIsSufficient = this.isBalanceSufficient(txMeta) - updateSendErrors({ - insufficientFunds: balanceIsSufficient - ? false - : this.context.t('insufficientFunds'), - }) + const shouldUpdateBalanceSendErrors = balance && [ + balance !== oldBalance, + conversionRate !== oldConversionRate, + ].some(x => Boolean(x)) + + if (shouldUpdateBalanceSendErrors) { + const balanceIsSufficient = this.isBalanceSufficient(txMeta) + updateSendErrors({ + insufficientFunds: balanceIsSufficient ? false : this.context.t('insufficientFunds'), + }) + } +} + +ConfirmSendEther.prototype.componentWillMount = function () { + this.updateComponentSendErrors({}) +} + +ConfirmSendEther.prototype.componentDidUpdate = function (prevProps) { + this.updateComponentSendErrors(prevProps) } ConfirmSendEther.prototype.getAmount = function () { diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index dd9fdc23f..814386c5c 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -147,21 +147,43 @@ function ConfirmSendToken () { this.onSubmit = this.onSubmit.bind(this) } -ConfirmSendToken.prototype.componentWillMount = function () { - const { tokenContract, selectedAddress, updateSendErrors} = this.props +ConfirmSendToken.prototype.updateComponentSendErrors = function (prevProps) { + const { + balance: oldBalance, + conversionRate: oldConversionRate, + } = prevProps + const { + updateSendErrors, + balance, + conversionRate, + } = this.props const txMeta = this.gatherTxMeta() - const balanceIsSufficient = this.isBalanceSufficient(txMeta) + + const shouldUpdateBalanceSendErrors = balance && [ + balance !== oldBalance, + conversionRate !== oldConversionRate, + ].some(x => Boolean(x)) + + if (shouldUpdateBalanceSendErrors) { + const balanceIsSufficient = this.isBalanceSufficient(txMeta) + updateSendErrors({ + insufficientFunds: balanceIsSufficient ? false : this.context.t('insufficientFunds'), + }) + } +} + +ConfirmSendToken.prototype.componentWillMount = function () { + const { tokenContract, selectedAddress } = this.props tokenContract && tokenContract .balanceOf(selectedAddress) .then(usersToken => { }) this.props.updateTokenExchangeRate() + this.updateComponentSendErrors({}) +} - updateSendErrors({ - insufficientFunds: balanceIsSufficient - ? false - : this.context.t('insufficientFunds'), - }) +ConfirmSendToken.prototype.componentDidUpdate = function (prevProps) { + this.updateComponentSendErrors(prevProps) } ConfirmSendToken.prototype.getAmount = function () { diff --git a/yarn.lock b/yarn.lock index 35365248a..cda23f3c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -99,7 +99,7 @@ JSONStream@^1.0.3: jsonparse "^1.2.0" through ">=2.2.7 <3" -abab@^1.0.3: +abab@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" @@ -152,7 +152,7 @@ acorn-dynamic-import@^2.0.0: dependencies: acorn "^4.0.3" -acorn-globals@^4.0.0: +acorn-globals@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538" dependencies: @@ -171,7 +171,7 @@ acorn-node@^1.3.0: acorn "^5.4.1" xtend "^4.0.1" -acorn@5.X, acorn@^5.0.0, acorn@^5.0.3, acorn@^5.1.2, acorn@^5.2.1: +acorn@5.X, acorn@^5.0.0, acorn@^5.0.3, acorn@^5.2.1: version "5.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" @@ -183,7 +183,7 @@ acorn@^4.0.3: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" -acorn@^5.4.1: +acorn@^5.3.0, acorn@^5.4.1: version "5.5.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" @@ -268,10 +268,6 @@ ansi-colors@^1.0.1: dependencies: ansi-wrap "^0.1.0" -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - ansi-escapes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" @@ -318,10 +314,6 @@ ansi-wrap@0.1.0, ansi-wrap@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" -ansi@^0.3.0, ansi@~0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/ansi/-/ansi-0.3.1.tgz#0c42d4fb17160d5a9af1e484bace1c66922c1b21" - ansicolors@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" @@ -1634,7 +1626,7 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@^3.0.5, bluebird@^3.1.1, bluebird@^3.3.0, bluebird@^3.4.6, bluebird@^3.4.7, bluebird@^3.5.0: +bluebird@^3.0.5, bluebird@^3.1.1, bluebird@^3.3.0, bluebird@^3.4.6, bluebird@^3.5.0: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" @@ -2044,10 +2036,6 @@ buffer-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" -buffer-from@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" - buffer-more-ints@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz#26b3885d10fa13db7fc01aae3aab870199e0124c" @@ -2182,22 +2170,6 @@ caniuse-lite@^1.0.30000810, caniuse-lite@^1.0.30000813: version "1.0.30000814" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000814.tgz#73eb6925ac2e54d495218f1ea0007da3940e488b" -caporal@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/caporal/-/caporal-0.10.0.tgz#2ddfbe5ede26d2bd356f042f564ff57803cdabc9" - dependencies: - bluebird "^3.4.7" - chalk "^1.1.3" - cli-table2 "^0.2.0" - fast-levenshtein "^2.0.6" - lodash.camelcase "^4.3.0" - lodash.kebabcase "^4.1.1" - lodash.merge "^4.6.0" - micromist "^1.0.1" - prettyjson "^1.2.1" - tabtab "^2.2.2" - winston "^2.3.1" - caseless@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" @@ -2367,6 +2339,16 @@ chokidar@^2.0.0: optionalDependencies: fsevents "^1.0.0" +chromedriver@^2.34.1: + version "2.37.0" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-2.37.0.tgz#e7867c8236f6bb89024737bbffc9a4b33ded658b" + dependencies: + del "^3.0.0" + extract-zip "^1.6.5" + kew "^0.7.0" + mkdirp "^0.5.1" + request "^2.83.0" + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -2396,35 +2378,16 @@ classnames@^2.2.4, classnames@^2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" -cli-cursor@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - dependencies: - restore-cursor "^1.0.1" - cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: restore-cursor "^2.0.0" -cli-table2@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" - dependencies: - lodash "^3.10.1" - string-width "^1.0.1" - optionalDependencies: - colors "^1.1.2" - cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" -client-sw-ready-event@^3.3.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/client-sw-ready-event/-/client-sw-ready-event-3.4.0.tgz#ff486461769055e7748570f1aef102b8675b66d0" - cliui@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" @@ -2685,7 +2648,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.3, concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.5.1, concat-stream@^1.6.0, concat-stream@~1.6.0: +concat-stream@1.6.0, concat-stream@^1.4.3, concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.5.1, concat-stream@^1.6.0, concat-stream@~1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -2693,15 +2656,6 @@ concat-stream@^1.4.3, concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@ readable-stream "^2.2.2" typedarray "^0.0.6" -concat-stream@^1.4.7: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - concat-stream@~1.5.0, concat-stream@~1.5.1: version "1.5.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" @@ -2750,7 +2704,7 @@ content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" -content-type-parser@^1.0.1: +content-type-parser@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.2.tgz#caabe80623e63638b2502fd4c7f12ff4ce2352e7" @@ -2799,6 +2753,10 @@ core-js@^2.2.0, core-js@^2.4.0, core-js@^2.5.0: version "2.5.3" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" +core-js@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -3489,7 +3447,7 @@ duplexer@^0.1.1, duplexer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" -duplexify@^3.1.2, duplexify@^3.4.2, duplexify@^3.5.0: +duplexify@^3.1.2, duplexify@^3.4.2: version "3.5.1" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.1.tgz#4e1516be68838bc90a49994f0b39a6e5960befcd" dependencies: @@ -3744,14 +3702,6 @@ es-abstract@^1.5.0, es-abstract@^1.6.1, es-abstract@^1.7.0: is-callable "^1.1.3" is-regex "^1.0.4" -es-check@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es-check/-/es-check-2.0.3.tgz#04eafde54f5bfcf0881b1ae35c4a5205a9041ee2" - dependencies: - acorn "^5.1.2" - caporal "^0.10.0" - glob "^7.1.2" - es-to-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" @@ -3790,6 +3740,10 @@ es6-promise@^4.0.3: version "4.2.4" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" +es6-promise@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" + es6-promisify@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" @@ -3884,11 +3838,11 @@ eslint-plugin-chai@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-chai/-/eslint-plugin-chai-0.0.1.tgz#9a1dea58b335c31242219d059b37ffb14309f6e1" -eslint-plugin-mocha@^4.9.0: - version "4.11.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-mocha/-/eslint-plugin-mocha-4.11.0.tgz#91193a2f55e20a5e35974054a0089d30198ee578" +eslint-plugin-mocha@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-mocha/-/eslint-plugin-mocha-5.0.0.tgz#43946a7ecaf39039eb3ee20635ebd4cc19baf6dd" dependencies: - ramda "^0.24.1" + ramda "^0.25.0" eslint-plugin-react@^7.4.0: version "7.5.1" @@ -4377,12 +4331,12 @@ ethjs-format@0.2.3: number-to-bn "1.7.0" strip-hex-prefix "1.0.0" -ethjs-format@0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/ethjs-format/-/ethjs-format-0.2.4.tgz#5bbbc44a5ad24e68ab393312ff9039a73b65bf81" +ethjs-format@0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/ethjs-format/-/ethjs-format-0.2.5.tgz#44f30abee17b074d7162d2c886abffd065828925" dependencies: bn.js "4.11.6" - ethjs-schema "^0.1.9" + ethjs-schema "0.2.0" ethjs-util "0.1.3" is-hex-prefixed "1.0.0" number-to-bn "1.7.0" @@ -4408,26 +4362,30 @@ ethjs-query@^0.2.4, ethjs-query@^0.2.6, ethjs-query@^0.2.9: ethjs-format "0.2.2" ethjs-rpc "0.1.5" -ethjs-query@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/ethjs-query/-/ethjs-query-0.3.2.tgz#f488a48ce1994cd4c77eccb7b52902c6f29cfd85" +ethjs-query@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/ethjs-query/-/ethjs-query-0.3.4.tgz#068a8b268fe045acd2dfdf167bb740b12e596bc3" dependencies: - ethjs-format "0.2.4" - ethjs-rpc "0.1.8" + ethjs-format "0.2.5" + ethjs-rpc "0.1.9" ethjs-rpc@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/ethjs-rpc/-/ethjs-rpc-0.1.5.tgz#099e22f27dc4c18b6978a485fc36b1b0f7969080" -ethjs-rpc@0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/ethjs-rpc/-/ethjs-rpc-0.1.8.tgz#1676740e41c7228196a71189d33f15c9c85b599d" +ethjs-rpc@0.1.9: + version "0.1.9" + resolved "https://registry.yarnpkg.com/ethjs-rpc/-/ethjs-rpc-0.1.9.tgz#389dcd61be52e72bc47111a75805f8e45882faea" ethjs-schema@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/ethjs-schema/-/ethjs-schema-0.1.5.tgz#59740e3b3977bcdbb9b11bc3068201e8aceabb0d" -ethjs-schema@^0.1.6, ethjs-schema@^0.1.9: +ethjs-schema@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ethjs-schema/-/ethjs-schema-0.2.0.tgz#07b46d4f55b792a846c90a79f330d31d112cca38" + +ethjs-schema@^0.1.6: version "0.1.9" resolved "https://registry.yarnpkg.com/ethjs-schema/-/ethjs-schema-0.1.9.tgz#858c2a5da706ae04812b4ce8b1eb4b4921e33092" @@ -4547,10 +4505,6 @@ exists-stat@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - expand-braces@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/expand-braces/-/expand-braces-0.1.2.tgz#488b1d1d2451cb3d3a6b192cfc030f44c5855fea" @@ -4668,14 +4622,6 @@ extensionizer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/extensionizer/-/extensionizer-1.0.0.tgz#01c209bbea6d9c0acba77129c3aa4a9a98fc3538" -external-editor@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" - dependencies: - extend "^3.0.0" - spawn-sync "^1.0.15" - tmp "^0.0.29" - external-editor@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" @@ -4716,6 +4662,15 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +extract-zip@^1.6.5: + version "1.6.6" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" + dependencies: + concat-stream "1.6.0" + debug "2.6.9" + mkdirp "0.5.0" + yauzl "2.4.1" + extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -4787,19 +4742,18 @@ fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.9: setimmediate "^1.0.5" ua-parser-js "^0.7.9" +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + dependencies: + pend "~1.2.0" + fetch-ponyfill@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893" dependencies: node-fetch "~1.7.1" -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -5018,10 +4972,6 @@ forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" -fork-stream@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/fork-stream/-/fork-stream-0.0.4.tgz#db849fce77f6708a5f8f386ae533a0907b54ae70" - form-data@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.0.0.tgz#6f0aebadcc5da16c13e1ecc11137d85f9b883b25" @@ -5172,16 +5122,6 @@ gather-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b" -gauge@~1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-1.2.7.tgz#e9cec5483d3d4ee0ef44b60a7d99e4935e136d93" - dependencies: - ansi "^0.3.0" - has-unicode "^2.0.0" - lodash.pad "^4.1.0" - lodash.padend "^4.1.0" - lodash.padstart "^4.1.0" - gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -5219,6 +5159,10 @@ get-func-name@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" +get-own-enumerable-property-symbols@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz#5c4ad87f2834c4b9b4e84549dc1e0650fb38c24b" + get-stdin@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-3.0.2.tgz#c1ced24b9039b38ded85bdf161e57713b6dd4abe" @@ -5497,6 +5441,17 @@ gulp-cli@^2.0.0: v8flags "^3.0.1" yargs "^7.1.0" +gulp-debug@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/gulp-debug/-/gulp-debug-3.2.0.tgz#45aba4439fa79fe0788f6a411ee0778f4492dfa5" + dependencies: + chalk "^2.3.0" + fancy-log "^1.3.2" + plur "^2.0.0" + stringify-object "^3.0.0" + through2 "^2.0.0" + tildify "^1.1.2" + gulp-eslint@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/gulp-eslint/-/gulp-eslint-4.0.0.tgz#16d9ea4d696e7b7a9d65eeb1aa5bc4ba0a22c7f7" @@ -5504,14 +5459,6 @@ gulp-eslint@^4.0.0: eslint "^4.0.0" gulp-util "^3.0.8" -gulp-if@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-2.0.2.tgz#a497b7e7573005041caa2bc8b7dda3c80444d629" - dependencies: - gulp-match "^1.0.3" - ternary-stream "^2.0.1" - through2 "^2.0.1" - gulp-json-editor@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/gulp-json-editor/-/gulp-json-editor-2.2.1.tgz#7c4dd7477e8d06dc5dc49c0b81e745cdb04f97bb" @@ -5533,12 +5480,6 @@ gulp-livereload@^3.8.1: lodash.assign "^3.0.0" mini-lr "^0.1.8" -gulp-match@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.0.3.tgz#91c7c0d7f29becd6606d57d80a7f8776a87aba8e" - dependencies: - minimatch "^3.0.3" - gulp-replace@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/gulp-replace/-/gulp-replace-0.6.1.tgz#11bf8c8fce533e33e2f6a8f2f430b955ba0be066" @@ -5912,7 +5853,7 @@ hosted-git-info@^2.1.4: version "2.5.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" -html-encoding-sniffer@^1.0.1: +html-encoding-sniffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" dependencies: @@ -6102,6 +6043,10 @@ immediate@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -6167,25 +6112,6 @@ inline-source-map@~0.6.0: dependencies: source-map "~0.5.3" -inquirer@^1.0.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" - dependencies: - ansi-escapes "^1.1.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" - cli-width "^2.0.0" - external-editor "^1.1.0" - figures "^1.3.5" - lodash "^4.3.0" - mute-stream "0.0.6" - pinkie-promise "^2.0.0" - run-async "^2.2.0" - rx "^4.1.0" - string-width "^1.0.1" - strip-ansi "^3.0.0" - through "^2.3.6" - inquirer@^3.0.6: version "3.3.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" @@ -6461,6 +6387,10 @@ is-number@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" +is-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + is-odd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-1.0.0.tgz#3b8a932eb028b3775c39bb09e91767accdb69088" @@ -6749,34 +6679,36 @@ jsdom-global@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/jsdom-global/-/jsdom-global-3.0.2.tgz#6bd299c13b0c4626b2da2c0393cd4385d606acb9" -jsdom@^11.1.0: - version "11.5.1" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.5.1.tgz#5df753b8d0bca20142ce21f4f6c039f99a992929" +jsdom@^11.2.0: + version "11.6.2" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.6.2.tgz#25d1ef332d48adf77fc5221fe2619967923f16bb" dependencies: - abab "^1.0.3" - acorn "^5.1.2" - acorn-globals "^4.0.0" + abab "^1.0.4" + acorn "^5.3.0" + acorn-globals "^4.1.0" array-equal "^1.0.0" browser-process-hrtime "^0.1.2" - content-type-parser "^1.0.1" + content-type-parser "^1.0.2" cssom ">= 0.3.2 < 0.4.0" cssstyle ">= 0.2.37 < 0.3.0" domexception "^1.0.0" escodegen "^1.9.0" - html-encoding-sniffer "^1.0.1" + html-encoding-sniffer "^1.0.2" left-pad "^1.2.0" nwmatcher "^1.4.3" - parse5 "^3.0.2" - pn "^1.0.0" + parse5 "4.0.0" + pn "^1.1.0" request "^2.83.0" - request-promise-native "^1.0.3" - sax "^1.2.1" - symbol-tree "^3.2.1" + request-promise-native "^1.0.5" + sax "^1.2.4" + symbol-tree "^3.2.2" tough-cookie "^2.3.3" + w3c-hr-time "^1.0.1" webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.1" - whatwg-url "^6.3.0" - xml-name-validator "^2.0.1" + whatwg-encoding "^1.0.3" + whatwg-url "^6.4.0" + ws "^4.0.0" + xml-name-validator "^3.0.0" jsesc@^1.3.0: version "1.3.0" @@ -6941,6 +6873,16 @@ jsx-ast-utils@^2.0.0: dependencies: array-includes "^3.0.3" +jszip@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.5.tgz#e3c2a6c6d706ac6e603314036d43cd40beefdf37" + dependencies: + core-js "~2.3.0" + es6-promise "~3.0.2" + lie "~3.1.0" + pako "~1.0.2" + readable-stream "~2.0.6" + just-debounce@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea" @@ -7019,6 +6961,10 @@ keccakjs@^0.2.0: browserify-sha3 "^0.0.1" sha3 "^1.1.0" +kew@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.1.0, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -7184,6 +7130,12 @@ libqp@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/libqp/-/libqp-1.1.0.tgz#f5e6e06ad74b794fb5b5b66988bf728ef1dedbe8" +lie@~3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + dependencies: + immediate "~3.0.5" + liftoff@^2.3.0: version "2.5.0" resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.5.0.tgz#2009291bb31cea861bbf10a7c15a28caf75c31ec" @@ -7313,10 +7265,6 @@ lodash.assignin@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - lodash.castarray@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" @@ -7335,10 +7283,6 @@ lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" -lodash.difference@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" - lodash.escape@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" @@ -7376,10 +7320,6 @@ lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" -lodash.kebabcase@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" - lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" @@ -7396,26 +7336,10 @@ lodash.memoize@~3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" -lodash.merge@^4.6.0: - version "4.6.1" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" - lodash.mergewith@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55" -lodash.pad@^4.1.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/lodash.pad/-/lodash.pad-4.5.1.tgz#4330949a833a7c8da22cc20f6a26c4d59debba70" - -lodash.padend@^4.1.0: - version "4.6.1" - resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e" - -lodash.padstart@^4.1.0: - version "4.6.1" - resolved "https://registry.yarnpkg.com/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b" - lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" @@ -7449,18 +7373,10 @@ lodash.templatesettings@^3.0.0: lodash._reinterpolate "^3.0.0" lodash.escape "^3.0.0" -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - lodash.uniqby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" -lodash@^3.10.1: - version "3.10.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" - lodash@^4.0.0, lodash@^4.1.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.0, lodash@~4.17.2, lodash@~4.17.4: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -7731,12 +7647,6 @@ merge-source-map@^1.0.2: dependencies: source-map "^0.6.1" -merge-stream@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" - dependencies: - readable-stream "^2.0.1" - merkle-patricia-tree@^2.1.2: version "2.3.0" resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.0.tgz#84c606232ef343f1b96fc972e697708754f08573" @@ -7831,12 +7741,6 @@ micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -micromist@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromist/-/micromist-1.0.2.tgz#41f84949a04c30cdc60a394d0cb06aaa08b86364" - dependencies: - lodash.camelcase "^4.3.0" - miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -7909,7 +7813,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -7942,6 +7846,12 @@ mkdirp@0.0.x: version "0.0.7" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.0.7.tgz#d89b4f0e4c3e5e5ca54235931675e094fe1a5072" +mkdirp@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + dependencies: + minimist "0.0.8" + mkdirp@0.5.1, mkdirp@0.x.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -8065,10 +7975,6 @@ mute-stdout@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.0.tgz#5b32ea07eb43c9ded6130434cf926f46b2a7fd4d" -mute-stream@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" - mute-stream@0.0.7, mute-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -8389,14 +8295,6 @@ npm-run-path@^2.0.0: gauge "~2.7.3" set-blocking "~2.0.0" -npmlog@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-2.0.4.tgz#98b52530f2514ca90d09ec5b22c8846722375692" - dependencies: - ansi "~0.3.1" - are-we-there-yet "~1.1.2" - gauge "~1.2.5" - nth-check@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" @@ -8631,10 +8529,6 @@ onecolor@^3.0.4: version "3.0.5" resolved "https://registry.yarnpkg.com/onecolor/-/onecolor-3.0.5.tgz#36eff32201379efdf1180fb445e51a8e2425f9f6" -onetime@^1.0.0: - version "1.1.0" - resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" @@ -8703,10 +8597,6 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" -os-shim@^0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" - os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -8766,7 +8656,7 @@ pac-resolver@~2.0.0: netmask "~1.0.4" thunkify "~2.1.1" -pako@~1.0.5: +pako@~1.0.2, pako@~1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" @@ -8831,7 +8721,11 @@ parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" -parse5@^3.0.1, parse5@^3.0.2: +parse5@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + +parse5@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" dependencies: @@ -8955,6 +8849,10 @@ pbkdf2@^3.0.3, pbkdf2@^3.0.9: safe-buffer "^5.0.1" sha.js "^2.4.8" +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + percentile@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/percentile/-/percentile-1.2.0.tgz#fa3b05c1ffd355b35228529834e5fa37f0bd465d" @@ -9037,9 +8935,9 @@ pluralize@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" -pn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.0.0.tgz#1cf5a30b0d806cd18f88fc41a6b5d4ad615b3ba9" +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" pojo-migrator@^2.1.0: version "2.1.0" @@ -9169,13 +9067,6 @@ pretty-hrtime@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" -prettyjson@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prettyjson/-/prettyjson-1.2.1.tgz#fcffab41d19cab4dfae5e575e64246619b12d289" - dependencies: - colors "^1.1.2" - minimist "^1.2.0" - printf@^0.2.3: version "0.2.5" resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" @@ -9421,6 +9312,10 @@ ramda@^0.24.1: version "0.24.1" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.24.1.tgz#c3b7755197f35b8dc3502228262c4c91ddb6b857" +ramda@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" + randexp@^0.4.2: version "0.4.6" resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3" @@ -9721,7 +9616,7 @@ readable-stream@^2, readable-stream@^2.0.0, readable-stream@^2.0.1, readable-str string_decoder "~1.0.3" util-deprecate "~1.0.1" -readable-stream@~2.0.0, readable-stream@~2.0.5: +readable-stream@~2.0.0, readable-stream@~2.0.5, readable-stream@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: @@ -9964,7 +9859,7 @@ request-promise-core@1.1.1: dependencies: lodash "^4.13.1" -request-promise-native@^1.0.3: +request-promise-native@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" dependencies: @@ -10184,13 +10079,6 @@ response-stream@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/response-stream/-/response-stream-0.0.0.tgz#da4b17cc7684c98c962beb4d95f668c8dcad09d5" -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -10262,10 +10150,6 @@ rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" -rx@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" - safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -10293,7 +10177,7 @@ sass-graph@^2.2.4: scss-tokenizer "^0.2.3" yargs "^7.0.0" -sax@^1.2.1: +sax@>=0.6.0, sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -10344,6 +10228,15 @@ secp256k1@^3.0.1: nan "^2.2.1" safe-buffer "^5.1.0" +selenium-webdriver@^3.5.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" + dependencies: + jszip "^3.1.3" + rimraf "^2.5.4" + tmp "0.0.30" + xml2js "^0.4.17" + semaphore@>=1.0.1, semaphore@^1.0.3, semaphore@^1.0.5: version "1.1.0" resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" @@ -10492,9 +10385,9 @@ signal-exit@^3.0.0, signal-exit@^3.0.1, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -sinon@^4.0.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.1.3.tgz#fc599eda47ed9f1a694ce774b94ab44260bd7ac5" +sinon@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-5.0.0.tgz#e6de3b3f7fed338b470f8779dc4bab9fca058894" dependencies: diff "^3.1.0" formatio "1.2.0" @@ -10766,13 +10659,6 @@ spawn-args@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" -spawn-sync@^1.0.15: - version "1.0.15" - resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" - dependencies: - concat-stream "^1.4.7" - os-shim "^0.1.2" - spawn-wrap@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.4.2.tgz#cff58e73a8224617b6561abdc32586ea0c82248c" @@ -11008,6 +10894,14 @@ string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" +stringify-object@^3.0.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.2.2.tgz#9853052e5a88fb605a44cd27445aa257ad7ffbcd" + dependencies: + get-own-enumerable-property-symbols "^2.0.1" + is-obj "^1.0.1" + is-regexp "^1.0.0" + stringstream@~0.0.4, stringstream@~0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" @@ -11226,7 +11120,15 @@ svg-tags@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" -sw-stream@^2.0.0: +sw-controller@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sw-controller/-/sw-controller-1.0.3.tgz#794b5e3e324cf2c515d12b3df57a56128e67dd1e" + dependencies: + babel-preset-es2015 "^6.22.0" + babel-runtime "^6.23.0" + babelify "^7.3.0" + +sw-stream@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/sw-stream/-/sw-stream-2.0.2.tgz#68cd1ce959f3fe79b76f583f98c9172543880a0f" dependencies: @@ -11242,7 +11144,7 @@ symbol-observable@^1.0.3, symbol-observable@^1.0.4: version "1.1.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.1.0.tgz#5c68fd8d54115d9dfb72a84720549222e8db9b32" -symbol-tree@^3.2.1: +symbol-tree@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" @@ -11269,19 +11171,6 @@ table@^4.0.1: slice-ansi "1.0.0" string-width "^2.1.1" -tabtab@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/tabtab/-/tabtab-2.2.2.tgz#7a047f143b010b4cbd31f857e82961512cbf4e14" - dependencies: - debug "^2.2.0" - inquirer "^1.0.2" - lodash.difference "^4.5.0" - lodash.uniq "^4.5.0" - minimist "^1.2.0" - mkdirp "^0.5.1" - npmlog "^2.0.3" - object-assign "^4.1.0" - tap-parser@^5.1.0: version "5.4.0" resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-5.4.0.tgz#6907e89725d7b7fa6ae41ee2c464c3db43188aec" @@ -11334,15 +11223,6 @@ tar@^2.0.0, tar@^2.2.1: fstream "^1.0.2" inherits "2" -ternary-stream@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-2.0.1.tgz#064e489b4b5bf60ba6a6b7bc7f2f5c274ecf8269" - dependencies: - duplexify "^3.5.0" - fork-stream "^0.0.4" - merge-stream "^1.0.0" - through2 "^2.0.1" - test-exclude@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.1.1.tgz#4d84964b0966b0087ecc334a2ce002d3d9341e26" @@ -11467,6 +11347,12 @@ thunkify@~2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/thunkify/-/thunkify-2.1.2.tgz#faa0e9d230c51acc95ca13a361ac05ca7e04553d" +tildify@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tildify/-/tildify-1.2.0.tgz#dcec03f55dca9b7aa3e5b04f21817eb56e63588a" + dependencies: + os-homedir "^1.0.0" + time-stamp@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" @@ -11494,18 +11380,18 @@ timespan@2.3.x: version "2.3.0" resolved "https://registry.yarnpkg.com/timespan/-/timespan-2.3.0.tgz#4902ce040bd13d845c8f59b27e9d59bad6f39929" +tmp@0.0.30: + version "0.0.30" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + dependencies: + os-tmpdir "~1.0.1" + tmp@0.0.33, tmp@0.0.x, tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" dependencies: os-tmpdir "~1.0.2" -tmp@^0.0.29: - version "0.0.29" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" - dependencies: - os-tmpdir "~1.0.1" - to-absolute-glob@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b" @@ -12077,6 +11963,12 @@ vreme@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/vreme/-/vreme-3.0.2.tgz#4721376b449457fefde8a849d3340933b90b5686" +w3c-hr-time@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" + dependencies: + browser-process-hrtime "^0.1.2" + walk-sync@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" @@ -12141,14 +12033,14 @@ web3-provider-engine@^13.3.2: xhr "^2.2.0" xtend "^4.0.1" -web3-provider-engine@^13.5.6: - version "13.6.0" - resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.6.0.tgz#836f51c4ee48bd7583acf3696033779c704c2214" +web3-provider-engine@^13.8.0: + version "13.8.0" + resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz#4c7c1ad2af5f1fe10343b8a65495879a2f9c00df" dependencies: async "^2.5.0" clone "^2.0.0" eth-block-tracker "^2.2.2" - eth-sig-util "^1.3.0" + eth-sig-util "^1.4.2" ethereumjs-block "^1.2.2" ethereumjs-tx "^1.2.0" ethereumjs-util "^5.1.1" @@ -12239,7 +12131,7 @@ websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" -whatwg-encoding@^1.0.1: +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" dependencies: @@ -12249,7 +12141,7 @@ whatwg-fetch@>=0.10.0: version "2.0.3" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" -whatwg-url@^6.3.0: +whatwg-url@^6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.4.0.tgz#08fdf2b9e872783a7a1f6216260a1d66cc722e08" dependencies: @@ -12309,17 +12201,6 @@ winston@2.1.x: pkginfo "0.3.x" stack-trace "0.0.x" -winston@^2.3.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/winston/-/winston-2.4.1.tgz#a3a9265105564263c6785b4583b8c8aca26fded6" - dependencies: - async "~1.0.0" - colors "1.0.x" - cycle "1.0.x" - eyes "0.1.x" - isstream "0.1.x" - stack-trace "0.0.x" - wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" @@ -12368,6 +12249,13 @@ ws@1.1.1: options ">=0.0.5" ultron "1.0.x" +ws@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-4.1.0.tgz#a979b5d7d4da68bf54efe0408967c324869a7289" + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ws@~3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" @@ -12405,9 +12293,20 @@ xhr@^2.2.0: parse-headers "^2.0.0" xtend "^4.0.0" -xml-name-validator@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + +xml2js@^0.4.17: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" xmldom@^0.1.19: version "0.1.27" @@ -12579,6 +12478,12 @@ yargs@~3.10.0: decamelize "^1.0.0" window-size "0.1.0" +yauzl@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + dependencies: + fd-slicer "~1.0.1" + yazl@^2.1.0: version "2.4.3" resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.4.3.tgz#ec26e5cc87d5601b9df8432dbdd3cd2e5173a071" From 7ccf6163fd4dda52d4c75f57cb36d1f4b05b50ea Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 2 Apr 2018 16:29:35 -0230 Subject: [PATCH 174/246] Adds simulation failure error messages to confirm screen. --- app/_locales/en/messages.json | 3 +++ .../components/pending-tx/confirm-send-ether.js | 15 +++++++++++++++ .../components/pending-tx/confirm-send-token.js | 15 +++++++++++++++ ui/app/css/itcss/components/confirm.scss | 11 +++++++++++ 4 files changed, 44 insertions(+) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 3e469cf44..34575b4dd 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -826,6 +826,9 @@ "transactions": { "message": "transactions" }, + "transactionError": { + "message": "Transaction Error. Exception thrown in contract code." + }, "transactionMemo": { "message": "Transaction memo (optional)" }, diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index eae70b279..d007e6661 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -118,6 +118,11 @@ ConfirmSendEther.prototype.updateComponentSendErrors = function (prevProps) { updateSendErrors, balance, conversionRate, + send: { + errors: { + simulationFails, + }, + }, } = this.props const txMeta = this.gatherTxMeta() @@ -132,6 +137,14 @@ ConfirmSendEther.prototype.updateComponentSendErrors = function (prevProps) { insufficientFunds: balanceIsSufficient ? false : this.context.t('insufficientFunds'), }) } + + const shouldUpdateSimulationSendError = Boolean(txMeta.simulationFails) !== Boolean(simulationFails) + + if (shouldUpdateSimulationSendError) { + updateSendErrors({ + simulationFails: !txMeta.simulationFails ? false : this.context.t('transactionError'), + }) + } } ConfirmSendEther.prototype.componentWillMount = function () { @@ -478,8 +491,10 @@ ConfirmSendEther.prototype.render = function () { ]), h('form#pending-tx-form', { + className: 'confirm-screen-form', onSubmit: this.onSubmit, }, [ + this.renderErrorMessage('simulationFails'), h('.page-container__footer', [ // Cancel Button h('button.btn-cancel.page-container__footer-button.allcaps', { diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index 814386c5c..19e591fd6 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -156,6 +156,11 @@ ConfirmSendToken.prototype.updateComponentSendErrors = function (prevProps) { updateSendErrors, balance, conversionRate, + send: { + errors: { + simulationFails, + }, + }, } = this.props const txMeta = this.gatherTxMeta() @@ -170,6 +175,14 @@ ConfirmSendToken.prototype.updateComponentSendErrors = function (prevProps) { insufficientFunds: balanceIsSufficient ? false : this.context.t('insufficientFunds'), }) } + + const shouldUpdateSimulationSendError = Boolean(txMeta.simulationFails) !== Boolean(simulationFails) + + if (shouldUpdateSimulationSendError) { + updateSendErrors({ + simulationFails: !txMeta.simulationFails ? false : this.context.t('transactionError'), + }) + } } ConfirmSendToken.prototype.componentWillMount = function () { @@ -489,8 +502,10 @@ ConfirmSendToken.prototype.render = function () { ]), h('form#pending-tx-form', { + className: 'confirm-screen-form', onSubmit: this.onSubmit, }, [ + this.renderErrorMessage('simulationFails'), h('.page-container__footer', [ // Cancel Button h('button.btn-cancel.page-container__footer-button.allcaps', { diff --git a/ui/app/css/itcss/components/confirm.scss b/ui/app/css/itcss/components/confirm.scss index 85ff14e6e..47762e8de 100644 --- a/ui/app/css/itcss/components/confirm.scss +++ b/ui/app/css/itcss/components/confirm.scss @@ -312,6 +312,17 @@ section .confirm-screen-account-number, } } +.confirm-screen-form { + position: relative; + + .confirm-screen-error { + right: 0; + width: 100%; + margin-top: 7px; + text-align: center; + } +} + .confirm-screen-confirm-button { height: 50px; border-radius: 4px; From d166cb2b1b0d8313c2b645b620d5270d9cf93b2d Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 2 Apr 2018 16:38:51 -0230 Subject: [PATCH 175/246] Ensure txParams are prefixed with 0x when sending. --- ui/app/send-v2.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index bcc5cb03d..0f2997fb2 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -635,6 +635,10 @@ SendTransactionScreen.prototype.onSubmit = function (event) { txParams.to = to } + Object.keys(txParams).forEach(key => { + txParams[key] = ethUtil.addHexPrefix(txParams[key]) + }) + selectedToken ? signTokenTx(selectedToken.address, to, amount, txParams) : signTx(txParams) From 4dd2bfade1b4c87f6dac64858028e86dd92fc671 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 12:44:13 -0700 Subject: [PATCH 176/246] lint - include old ui --- gulpfile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 1eb0a974b..e3d288276 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -209,7 +209,7 @@ gulp.task('dev:copy', gulp.task('lint', function () { // Ignoring node_modules, dist/firefox, and docs folders: - return gulp.src(['app/**/*.js', '!app/scripts/vendor/**/*.js', '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']) + return gulp.src(['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']) .pipe(eslint(fs.readFileSync(path.join(__dirname, '.eslintrc')))) // eslint.format() outputs the lint results to the console. // Alternatively use eslint.formatEach() (see Docs). @@ -220,7 +220,7 @@ gulp.task('lint', function () { }); gulp.task('lint:fix', function () { - return gulp.src(['app/**/*.js', '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']) + return gulp.src(['app/**/*.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']) .pipe(eslint(Object.assign(fs.readFileSync(path.join(__dirname, '.eslintrc')), {fix: true}))) .pipe(eslint.format()) .pipe(eslint.failAfterError()) From b7b95f269d8b1a2237bfe25e36e8a9832116a6b2 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 12:48:01 -0700 Subject: [PATCH 177/246] old-ui - lint fixes --- old-ui/app/app.js | 1 - old-ui/app/components/buy-button-subview.js | 1 - old-ui/app/components/qr-code.js | 1 - old-ui/app/components/transaction-list-item.js | 2 +- 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/old-ui/app/app.js b/old-ui/app/app.js index e9ab185f3..37611987f 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -581,7 +581,6 @@ App.prototype.renderPrimary = function () { case 'qr': log.debug('rendering show qr screen') - console.log(`QrView`, QrView); return h('div', { style: { position: 'absolute', diff --git a/old-ui/app/components/buy-button-subview.js b/old-ui/app/components/buy-button-subview.js index 843627c33..56d173839 100644 --- a/old-ui/app/components/buy-button-subview.js +++ b/old-ui/app/components/buy-button-subview.js @@ -247,7 +247,6 @@ BuyButtonSubview.prototype.backButtonContext = function () { if (this.props.context === 'confTx') { this.props.dispatch(actions.showConfTxPage(false)) } else { - console.log(`actions.goHome`, actions.goHome); this.props.dispatch(actions.goHome()) } } diff --git a/old-ui/app/components/qr-code.js b/old-ui/app/components/qr-code.js index fa38dcd92..06b9aed9b 100644 --- a/old-ui/app/components/qr-code.js +++ b/old-ui/app/components/qr-code.js @@ -25,7 +25,6 @@ function QrCodeView () { QrCodeView.prototype.render = function () { const props = this.props const Qr = props.Qr - console.log(`QrCodeView Qr`, Qr); const address = `${isHexPrefixed(Qr.data) ? 'ethereum:' : ''}${Qr.data}` const qrImage = qrCode(4, 'M') qrImage.addData(address) diff --git a/old-ui/app/components/transaction-list-item.js b/old-ui/app/components/transaction-list-item.js index f7d59005a..b9f82c668 100644 --- a/old-ui/app/components/transaction-list-item.js +++ b/old-ui/app/components/transaction-list-item.js @@ -30,7 +30,7 @@ function TransactionListItem () { TransactionListItem.prototype.showRetryButton = function () { const { transaction = {}, transactions } = this.props - const { status, submittedTime, txParams } = transaction + const { submittedTime, txParams } = transaction if (!txParams) { return false From 3f6554b637f99470bec279524e2ce35d8ef64d35 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 12:51:45 -0700 Subject: [PATCH 178/246] lint - rules - disallow 'event' global --- .eslintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc b/.eslintrc index 4fa7c2d7f..033b5512e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -41,6 +41,7 @@ }, "rules": { + "no-restricted-globals": ["error", "event"], "accessor-pairs": 2, "arrow-spacing": [2, { "before": true, "after": true }], "block-spacing": [2, "always"], From f0e4097972342ea9b8f0e40ef24a1b9ea33d1812 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 12:52:01 -0700 Subject: [PATCH 179/246] lint - remove use of 'event' global --- old-ui/app/components/range-slider.js | 4 ++-- old-ui/app/config.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/old-ui/app/components/range-slider.js b/old-ui/app/components/range-slider.js index 823f5eb01..bae740a74 100644 --- a/old-ui/app/components/range-slider.js +++ b/old-ui/app/components/range-slider.js @@ -35,7 +35,7 @@ RangeSlider.prototype.render = function () { step: increment, style: range, value: state.value || defaultValue, - onChange: mirrorInput ? this.mirrorInputs.bind(this, event) : onInput, + onChange: mirrorInput ? this.mirrorInputs.bind(this) : onInput, }), // Mirrored input for range @@ -47,7 +47,7 @@ RangeSlider.prototype.render = function () { value: state.value || defaultValue, step: increment, style: input, - onChange: this.mirrorInputs.bind(this, event), + onChange: this.mirrorInputs.bind(this), }) : null, ]) ) diff --git a/old-ui/app/config.js b/old-ui/app/config.js index 7da3694ac..508770bd4 100644 --- a/old-ui/app/config.js +++ b/old-ui/app/config.js @@ -42,7 +42,7 @@ ConfigScreen.prototype.render = function () { // subtitle and nav h('.section-title.flex-row.flex-center', [ h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { - onClick: (event) => { + onClick: () => { state.dispatch(actions.goHome()) }, }), From e8a480aac44546e6bd5d7457545bc951a8787814 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Mon, 2 Apr 2018 13:17:54 -0700 Subject: [PATCH 180/246] transactions validationt - valdate from field on txParams --- app/scripts/lib/tx-gas-utils.js | 9 ++++++++- test/unit/tx-gas-util-test.js | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js index 0fa9dd8d4..4be7738b0 100644 --- a/app/scripts/lib/tx-gas-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -100,6 +100,7 @@ module.exports = class TxGasUtil { } async validateTxParams (txParams) { + this.validateFrom(txParams) this.validateRecipient(txParams) if ('value' in txParams) { const value = txParams.value.toString() @@ -112,6 +113,12 @@ module.exports = class TxGasUtil { } } } + + validateFrom (txParams) { + if ( !(typeof txParams.from === 'string') ) throw new Error(`Invalid from address ${txParams.from} not a string`) + if (!isValidAddress(txParams.from)) throw new Error('Invalid from address') + } + validateRecipient (txParams) { if (txParams.to === '0x' || txParams.to === null ) { if (txParams.data) { @@ -124,4 +131,4 @@ module.exports = class TxGasUtil { } return txParams } -} +} \ No newline at end of file diff --git a/test/unit/tx-gas-util-test.js b/test/unit/tx-gas-util-test.js index d9a12d1c3..15d412c72 100644 --- a/test/unit/tx-gas-util-test.js +++ b/test/unit/tx-gas-util-test.js @@ -29,4 +29,28 @@ describe('Tx Gas Util', function () { } assert.throws(() => { txGasUtil.validateRecipient(zeroRecipientTxParams) }, Error, 'Invalid recipient address') }) + + it('should error when from is not a hex string', function () { + + // where from is undefined + const txParams = {} + assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`) + + // where from is array + txParams.from = [] + assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`) + + // where from is a object + txParams.from = {} + assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`) + + // where from is a invalid address + txParams.from = 'im going to fail' + assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address`) + + // should run + txParams.from ='0x1678a085c290ebd122dc42cba69373b5953b831d' + txGasUtil.validateFrom(txParams) + }) + }) From 2b6557a02473a0603752056544cd98d86143b342 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 14:47:47 -0700 Subject: [PATCH 181/246] lint - lint json files in app/ --- .eslintrc | 3 +- gulpfile.js | 6 ++- package-lock.json | 113 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 4 files changed, 120 insertions(+), 3 deletions(-) diff --git a/.eslintrc b/.eslintrc index 4fa7c2d7f..028a6dfa3 100644 --- a/.eslintrc +++ b/.eslintrc @@ -29,7 +29,8 @@ "plugins": [ "mocha", "chai", - "react" + "react", + "json" ], "globals": { diff --git a/gulpfile.js b/gulpfile.js index 1eb0a974b..fd9ab6249 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -207,9 +207,11 @@ gulp.task('dev:copy', // lint js +const lintTargets = ['app/**/*.json', 'app/**/*.js', '!app/scripts/vendor/**/*.js', '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(['app/**/*.js', '!app/scripts/vendor/**/*.js', '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']) + 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). @@ -220,7 +222,7 @@ gulp.task('lint', function () { }); gulp.task('lint:fix', function () { - return gulp.src(['app/**/*.js', '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']) + return gulp.src(lintTargets) .pipe(eslint(Object.assign(fs.readFileSync(path.join(__dirname, '.eslintrc')), {fix: true}))) .pipe(eslint.format()) .pipe(eslint.failAfterError()) diff --git a/package-lock.json b/package-lock.json index fe47f8cf9..e06499b81 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3112,6 +3112,16 @@ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.5.tgz", "integrity": "sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0=" }, + "cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "7.1.2" + } + }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -5205,6 +5215,15 @@ "integrity": "sha1-mh3qWLM1wxJCIZ0Fmzf/sUMJ9uE=", "dev": true }, + "eslint-plugin-json": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-json/-/eslint-plugin-json-1.2.0.tgz", + "integrity": "sha1-m6c7sL6Z1QCT6In1uWhGPSow764=", + "dev": true, + "requires": { + "jshint": "2.9.5" + } + }, "eslint-plugin-mocha": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-5.0.0.tgz", @@ -6269,6 +6288,12 @@ "integrity": "sha1-BmDjUlouidnkRhKUQMJy7foktSk=", "dev": true }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, "expand-braces": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", @@ -11102,6 +11127,88 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" }, + "jshint": { + "version": "2.9.5", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz", + "integrity": "sha1-HnJSkVzmgbQIJ+4UJIxG006apiw=", + "dev": true, + "requires": { + "cli": "1.0.1", + "console-browserify": "1.1.0", + "exit": "0.1.2", + "htmlparser2": "3.8.3", + "lodash": "3.7.0", + "minimatch": "3.0.4", + "shelljs": "0.3.0", + "strip-json-comments": "1.0.4" + }, + "dependencies": { + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "dev": true + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.3.0", + "domutils": "1.5.1", + "entities": "1.0.0", + "readable-stream": "1.1.14" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "lodash": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", + "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + } + } + }, "jshint-stylish": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/jshint-stylish/-/jshint-stylish-2.2.1.tgz", @@ -18862,6 +18969,12 @@ "jsonify": "0.0.0" } }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", diff --git a/package.json b/package.json index 62d703c90..8a64659ed 100644 --- a/package.json +++ b/package.json @@ -214,6 +214,7 @@ "enzyme": "^3.3.0", "enzyme-adapter-react-15": "^1.0.5", "eslint-plugin-chai": "0.0.1", + "eslint-plugin-json": "^1.2.0", "eslint-plugin-mocha": "^5.0.0", "eslint-plugin-react": "^7.4.0", "eth-json-rpc-middleware": "^1.2.7", From 9867bec17e1b9ca270bb265ee5042c5796e54dfb Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 14:49:25 -0700 Subject: [PATCH 182/246] lint - i18n - ru - lint fix --- app/_locales/ru/messages.json | 1 + 1 file changed, 1 insertion(+) diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index cd43416ad..b43251064 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -237,6 +237,7 @@ }, "downloadStateLogs": { "message": "Скачать журнал состояния" + }, "dropped": { "message": "Отброшена" }, From ab126b8c7894a0cfb8e728eeed48689200ed7a6c Mon Sep 17 00:00:00 2001 From: frankiebee Date: Mon, 2 Apr 2018 15:43:32 -0700 Subject: [PATCH 183/246] transactions gasLimit - use the block gasLimit if getCode fails --- app/scripts/controllers/transactions.js | 5 +++-- app/scripts/lib/tx-gas-utils.js | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index a18a2d2e2..31e53554d 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -187,12 +187,12 @@ module.exports = class TransactionController extends EventEmitter { // validate await this.txGasUtil.validateTxParams(txParams) // construct txMeta - const txMeta = this.txStateManager.generateTxMeta({txParams}) + let txMeta = this.txStateManager.generateTxMeta({txParams}) this.addTx(txMeta) this.emit('newUnapprovedTx', txMeta) // add default tx params try { - await this.addTxDefaults(txMeta) + txMeta = await this.addTxDefaults(txMeta) } catch (error) { console.log(error) this.txStateManager.setTxStatusFailed(txMeta.id, error) @@ -215,6 +215,7 @@ module.exports = class TransactionController extends EventEmitter { } txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16)) txParams.value = txParams.value || '0x0' + if (txParams.to === null) delete txParams.to // set gasLimit return await this.txGasUtil.analyzeGasUsage(txMeta) } diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js index 4be7738b0..829b4c421 100644 --- a/app/scripts/lib/tx-gas-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -52,7 +52,9 @@ module.exports = class TxGasUtil { // if recipient has no code, gas is 21k max: const recipient = txParams.to const hasRecipient = Boolean(recipient) - const code = await this.query.getCode(recipient) + let code + if (recipient) code = await this.query.getCode(recipient) + if (hasRecipient && (!code || code === '0x')) { txParams.gas = SIMPLE_GAS_COST txMeta.simpleSend = true // Prevents buffer addition From b58ca99b61e8332afc441a1520759578b754c424 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Mon, 2 Apr 2018 15:43:50 -0700 Subject: [PATCH 184/246] tests - fix txController tests so that txMetas have a from feild --- test/unit/tx-controller-test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js index 712097fce..6bd010e7a 100644 --- a/test/unit/tx-controller-test.js +++ b/test/unit/tx-controller-test.js @@ -162,7 +162,7 @@ describe('Transaction Controller', function () { describe('#addUnapprovedTransaction', function () { it('should add an unapproved transaction and return a valid txMeta', function (done) { - txController.addUnapprovedTransaction({}) + txController.addUnapprovedTransaction({ from: '0x1678a085c290ebd122dc42cba69373b5953b831d' }) .then((txMeta) => { assert(('id' in txMeta), 'should have a id') assert(('time' in txMeta), 'should have a time stamp') @@ -182,7 +182,7 @@ describe('Transaction Controller', function () { assert(txMetaFromEmit, 'txMeta is falsey') done() }) - txController.addUnapprovedTransaction({}) + txController.addUnapprovedTransaction({ from: '0x1678a085c290ebd122dc42cba69373b5953b831d' }) .catch(done) }) @@ -213,6 +213,7 @@ describe('Transaction Controller', function () { describe('#validateTxParams', function () { it('does not throw for positive values', function (done) { var sample = { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', value: '0x01', } txController.txGasUtil.validateTxParams(sample).then(() => { @@ -222,6 +223,7 @@ describe('Transaction Controller', function () { it('returns error for negative values', function (done) { var sample = { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', value: '-0x01', } txController.txGasUtil.validateTxParams(sample) From eb7bafc914f732ccc34a59f3e0c901dac68bef2e Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 15:50:26 -0700 Subject: [PATCH 185/246] deps - update shell-parallel --- package-lock.json | 17 ++++++++++++++--- package.json | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8cb624c58..8a2d642e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18885,6 +18885,15 @@ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" }, + "ps-tree": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.0.tgz", + "integrity": "sha1-tCGyQUDWID8e08dplrRCewjowBQ=", + "dev": true, + "requires": { + "event-stream": "3.3.4" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -20481,12 +20490,14 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, "shell-parallel": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/shell-parallel/-/shell-parallel-1.0.2.tgz", - "integrity": "sha512-GTAfqAiy37hu+H5Wd4Pz0LfjY0qs/xfLNMxAuCZAuSAVHHj+eGB8QgiC0oNWurhsG/KGliIA4GsLVP2NWoi/bA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/shell-parallel/-/shell-parallel-1.0.3.tgz", + "integrity": "sha512-h8uh4DChqYYstF2QXEyU1DaWIy0S9MaeH1HHWQfV91BV2ORJftRw3XjJtVHL9GopTpKXvTUYJ6uvcdwkxSFr9w==", "dev": true, "requires": { "once": "1.4.0", + "pify": "3.0.0", + "ps-tree": "1.1.0", "yargs": "11.0.0" }, "dependencies": { diff --git a/package.json b/package.json index cdf4a3a3f..e8f83016c 100644 --- a/package.json +++ b/package.json @@ -267,7 +267,7 @@ "redux-test-utils": "^0.2.2", "rimraf": "^2.6.2", "selenium-webdriver": "^3.5.0", - "shell-parallel": "^1.0.2", + "shell-parallel": "^1.0.3", "sinon": "^5.0.0", "stylelint-config-standard": "^18.2.0", "tape": "^4.5.1", From d5a88cdc00dba6a928a6264f8b8dfee8f50bc4a3 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 15:51:00 -0700 Subject: [PATCH 186/246] ci:screens - turn on repeat in walkthrough gif --- test/screens/new-ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/screens/new-ui.js b/test/screens/new-ui.js index f7d7ea20f..91b3a9633 100644 --- a/test/screens/new-ui.js +++ b/test/screens/new-ui.js @@ -208,7 +208,7 @@ async function captureAllScreens() { // read only the english pngs into gif const encoder = new GIFEncoder(size.width, size.height) const stream = pngFileStream('./test-artifacts/screens/* (en).png') - .pipe(encoder.createWriteStream({ repeat: -1, delay: 1000, quality: 10 })) + .pipe(encoder.createWriteStream({ repeat: 0, delay: 1000, quality: 10 })) .pipe(fs.createWriteStream('./test-artifacts/screens/walkthrough (en).gif')) // wait for end From 8d577a923b0e14b087f79a0685b65caa7958c994 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 16:25:07 -0700 Subject: [PATCH 187/246] ci - dont log unneeded env var --- development/metamaskbot-build-announce.js | 1 - 1 file changed, 1 deletion(-) diff --git a/development/metamaskbot-build-announce.js b/development/metamaskbot-build-announce.js index e867d797e..41e2796b4 100755 --- a/development/metamaskbot-build-announce.js +++ b/development/metamaskbot-build-announce.js @@ -3,7 +3,6 @@ const request = require('request-promise') const { version } = require('../dist/chrome/manifest.json') const GITHUB_COMMENT_TOKEN = process.env.GITHUB_COMMENT_TOKEN -console.log('GITHUB_COMMENT_TOKEN', GITHUB_COMMENT_TOKEN) const CIRCLE_PULL_REQUEST = process.env.CIRCLE_PULL_REQUEST console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST) const CIRCLE_SHA1 = process.env.CIRCLE_SHA1 From 0ab227d8a267c63109d671fd34509e7a417b9114 Mon Sep 17 00:00:00 2001 From: David Yoo Date: Mon, 2 Apr 2018 17:04:27 -0700 Subject: [PATCH 188/246] Address Add Token design feedback --- app/_locales/en/messages.json | 2 +- ui/app/add-token.js | 8 +++----- ui/app/css/itcss/components/add-token.scss | 10 ++++++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 34575b4dd..b372326ee 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -56,7 +56,7 @@ "message": "Balance:" }, "balances": { - "message": "Your balances" + "message": "Token balance(s)" }, "balanceIsInsufficientGas": { "message": "Insufficient balance for current gas total" diff --git a/ui/app/add-token.js b/ui/app/add-token.js index ebdd220aa..ea4f75835 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -310,9 +310,6 @@ AddTokenScreen.prototype.renderConfirmation = function () { return ( h('div.add-token', [ h('div.add-token__wrapper', [ - h('div.add-token__title-container.add-token__confirmation-title', [ - h('div.add-token__description', this.context.t('likeToAddTokens')), - ]), h('div.add-token__content-container.add-token__confirmation-content', [ h('div.add-token__description.add-token__confirmation-description', this.context.t('balances')), h('div.add-token__confirmation-token-list', @@ -390,12 +387,13 @@ AddTokenScreen.prototype.render = function () { h('span', this.context.t('cancel')), ]), h('div.add-token__header__title', this.context.t('addTokens')), + isShowingConfirmation && h('div.add-token__header__subtitle', this.context.t('likeToAddTokens')), !isShowingConfirmation && h('div.add-token__header__tabs', [ h('div.add-token__header__tabs__tab', { className: classnames('add-token__header__tabs__tab', { 'add-token__header__tabs__selected': displayedTab === 'SEARCH', - 'add-token__header__tabs__unselected cursor-pointer': displayedTab !== 'SEARCH', + 'add-token__header__tabs__unselected': displayedTab !== 'SEARCH', }), onClick: () => this.displayTab('SEARCH'), }, this.context.t('search')), @@ -403,7 +401,7 @@ AddTokenScreen.prototype.render = function () { h('div.add-token__header__tabs__tab', { className: classnames('add-token__header__tabs__tab', { 'add-token__header__tabs__selected': displayedTab === 'CUSTOM_TOKEN', - 'add-token__header__tabs__unselected cursor-pointer': displayedTab !== 'CUSTOM_TOKEN', + 'add-token__header__tabs__unselected': displayedTab !== 'CUSTOM_TOKEN', }), onClick: () => this.displayTab('CUSTOM_TOKEN'), }, this.context.t('customToken')), diff --git a/ui/app/css/itcss/components/add-token.scss b/ui/app/css/itcss/components/add-token.scss index f5c1de67c..53600d00e 100644 --- a/ui/app/css/itcss/components/add-token.scss +++ b/ui/app/css/itcss/components/add-token.scss @@ -31,7 +31,7 @@ span { font-family: Roboto; - font-size: 16px; + font-size: 16px; line-height: 21px; margin-left: 8px; } @@ -44,6 +44,11 @@ margin-top: 4px; } + &__subtitle { + margin-top: 15px; + margin-bottom: 21px; + } + &__tabs { margin-left: 22px; display: flex; @@ -65,6 +70,7 @@ &__unselected:hover { color: $black; border-bottom: none; + cursor: pointer; } &__selected { @@ -124,7 +130,7 @@ } &__confirmation-description { - margin: 12px 0; + margin: 20px 0 40px 0; } &__content-container { From 945653eb78189a3a77e11b4d87d25037310920e0 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 17:18:03 -0700 Subject: [PATCH 189/246] changelog - add note on locales --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d5d3cc1c..050b6a350 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,10 @@ ## Current Master +- (beta ui) Internationalization: Select your preferred language in the settings screen +- Internationalization: various locale improvements - Fix bug where the "Reset account" feature would not clear the network cache. - Increase maximum gas limit, to allow very gas heavy transactions, since block gas limits have been stable. -- Allow user to select language on settings page ## 4.4.0 Mon Mar 26 2018 From cbf94dad4bac9142041949cddcc038d9f22cb7f9 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Apr 2018 17:19:50 -0700 Subject: [PATCH 190/246] 4.5.0 --- CHANGELOG.md | 2 ++ app/manifest.json | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 050b6a350..d99fb5c93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +## 4.5.0 Mon Apr 02 2018 + - (beta ui) Internationalization: Select your preferred language in the settings screen - Internationalization: various locale improvements - Fix bug where the "Reset account" feature would not clear the network cache. diff --git a/app/manifest.json b/app/manifest.json index 1982b4820..73496adfa 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.4.0", + "version": "4.5.0", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", @@ -69,4 +69,4 @@ "https://metamask.io/*" ] } -} +} \ No newline at end of file From 3d2b32167b72e026a50929ba4007e67b5442b425 Mon Sep 17 00:00:00 2001 From: David Yoo Date: Mon, 2 Apr 2018 17:21:30 -0700 Subject: [PATCH 191/246] Fix tests --- test/integration/lib/add-token.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/lib/add-token.js b/test/integration/lib/add-token.js index cc04beb21..1840bdd39 100644 --- a/test/integration/lib/add-token.js +++ b/test/integration/lib/add-token.js @@ -75,7 +75,7 @@ async function runAddTokenFlowTest (assert, done) { // Confirm Add token assert.equal( $('.add-token__description')[0].textContent, - 'Would you like to add these tokens?', + 'Token balance(s)', 'confirm add token rendered' ) assert.ok($('button.btn-primary--lg')[0], 'confirm add token button found') From 4ddf5d2516acc2f2ffac3a36a7114b42d95ce4be Mon Sep 17 00:00:00 2001 From: David Yoo Date: Tue, 3 Apr 2018 09:38:27 -0700 Subject: [PATCH 192/246] Address feedback --- ui/app/add-token.js | 13 +++++++++---- ui/app/css/itcss/components/add-token.scss | 19 +++++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/ui/app/add-token.js b/ui/app/add-token.js index ea4f75835..a73874320 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -56,6 +56,7 @@ inherits(AddTokenScreen, Component) function AddTokenScreen () { this.state = { isShowingConfirmation: false, + isShowingInfoBox: true, customAddress: '', customSymbol: '', customDecimals: '', @@ -344,18 +345,22 @@ AddTokenScreen.prototype.displayTab = function (selectedTab) { } AddTokenScreen.prototype.renderTabs = function () { - const { displayedTab, errors } = this.state + const { isShowingInfoBox, displayedTab, errors } = this.state return displayedTab === 'CUSTOM_TOKEN' ? this.renderCustomForm() : h('div', [ h('div.add-token__wrapper', [ h('div.add-token__content-container', [ - h('div.add-token__info-box', [ - h('div.add-token__info-box__close'), + isShowingInfoBox && h('div.add-token__info-box', [ + h('div.add-token__info-box__close', { + onClick: () => this.setState({ isShowingInfoBox: false }), + }), h('div.add-token__info-box__title', this.context.t('whatsThis')), h('div.add-token__info-box__copy', this.context.t('keepTrackTokens')), - h('div.add-token__info-box__copy--blue', this.context.t('learnMore')), + h('a.add-token__info-box__copy--blue', { + href: 'http://metamask.helpscoutdocs.com/article/16-managing-erc20-tokens', + }, this.context.t('learnMore')), ]), h('div.add-token__input-container', [ h('input.add-token__input', { diff --git a/ui/app/css/itcss/components/add-token.scss b/ui/app/css/itcss/components/add-token.scss index 53600d00e..2fdda6f43 100644 --- a/ui/app/css/itcss/components/add-token.scss +++ b/ui/app/css/itcss/components/add-token.scss @@ -8,6 +8,7 @@ font-family: 'Roboto'; background: white; border-radius: 8px; + box-shadow: 0 0 7px 0 rgba(0, 0, 0, 0.08); &__wrapper { background-color: $white; @@ -20,7 +21,7 @@ &__header { display: flex; flex-flow: column nowrap; - padding: 16px 16px 0px; + padding: 20px 20px 0px; border-bottom: 1px solid $geyser; flex: 0 0 auto; @@ -32,6 +33,7 @@ span { font-family: Roboto; font-size: 16px; + font-weight: 400; line-height: 21px; margin-left: 8px; } @@ -45,12 +47,12 @@ } &__subtitle { + font-weight: 400; margin-top: 15px; margin-bottom: 21px; } &__tabs { - margin-left: 22px; display: flex; &__tab { @@ -59,6 +61,7 @@ color: $dusty-gray; font-family: Roboto; font-size: 18px; + font-weight: 400; line-height: 24px; text-align: center; } @@ -82,7 +85,7 @@ &__info-box { height: 96px; - margin: 20px 24px 0px; + margin: 20px 20px 0px; border-radius: 4px; background-color: $alabaster; position: relative; @@ -104,6 +107,7 @@ color: $mid-gray; font-family: Roboto; font-size: 14px; + font-weight: 400; margin-top: 15px; margin-bottom: 9px; } @@ -113,6 +117,7 @@ color: $mid-gray; font-family: Roboto; font-size: 12px; + font-weight: 400; line-height: 18px; } @@ -130,6 +135,7 @@ } &__confirmation-description { + font-weight: 400; margin: 20px 0 40px 0; } @@ -157,7 +163,7 @@ &__input, &__add-custom-input { height: 54px; - padding: 21px 6px; + padding: 0px 20px; border: 1px solid $geyser; border-radius: 4px; margin: 22px 24px; @@ -238,6 +244,7 @@ &__add-custom-label { font-size: 16px; + font-weight: 400; line-height: 21px; margin-left: 22px; color: $scorpion; @@ -280,9 +287,11 @@ color: #5B5D67; font-family: Roboto; font-size: 18px; + font-weight: 400; line-height: 24px; margin-left: 24px; margin-top: 8px; + margin-bottom: 20px; } &__token-icons-container { @@ -323,6 +332,7 @@ } &__token-name { + font-weight: 400; font-size: 14px; line-height: 19px; } @@ -374,6 +384,7 @@ &__symbol { color: $scorpion; font-size: 16px; + font-weight: 400; line-height: 24px; } } From 00657e14a8b102051157e18bbea24630ff050488 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 09:51:33 -0700 Subject: [PATCH 193/246] build - correctly set METAMASK_ENV via envify --- app/scripts/background.js | 4 ++-- app/scripts/config.js | 2 +- app/scripts/first-time-state.js | 2 +- app/scripts/inpage.js | 2 +- app/scripts/lib/setupRaven.js | 2 +- gulpfile.js | 16 +++++++--------- package.json | 3 +-- ui/app/store.js | 2 +- 8 files changed, 15 insertions(+), 18 deletions(-) diff --git a/app/scripts/background.js b/app/scripts/background.js index 7782fc41e..3ad0a7863 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -22,7 +22,7 @@ const EdgeEncryptor = require('./edge-encryptor') const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code') const STORAGE_KEY = 'metamask-config' -const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +const METAMASK_DEBUG = process.env.METAMASK_DEBUG window.log = log log.setDefaultLevel(METAMASK_DEBUG ? 'debug' : 'warn') @@ -94,7 +94,7 @@ function setupController (initState, initLangCode) { // // MetaMask Controller // - + const controller = new MetamaskController({ // User confirmation callbacks: showUnconfirmedMessage: triggerUi, diff --git a/app/scripts/config.js b/app/scripts/config.js index 74c5b576e..a8470ed82 100644 --- a/app/scripts/config.js +++ b/app/scripts/config.js @@ -13,7 +13,7 @@ const DEFAULT_RPC = 'rinkeby' const OLD_UI_NETWORK_TYPE = 'network' const BETA_UI_NETWORK_TYPE = 'networkBeta' -global.METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +global.METAMASK_DEBUG = process.env.METAMASK_DEBUG module.exports = { network: { diff --git a/app/scripts/first-time-state.js b/app/scripts/first-time-state.js index 5e8577100..3063df627 100644 --- a/app/scripts/first-time-state.js +++ b/app/scripts/first-time-state.js @@ -1,6 +1,6 @@ // test and development environment variables const env = process.env.METAMASK_ENV -const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +const METAMASK_DEBUG = process.env.METAMASK_DEBUG // // The default state of MetaMask diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index 9261e7d64..ec99bfc35 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -9,7 +9,7 @@ const setupDappAutoReload = require('./lib/auto-reload.js') const MetamaskInpageProvider = require('./lib/inpage-provider.js') restoreContextAfterImports() -const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +const METAMASK_DEBUG = process.env.METAMASK_DEBUG window.log = log log.setDefaultLevel(METAMASK_DEBUG ? 'debug' : 'warn') diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js index b93591e65..9ec9a256f 100644 --- a/app/scripts/lib/setupRaven.js +++ b/app/scripts/lib/setupRaven.js @@ -1,5 +1,5 @@ const Raven = require('raven-js') -const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +const METAMASK_DEBUG = process.env.METAMASK_DEBUG const extractEthjsErrorMessage = require('./extractEthjsErrorMessage') const PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505' const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496' diff --git a/gulpfile.js b/gulpfile.js index b71ce0703..4f0da9d60 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,5 +1,6 @@ const watchify = require('watchify') const browserify = require('browserify') +const envify = require('envify/custom') const disc = require('disc') const gulp = require('gulp') const source = require('vinyl-source-stream') @@ -377,12 +378,6 @@ gulp.task('zip:edge', zipTask('edge')) gulp.task('zip:opera', zipTask('opera')) gulp.task('zip', gulp.parallel('zip:chrome', 'zip:firefox', 'zip:edge', 'zip:opera')) -// set env for production -gulp.task('apply-prod-environment', function(done) { - process.env.NODE_ENV = 'production' - done() -}); - // high level tasks gulp.task('dev', @@ -458,7 +453,6 @@ gulp.task('build:mascara', gulp.task('dist', gulp.series( - 'apply-prod-environment', 'build', 'zip' ) @@ -484,6 +478,12 @@ function generateBundler(opts, performBundle) { let bundler = browserify(browserifyOpts) + // inject variables into bundle + bundler.transform(envify({ + METAMASK_DEBUG: opts.devMode, + NODE_ENV: opts.devMode ? 'development' : 'production', + })) + // Minification if (opts.minifyBuild) { bundler.transform('uglifyify', { @@ -557,8 +557,6 @@ function bundleTask(opts) { buildStream = buildStream // convert bundle stream to gulp vinyl stream .pipe(source(opts.filename)) - // inject variables into bundle - .pipe(replace('\'GULP_METAMASK_DEBUG\'', opts.devMode)) // buffer file contents (?) .pipe(buffer()) diff --git a/package.json b/package.json index fa91c69e4..1227b82b7 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "private": true, "scripts": { "start": "gulp dev:extension", - "mascara": "gulp dev:mascara & cross-env METAMASK_DEBUG=true node ./mascara/example/server", + "mascara": "gulp dev:mascara & node ./mascara/example/server", "dist": "gulp dist", "test": "npm run test:unit && npm run test:integration && npm run lint", "test:unit": "cross-env METAMASK_ENV=test mocha --exit --require babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"", @@ -61,7 +61,6 @@ } ], "reactify", - "envify", "brfs" ] }, diff --git a/ui/app/store.js b/ui/app/store.js index 3bafdee11..feebbabc0 100644 --- a/ui/app/store.js +++ b/ui/app/store.js @@ -4,7 +4,7 @@ const thunkMiddleware = require('redux-thunk').default const rootReducer = require('./reducers') const createLogger = require('redux-logger').createLogger -global.METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +global.METAMASK_DEBUG = process.env.METAMASK_DEBUG module.exports = configureStore From ecbab14cae659cdcec9e59dc0a3f450069a6a05f Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 10:33:10 -0700 Subject: [PATCH 194/246] app - warn on fetch errors instead of spamming sentry --- app/scripts/controllers/blacklist.js | 5 ++--- app/scripts/controllers/currency.js | 22 ++++++++++------------ app/scripts/controllers/infura.js | 18 ++++++++---------- app/scripts/controllers/shapeshift.js | 15 ++++++++------- ui/i18n-helper.js | 21 +++++++++------------ 5 files changed, 37 insertions(+), 44 deletions(-) diff --git a/app/scripts/controllers/blacklist.js b/app/scripts/controllers/blacklist.js index 33c31dab9..df41c90c0 100644 --- a/app/scripts/controllers/blacklist.js +++ b/app/scripts/controllers/blacklist.js @@ -41,9 +41,9 @@ class BlacklistController { scheduleUpdates () { if (this._phishingUpdateIntervalRef) return - this.updatePhishingList() + this.updatePhishingList().catch(log.warn) this._phishingUpdateIntervalRef = setInterval(() => { - this.updatePhishingList() + this.updatePhishingList().catch(log.warn) }, POLLING_INTERVAL) } @@ -57,4 +57,3 @@ class BlacklistController { } module.exports = BlacklistController - diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js index 930fc52e8..aca57dc71 100644 --- a/app/scripts/controllers/currency.js +++ b/app/scripts/controllers/currency.js @@ -43,20 +43,18 @@ class CurrencyController { this.store.updateState({ conversionDate }) } - updateConversionRate () { - const currentCurrency = this.getCurrentCurrency() - return fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`) - .then(response => response.json()) - .then((parsedResponse) => { + await updateConversionRate () { + try { + const currentCurrency = this.getCurrentCurrency() + const response = await fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`) + const parsedResponse = await response.json() this.setConversionRate(Number(parsedResponse.bid)) this.setConversionDate(Number(parsedResponse.timestamp)) - }).catch((err) => { - if (err) { - console.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err) - this.setConversionRate(0) - this.setConversionDate('N/A') - } - }) + } catch (err) { + console.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err) + this.setConversionRate(0) + this.setConversionDate('N/A') + } } scheduleConversionInterval () { diff --git a/app/scripts/controllers/infura.js b/app/scripts/controllers/infura.js index 10adb1004..c6b4c9de2 100644 --- a/app/scripts/controllers/infura.js +++ b/app/scripts/controllers/infura.js @@ -19,15 +19,13 @@ class InfuraController { // Responsible for retrieving the status of Infura's nodes. Can return either // ok, degraded, or down. - checkInfuraNetworkStatus () { - return fetch('https://api.infura.io/v1/status/metamask') - .then(response => response.json()) - .then((parsedResponse) => { - this.store.updateState({ - infuraNetworkStatus: parsedResponse, - }) - return parsedResponse - }) + async checkInfuraNetworkStatus () { + const response = await fetch('https://api.infura.io/v1/status/metamask') + const parsedResponse = await response.json() + this.store.updateState({ + infuraNetworkStatus: parsedResponse, + }) + return parsedResponse } scheduleInfuraNetworkCheck () { @@ -35,7 +33,7 @@ class InfuraController { clearInterval(this.conversionInterval) } this.conversionInterval = setInterval(() => { - this.checkInfuraNetworkStatus() + this.checkInfuraNetworkStatus().catch(log.warn) }, POLLING_INTERVAL) } } diff --git a/app/scripts/controllers/shapeshift.js b/app/scripts/controllers/shapeshift.js index 3d955c01f..3bbfaa1c5 100644 --- a/app/scripts/controllers/shapeshift.js +++ b/app/scripts/controllers/shapeshift.js @@ -45,18 +45,19 @@ class ShapeshiftController { }) } - updateTx (tx) { - const url = `https://shapeshift.io/txStat/${tx.depositAddress}` - return fetch(url) - .then((response) => { - return response.json() - }).then((json) => { + async updateTx (tx) { + try { + const url = `https://shapeshift.io/txStat/${tx.depositAddress}` + const response = await fetch(url) + const json = await response.json() tx.response = json if (tx.response.status === 'complete') { tx.time = new Date().getTime() } return tx - }) + } catch (err) { + log.warn(err) + } } saveTx (tx) { diff --git a/ui/i18n-helper.js b/ui/i18n-helper.js index db2fd2dc4..3eee55ae9 100644 --- a/ui/i18n-helper.js +++ b/ui/i18n-helper.js @@ -25,18 +25,15 @@ const getMessage = (locale, key, substitutions) => { return phrase } -function fetchLocale (localeName) { - return new Promise((resolve, reject) => { - return fetch(`./_locales/${localeName}/messages.json`) - .then(response => response.json()) - .then( - locale => resolve(locale), - error => { - log.error(`failed to fetch ${localeName} locale because of ${error}`) - resolve({}) - } - ) - }) +async function fetchLocale (localeName) { + try { + const response = await fetch(`./_locales/${localeName}/messages.json`) + const locale = await response.json() + return locale + } catch (error) { + log.error(`failed to fetch ${localeName} locale because of ${error}`) + return {} + } } module.exports = { From 79d63332eeb798346f5cd4af6fc4ff91372ab014 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 10:35:41 -0700 Subject: [PATCH 195/246] app - currency - fix typo --- app/scripts/controllers/currency.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js index aca57dc71..266d8ff1d 100644 --- a/app/scripts/controllers/currency.js +++ b/app/scripts/controllers/currency.js @@ -43,7 +43,7 @@ class CurrencyController { this.store.updateState({ conversionDate }) } - await updateConversionRate () { + async updateConversionRate () { try { const currentCurrency = this.getCurrentCurrency() const response = await fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`) From 038ad914541c3a4e6579da5b1ac79ba41b33cfb3 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 10:39:23 -0700 Subject: [PATCH 196/246] app - currency - fix typo + prefer log over console --- app/scripts/controllers/currency.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js index 266d8ff1d..36b8808aa 100644 --- a/app/scripts/controllers/currency.js +++ b/app/scripts/controllers/currency.js @@ -44,14 +44,15 @@ class CurrencyController { } async updateConversionRate () { + let currentCurrency try { - const currentCurrency = this.getCurrentCurrency() + currentCurrency = this.getCurrentCurrency() const response = await fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`) const parsedResponse = await response.json() this.setConversionRate(Number(parsedResponse.bid)) this.setConversionDate(Number(parsedResponse.timestamp)) } catch (err) { - console.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err) + log.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err) this.setConversionRate(0) this.setConversionDate('N/A') } From 1bedef08205921af8f3b9f7add36209782b5b313 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 11:08:17 -0700 Subject: [PATCH 197/246] ci - load npm deps by revision to always get latest for build --- .circleci/config.yml | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 14d693d7d..182cbba34 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -67,7 +67,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Install deps via npm command: npm install @@ -75,6 +75,10 @@ jobs: key: dependency-cache-{{ checksum "package-lock.json" }} paths: - node_modules + - save_cache: + key: dependency-cache-{{ .Revision }} + paths: + - node_modules prep-deps-firefox: docker: @@ -97,7 +101,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: build:dist command: npm run dist @@ -116,7 +120,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Get Scss Cache key # this allows us to checksum against a whole directory @@ -135,7 +139,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Test command: npm run lint @@ -146,7 +150,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - restore_cache: key: build-cache-{{ .Revision }} - run: @@ -162,7 +166,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - restore_cache: key: build-cache-{{ .Revision }} - run: @@ -179,7 +183,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - restore_cache: key: build-cache-{{ .Revision }} - restore_cache: @@ -203,7 +207,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: test:coverage command: npm run test:coverage @@ -225,7 +229,7 @@ jobs: && sudo mv /usr/bin/firefox /usr/bin/firefox-old && sudo ln -s /opt/firefox58/firefox /usr/bin/firefox - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Get Scss Cache key # this allows us to checksum against a whole directory @@ -244,7 +248,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Get Scss Cache key # this allows us to checksum against a whole directory @@ -272,7 +276,7 @@ jobs: && sudo mv /usr/bin/firefox /usr/bin/firefox-old && sudo ln -s /opt/firefox58/firefox /usr/bin/firefox - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Get Scss Cache key # this allows us to checksum against a whole directory @@ -291,7 +295,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Get Scss Cache key # this allows us to checksum against a whole directory From 0cedffb365c97d1309c003b8d9da096207c36fcd Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 11:11:00 -0700 Subject: [PATCH 198/246] ci - announce - add sourcemaps to artifacts --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 182cbba34..b4c17d28a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -191,6 +191,9 @@ jobs: - store_artifacts: path: dist/mascara destination: builds/mascara + - store_artifacts: + path: dist/sourcemaps + destination: builds/sourcemaps - store_artifacts: path: builds destination: builds From 6354f7459216d1b1483fce4fe8456418e68e7ec6 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 11:12:39 -0700 Subject: [PATCH 199/246] ci - rename job-announce to job-publish --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b4c17d28a..5ee699f3e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,7 +23,7 @@ workflows: requires: - prep-deps-npm - prep-build - - job-announce: + - job-publish: requires: - prep-deps-npm - prep-build @@ -177,7 +177,7 @@ jobs: paths: - test-artifacts - job-announce: + job-publish: docker: - image: circleci/node:8-browsers steps: From 3b1e4c74f5c8d503184a75584dca570187a13b8c Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 3 Apr 2018 12:14:30 -0700 Subject: [PATCH 200/246] transactions - dont throw if chain id is not a string --- app/scripts/lib/tx-state-manager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js index 23c915a61..3577d45d0 100644 --- a/app/scripts/lib/tx-state-manager.js +++ b/app/scripts/lib/tx-state-manager.js @@ -140,8 +140,8 @@ module.exports = class TransactionStateManager extends EventEmitter { validateTxParams(txParams) { Object.keys(txParams).forEach((key) => { const value = txParams[key] - if (typeof value !== 'string') throw new Error(`${key}: ${value} in txParams is not a string`) - if (!ethUtil.isHexPrefixed(value)) throw new Error('is not hex prefixed, everything on txParams must be hex prefixed') + if (typeof value !== 'string' && key !== 'chainId') throw new Error(`${key}: ${value} in txParams is not a string`) + if (!ethUtil.isHexPrefixed(value) && key !== 'chainId') throw new Error('is not hex prefixed, everything on txParams must be hex prefixed') }) } From 6029ebf0edc4ce366aaaa98bc09455c94e759c1d Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 12:33:40 -0700 Subject: [PATCH 201/246] ci - metamaskbot announce - js style change --- development/metamaskbot-build-announce.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/development/metamaskbot-build-announce.js b/development/metamaskbot-build-announce.js index 41e2796b4..d935b30a6 100755 --- a/development/metamaskbot-build-announce.js +++ b/development/metamaskbot-build-announce.js @@ -1,6 +1,6 @@ #!/usr/bin/env node const request = require('request-promise') -const { version } = require('../dist/chrome/manifest.json') +const VERSION = require('../dist/chrome/manifest.json').version const GITHUB_COMMENT_TOKEN = process.env.GITHUB_COMMENT_TOKEN const CIRCLE_PULL_REQUEST = process.env.CIRCLE_PULL_REQUEST @@ -15,10 +15,10 @@ const SHORT_SHA1 = CIRCLE_SHA1.slice(0,7) const BUILD_LINK_BASE = `https://${CIRCLE_BUILD_NUM}-42009758-gh.circle-artifacts.com/0` const MASCARA = `${BUILD_LINK_BASE}/builds/mascara/home.html` -const CHROME = `${BUILD_LINK_BASE}/builds/metamask-chrome-${version}.zip` -const FIREFOX = `${BUILD_LINK_BASE}/builds/metamask-firefox-${version}.zip` -const EDGE = `${BUILD_LINK_BASE}/builds/metamask-edge-${version}.zip` -const OPERA = `${BUILD_LINK_BASE}/builds/metamask-opera-${version}.zip` +const CHROME = `${BUILD_LINK_BASE}/builds/metamask-chrome-${VERSION}.zip` +const FIREFOX = `${BUILD_LINK_BASE}/builds/metamask-firefox-${VERSION}.zip` +const EDGE = `${BUILD_LINK_BASE}/builds/metamask-edge-${VERSION}.zip` +const OPERA = `${BUILD_LINK_BASE}/builds/metamask-opera-${VERSION}.zip` const WALKTHROUGH = `${BUILD_LINK_BASE}/test-artifacts/screens/walkthrough%20%28en%29.gif` const commentBody = ` From 92dd2b32187c6e4514823612af9259061bc0e4cb Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 12:36:46 -0700 Subject: [PATCH 202/246] ci - job-publish - publish source+sourcemaps to sentry if new release --- .circleci/config.yml | 3 ++ development/sentry-publish.js | 55 +++++++++++++++++++++++++++++++++++ package-lock.json | 8 ++--- package.json | 8 +---- 4 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 development/sentry-publish.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 5ee699f3e..ee2054130 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -203,6 +203,9 @@ jobs: - run: name: build:announce command: ./development/metamaskbot-build-announce.js + - run: + name: sentry sourcemaps upload + command: npm run sentry:publish test-unit: docker: diff --git a/development/sentry-publish.js b/development/sentry-publish.js new file mode 100644 index 000000000..ab3acabbd --- /dev/null +++ b/development/sentry-publish.js @@ -0,0 +1,55 @@ +#!/usr/bin/env node +const pify = require('pify') +const exec = pify(require('child_process').exec, { multiArgs: true }) +const VERSION = require('../dist/chrome/manifest.json').version + +start().catch(console.error) + +async function start(){ + const authWorked = await checkIfAuthWorks() + if (!authWorked) { + console.log(`Sentry auth failed...`) + } + // check if version exists or not + const versionAlreadyExists = await checkIfVersionExists() + // abort if versions exists + if (versionAlreadyExists) { + console.log(`Version "${VERSION}" already exists on Sentry, aborting sourcemap upload.`) + return + } + + // create sentry release + console.log(`creating Sentry release for "${VERSION}"...`) + await exec(`sentry-cli releases --org 'metamask' --project 'metamask' new ${VERSION}`) + console.log(`removing any existing files from Sentry release "${VERSION}"...`) + await exec(`sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} delete --all`) + // upload sentry source and sourcemaps + console.log(`uploading source files Sentry release "${VERSION}"...`) + await exec(`for FILEPATH in ./dist/chrome/*.js; do [ -e $FILEPATH ] || continue; export FILE=\`basename $FILEPATH\` && echo uploading $FILE && sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} upload $FILEPATH metamask/$FILE; done;`) + console.log(`uploading sourcemaps Sentry release "${VERSION}"...`) + await exec(`sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} upload-sourcemaps ./dist/sourcemaps/ --url-prefix 'sourcemaps'`) + console.log('all done!') +} + +async function checkIfAuthWorks() { + const itWorked = await doesNotFail(async () => { + await exec(`sentry-cli releases --org 'metamask' --project 'metamask' list`) + }) + return itWorked +} + +async function checkIfVersionExists() { + const versionAlreadyExists = await doesNotFail(async () => { + await exec(`sentry-cli releases --org 'metamask' --project 'metamask' info ${VERSION}`) + }) + return versionAlreadyExists +} + +async function doesNotFail(asyncFn) { + try { + await asyncFn() + return true + } catch (err) { + return false + } +} diff --git a/package-lock.json b/package-lock.json index 1029c507f..2c1589bec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -188,7 +188,7 @@ "integrity": "sha1-AtD3eBwe5eG+WkMSoyX76LGzcjE=", "dev": true, "requires": { - "https-proxy-agent": "2.2.0", + "https-proxy-agent": "2.2.1", "node-fetch": "1.7.3", "progress": "2.0.0", "proxy-from-env": "1.0.0" @@ -213,9 +213,9 @@ } }, "https-proxy-agent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.0.tgz", - "integrity": "sha512-uUWcfXHvy/dwfM9bqa6AozvAjS32dZSTUYd/4SEpYKRg6LEcPLshksnQYRudM9AyNvUARMfAg5TLjUDyX/K4vA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", "dev": true, "requires": { "agent-base": "4.2.0", diff --git a/package.json b/package.json index 1227b82b7..310e357ca 100644 --- a/package.json +++ b/package.json @@ -31,13 +31,7 @@ "test:mascara:build:background": "browserify mascara/src/background.js -o dist/mascara/background.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'", - "sentry": "export RELEASE=`cat app/manifest.json| jq -r .version` && npm run sentry:release && npm run sentry:upload", - "sentry:release": "npm run sentry:release:new && npm run sentry:release:clean", - "sentry:release:new": "sentry-cli releases --org 'metamask' --project 'metamask' new $RELEASE", - "sentry:release:clean": "sentry-cli releases --org 'metamask' --project 'metamask' files $RELEASE delete --all", - "sentry:upload": "npm run sentry:upload:source && npm run sentry:upload:maps", - "sentry:upload:source": "for FILEPATH in ./dist/chrome/scripts/*.js; do [ -e $FILEPATH ] || continue; export FILE=`basename $FILEPATH` && echo uploading $FILE && sentry-cli releases --org 'metamask' --project 'metamask' files $RELEASE upload $FILEPATH metamask/scripts/$FILE; done;", - "sentry:upload:maps": "sentry-cli releases --org 'metamask' --project 'metamask' files $RELEASE upload-sourcemaps ./dist/sourcemaps/ --url-prefix 'sourcemaps' --rewrite", + "sentry:publish": "node ./development/sentry-publish.js", "lint": "gulp lint", "lint:fix": "gulp lint:fix", "ui": "npm run test:flat:build:states && beefy development/ui-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./", From 502a203218066de284eecc7666bfef3ffe486a20 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 12:51:18 -0700 Subject: [PATCH 203/246] ci - metamaskbot-announce - gracefully handle missing PR --- development/metamaskbot-build-announce.js | 105 ++++++++++++---------- 1 file changed, 58 insertions(+), 47 deletions(-) diff --git a/development/metamaskbot-build-announce.js b/development/metamaskbot-build-announce.js index d935b30a6..88614ca5c 100755 --- a/development/metamaskbot-build-announce.js +++ b/development/metamaskbot-build-announce.js @@ -2,50 +2,61 @@ const request = require('request-promise') const VERSION = require('../dist/chrome/manifest.json').version -const GITHUB_COMMENT_TOKEN = process.env.GITHUB_COMMENT_TOKEN -const CIRCLE_PULL_REQUEST = process.env.CIRCLE_PULL_REQUEST -console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST) -const CIRCLE_SHA1 = process.env.CIRCLE_SHA1 -console.log('CIRCLE_SHA1', CIRCLE_SHA1) -const CIRCLE_BUILD_NUM = process.env.CIRCLE_BUILD_NUM -console.log('CIRCLE_BUILD_NUM', CIRCLE_BUILD_NUM) - -const CIRCLE_PR_NUMBER = CIRCLE_PULL_REQUEST.split('/').pop() -const SHORT_SHA1 = CIRCLE_SHA1.slice(0,7) -const BUILD_LINK_BASE = `https://${CIRCLE_BUILD_NUM}-42009758-gh.circle-artifacts.com/0` - -const MASCARA = `${BUILD_LINK_BASE}/builds/mascara/home.html` -const CHROME = `${BUILD_LINK_BASE}/builds/metamask-chrome-${VERSION}.zip` -const FIREFOX = `${BUILD_LINK_BASE}/builds/metamask-firefox-${VERSION}.zip` -const EDGE = `${BUILD_LINK_BASE}/builds/metamask-edge-${VERSION}.zip` -const OPERA = `${BUILD_LINK_BASE}/builds/metamask-opera-${VERSION}.zip` -const WALKTHROUGH = `${BUILD_LINK_BASE}/test-artifacts/screens/walkthrough%20%28en%29.gif` - -const commentBody = ` -
- - Builds ready [${SHORT_SHA1}]: - mascara, - chrome, - firefox, - edge, - opera - - -
-` - -const JSON_PAYLOAD = JSON.stringify({ body: commentBody }) -const POST_COMMENT_URI = `https://api.github.com/repos/metamask/metamask-extension/issues/${CIRCLE_PR_NUMBER}/comments` -console.log(`Announcement:\n${commentBody}`) -console.log(`Posting to: ${POST_COMMENT_URI}`) - -request({ - method: 'POST', - uri: POST_COMMENT_URI, - body: JSON_PAYLOAD, - headers: { - 'User-Agent': 'metamaskbot', - 'Authorization': `token ${GITHUB_COMMENT_TOKEN}`, - }, -}) +start().catch(console.error) + +async function start() { + + const GITHUB_COMMENT_TOKEN = process.env.GITHUB_COMMENT_TOKEN + const CIRCLE_PULL_REQUEST = process.env.CIRCLE_PULL_REQUEST + console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST) + const CIRCLE_SHA1 = process.env.CIRCLE_SHA1 + console.log('CIRCLE_SHA1', CIRCLE_SHA1) + const CIRCLE_BUILD_NUM = process.env.CIRCLE_BUILD_NUM + console.log('CIRCLE_BUILD_NUM', CIRCLE_BUILD_NUM) + + if (!CIRCLE_PULL_REQUEST) { + console.warn(`No pull request detected for commit "${CIRCLE_SHA1}"`) + return + } + + const CIRCLE_PR_NUMBER = CIRCLE_PULL_REQUEST.split('/').pop() + const SHORT_SHA1 = CIRCLE_SHA1.slice(0,7) + const BUILD_LINK_BASE = `https://${CIRCLE_BUILD_NUM}-42009758-gh.circle-artifacts.com/0` + + const MASCARA = `${BUILD_LINK_BASE}/builds/mascara/home.html` + const CHROME = `${BUILD_LINK_BASE}/builds/metamask-chrome-${VERSION}.zip` + const FIREFOX = `${BUILD_LINK_BASE}/builds/metamask-firefox-${VERSION}.zip` + const EDGE = `${BUILD_LINK_BASE}/builds/metamask-edge-${VERSION}.zip` + const OPERA = `${BUILD_LINK_BASE}/builds/metamask-opera-${VERSION}.zip` + const WALKTHROUGH = `${BUILD_LINK_BASE}/test-artifacts/screens/walkthrough%20%28en%29.gif` + + const commentBody = ` +
+ + Builds ready [${SHORT_SHA1}]: + mascara, + chrome, + firefox, + edge, + opera + + +
+ ` + + const JSON_PAYLOAD = JSON.stringify({ body: commentBody }) + const POST_COMMENT_URI = `https://api.github.com/repos/metamask/metamask-extension/issues/${CIRCLE_PR_NUMBER}/comments` + console.log(`Announcement:\n${commentBody}`) + console.log(`Posting to: ${POST_COMMENT_URI}`) + + await request({ + method: 'POST', + uri: POST_COMMENT_URI, + body: JSON_PAYLOAD, + headers: { + 'User-Agent': 'metamaskbot', + 'Authorization': `token ${GITHUB_COMMENT_TOKEN}`, + }, + }) + +} From 83df8b58ba470b6446c158789a308e801bf5becb Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 13:55:20 -0700 Subject: [PATCH 204/246] tx-state-manager - validateTxParams - validate chainId is Number --- app/scripts/lib/tx-state-manager.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js index 3577d45d0..9e597ef37 100644 --- a/app/scripts/lib/tx-state-manager.js +++ b/app/scripts/lib/tx-state-manager.js @@ -140,8 +140,16 @@ module.exports = class TransactionStateManager extends EventEmitter { validateTxParams(txParams) { Object.keys(txParams).forEach((key) => { const value = txParams[key] - if (typeof value !== 'string' && key !== 'chainId') throw new Error(`${key}: ${value} in txParams is not a string`) - if (!ethUtil.isHexPrefixed(value) && key !== 'chainId') throw new Error('is not hex prefixed, everything on txParams must be hex prefixed') + // validate types + switch (key) { + case 'chainId': + if (typeof value !== 'number') throw new Error(`${key} in txParams is not a Number. got: (${value})`) + break + default: + if (typeof value !== 'string') throw new Error(`${key} in txParams is not a string. got: (${value})`) + if (!ethUtil.isHexPrefixed(value)) throw new Error(`${key} in txParams is not hex prefixed. got: (${value})`) + break + } }) } From 27832d3e86f5d99459e4bb26996c91f52cdd115f Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 11:01:01 -0700 Subject: [PATCH 205/246] changelog - add note on fixed NODE_ENV side effects --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d99fb5c93..b01fa352d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Current Master +- Fix default network (should be mainnet not Rinkeby) +- Fix Sentry automated error reporting endpoint + ## 4.5.0 Mon Apr 02 2018 - (beta ui) Internationalization: Select your preferred language in the settings screen From 31a9fb38c8e944653ea8c087c9bca17309b8b801 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Apr 2018 14:28:30 -0700 Subject: [PATCH 206/246] 4.5.1 --- CHANGELOG.md | 2 ++ app/manifest.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b01fa352d..479e422f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +## 4.5.1 Tue Apr 03 2018 + - Fix default network (should be mainnet not Rinkeby) - Fix Sentry automated error reporting endpoint diff --git a/app/manifest.json b/app/manifest.json index 73496adfa..99305f20e 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.5.0", + "version": "4.5.1", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From 5aff114001d21696e7a7670db56b53cf3f36afa5 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 3 Apr 2018 20:34:28 -0230 Subject: [PATCH 207/246] Ensure get-first-preferred-lang-code.js matches locale codes from local directory names and chrome extension api. --- app/scripts/lib/get-first-preferred-lang-code.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/get-first-preferred-lang-code.js b/app/scripts/lib/get-first-preferred-lang-code.js index 28612f763..25221ff98 100644 --- a/app/scripts/lib/get-first-preferred-lang-code.js +++ b/app/scripts/lib/get-first-preferred-lang-code.js @@ -2,7 +2,7 @@ const extension = require('extensionizer') const promisify = require('pify') const allLocales = require('../../_locales/index.json') -const existingLocaleCodes = allLocales.map(locale => locale.code) +const existingLocaleCodes = allLocales.map(locale => locale.code.replace('_', '-')) async function getFirstPreferredLangCode () { const userPreferredLocaleCodes = await promisify( From 3c4b72bf2c5eab9c98531fcf7b0929a415b63f87 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 3 Apr 2018 20:52:17 -0230 Subject: [PATCH 208/246] Map existingLocaleCodes and userPreferredLocaleCodes to lower case in get-first-preferred-lang-code.js --- app/scripts/lib/get-first-preferred-lang-code.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/get-first-preferred-lang-code.js b/app/scripts/lib/get-first-preferred-lang-code.js index 25221ff98..e3635434e 100644 --- a/app/scripts/lib/get-first-preferred-lang-code.js +++ b/app/scripts/lib/get-first-preferred-lang-code.js @@ -2,14 +2,16 @@ const extension = require('extensionizer') const promisify = require('pify') const allLocales = require('../../_locales/index.json') -const existingLocaleCodes = allLocales.map(locale => locale.code.replace('_', '-')) +const existingLocaleCodes = allLocales.map(locale => locale.code.toLowerCase().replace('_', '-')) async function getFirstPreferredLangCode () { const userPreferredLocaleCodes = await promisify( extension.i18n.getAcceptLanguages, { errorFirst: false } )() - const firstPreferredLangCode = userPreferredLocaleCodes.find(code => existingLocaleCodes.includes(code)) + const firstPreferredLangCode = userPreferredLocaleCodes + .map(code => code.toLowerCase()) + .find(code => existingLocaleCodes.includes(code)) return firstPreferredLangCode || 'en' } From 86693af15653c5966ee7d5842bcc905e2867e925 Mon Sep 17 00:00:00 2001 From: Dan Finlay <542863+danfinlay@users.noreply.github.com> Date: Tue, 3 Apr 2018 20:33:19 -0700 Subject: [PATCH 209/246] Add webby awards to web3 block list. --- app/scripts/contentscript.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 2098fae27..fe1766273 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -131,7 +131,11 @@ function documentElementCheck () { } function blacklistedDomainCheck () { - var blacklistedDomains = ['uscourts.gov', 'dropbox.com'] + var blacklistedDomains = [ + 'uscourts.gov', + 'dropbox.com', + 'webbyawards.com', + ] var currentUrl = window.location.href var currentRegex for (let i = 0; i < blacklistedDomains.length; i++) { From 02fa5c9c32bc1aac8b6d6b1e8f5945a9b3be144a Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 4 Apr 2018 00:09:11 -0700 Subject: [PATCH 210/246] Make token helpscout link open in new tab. --- ui/app/add-token.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/app/add-token.js b/ui/app/add-token.js index a73874320..46564a5e5 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -360,6 +360,7 @@ AddTokenScreen.prototype.renderTabs = function () { h('div.add-token__info-box__copy', this.context.t('keepTrackTokens')), h('a.add-token__info-box__copy--blue', { href: 'http://metamask.helpscoutdocs.com/article/16-managing-erc20-tokens', + target: '_blank', }, this.context.t('learnMore')), ]), h('div.add-token__input-container', [ From 502011019a028258305abcb415cdba1b2530b5ad Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 4 Apr 2018 08:59:03 -0700 Subject: [PATCH 211/246] tx - txParams - allow chainId to be a hex string --- app/scripts/lib/tx-state-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js index 9e597ef37..2ab24d6a0 100644 --- a/app/scripts/lib/tx-state-manager.js +++ b/app/scripts/lib/tx-state-manager.js @@ -143,7 +143,7 @@ module.exports = class TransactionStateManager extends EventEmitter { // validate types switch (key) { case 'chainId': - if (typeof value !== 'number') throw new Error(`${key} in txParams is not a Number. got: (${value})`) + if (typeof value !== 'number' && typeof value !== 'string') throw new Error(`${key} in txParams is not a Number or hex string. got: (${value})`) break default: if (typeof value !== 'string') throw new Error(`${key} in txParams is not a string. got: (${value})`) From 6be7365dd1d41a455daf8963a35d9f75a76e9e9d Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 4 Apr 2018 09:01:19 -0700 Subject: [PATCH 212/246] changelog - add note on txParams.chainId validation change --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 479e422f2..20651dbad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Fix overly strict validation where transactions were rejected with hex encoded "chainId" + ## 4.5.1 Tue Apr 03 2018 - Fix default network (should be mainnet not Rinkeby) From 222f207b7842734b5eea79e68391ef9e19bec1fa Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 4 Apr 2018 09:10:33 -0700 Subject: [PATCH 213/246] 4.5.2 --- CHANGELOG.md | 2 ++ app/manifest.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20651dbad..95aebf37d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +## 4.5.2 Wed Apr 04 2018 + - Fix overly strict validation where transactions were rejected with hex encoded "chainId" ## 4.5.1 Tue Apr 03 2018 diff --git a/app/manifest.json b/app/manifest.json index 99305f20e..2a18bdb2d 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.5.1", + "version": "4.5.2", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From 40bbca5d0d08bd8121712656989e0464104e6903 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 4 Apr 2018 15:45:29 -0230 Subject: [PATCH 214/246] Don't prevent user from setting an eth address in to field if there is no ens support. --- ui/app/components/ens-input.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index 1f3946817..feb0a7037 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -32,10 +32,10 @@ EnsInput.prototype.render = function () { const network = this.props.network const networkHasEnsSupport = getNetworkEnsSupport(network) - if (!networkHasEnsSupport) return - props.onChange(recipient) + if (!networkHasEnsSupport) return + if (recipient.match(ensRE) === null) { return this.setState({ loadingEns: false, From 3de1873126fa4241b2b149ac35ce7eb4da506ee2 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Wed, 4 Apr 2018 13:56:39 -0700 Subject: [PATCH 215/246] hot-fix new-ui - default to an object if identities is undefined --- ui/app/components/pending-tx/confirm-send-ether.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index d007e6661..7bf20bced 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -237,6 +237,7 @@ ConfirmSendEther.prototype.getData = function () { const { identities } = this.props const txMeta = this.gatherTxMeta() const txParams = txMeta.txParams || {} + const account = identities ? identities[txParams.from] || {} : {} const { FIAT: gasFeeInFIAT, ETH: gasFeeInETH, gasFeeInHex } = this.getGasFee() const { FIAT: amountInFIAT, ETH: amountInETH } = this.getAmount() @@ -252,7 +253,7 @@ ConfirmSendEther.prototype.getData = function () { return { from: { address: txParams.from, - name: identities[txParams.from].name, + name: account.name, }, to: { address: txParams.to, From 632a0db89b0f5f1563b9e0f3f36ea9ddcf2a6cb3 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Wed, 4 Apr 2018 13:58:35 -0700 Subject: [PATCH 216/246] add to CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95aebf37d..2efd01147 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- new ui: fix the confirm transaction screen + ## 4.5.2 Wed Apr 04 2018 - Fix overly strict validation where transactions were rejected with hex encoded "chainId" From 457a47bf62272deb257e3935a62e0ed265a49d78 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Wed, 4 Apr 2018 12:25:51 -0700 Subject: [PATCH 217/246] transactions - normalize txParams --- app/scripts/controllers/transactions.js | 54 +++++++++++++++++- app/scripts/lib/tx-gas-utils.js | 35 +----------- test/unit/tx-controller-test.js | 74 ++++++++++++++++++++++++- test/unit/tx-gas-util-test.js | 42 -------------- 4 files changed, 125 insertions(+), 80 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 31e53554d..9568fcbb9 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -185,7 +185,8 @@ module.exports = class TransactionController extends EventEmitter { async addUnapprovedTransaction (txParams) { // validate - await this.txGasUtil.validateTxParams(txParams) + await this._validateTxParams(txParams) + this._normalizeTxParams(txParams) // construct txMeta let txMeta = this.txStateManager.generateTxMeta({txParams}) this.addTx(txMeta) @@ -215,7 +216,6 @@ module.exports = class TransactionController extends EventEmitter { } txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16)) txParams.value = txParams.value || '0x0' - if (txParams.to === null) delete txParams.to // set gasLimit return await this.txGasUtil.analyzeGasUsage(txMeta) } @@ -314,6 +314,56 @@ module.exports = class TransactionController extends EventEmitter { // PRIVATE METHODS // + _normalizeTxParams (txParams) { + delete txParams.chainId + + if ( !txParams.to ) delete txParams.to + else txParams.to = ethUtil.addHexPrefix(txParams.to) + + txParams.from = ethUtil.addHexPrefix(txParams.from).toLowerCase() + + if (!txParams.data) delete txParams.data + else txParams.data = ethUtil.addHexPrefix(txParams.data) + + if (txParams.value) txParams.value = ethUtil.addHexPrefix(txParams.value) + + if (txParams.gas) txParams.gas = ethUtil.addHexPrefix(txParams.gas) + if (txParams.gasPrice) txParams.gas = ethUtil.addHexPrefix(txParams.gas) + } + + async _validateTxParams (txParams) { + this._validateFrom(txParams) + this._validateRecipient(txParams) + if ('value' in txParams) { + const value = txParams.value.toString() + if (value.includes('-')) { + throw new Error(`Invalid transaction value of ${txParams.value} not a positive number.`) + } + + if (value.includes('.')) { + throw new Error(`Invalid transaction value of ${txParams.value} number must be in wei`) + } + } + } + + _validateFrom (txParams) { + if ( !(typeof txParams.from === 'string') ) throw new Error(`Invalid from address ${txParams.from} not a string`) + if (!ethUtil.isValidAddress(txParams.from)) throw new Error('Invalid from address') + } + + _validateRecipient (txParams) { + if (txParams.to === '0x' || txParams.to === null ) { + if (txParams.data) { + delete txParams.to + } else { + throw new Error('Invalid recipient address') + } + } else if ( txParams.to !== undefined && !ethUtil.isValidAddress(txParams.to) ) { + throw new Error('Invalid recipient address') + } + return txParams + } + _markNonceDuplicatesDropped (txId) { this.txStateManager.setTxStatusConfirmed(txId) // get the confirmed transactions nonce and from address diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js index 829b4c421..c579e462a 100644 --- a/app/scripts/lib/tx-gas-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -4,7 +4,7 @@ const { BnMultiplyByFraction, bnToHex, } = require('./util') -const { addHexPrefix, isValidAddress } = require('ethereumjs-util') +const { addHexPrefix } = require('ethereumjs-util') const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send. /* @@ -100,37 +100,4 @@ module.exports = class TxGasUtil { // otherwise use blockGasLimit return bnToHex(upperGasLimitBn) } - - async validateTxParams (txParams) { - this.validateFrom(txParams) - this.validateRecipient(txParams) - if ('value' in txParams) { - const value = txParams.value.toString() - if (value.includes('-')) { - throw new Error(`Invalid transaction value of ${txParams.value} not a positive number.`) - } - - if (value.includes('.')) { - throw new Error(`Invalid transaction value of ${txParams.value} number must be in wei`) - } - } - } - - validateFrom (txParams) { - if ( !(typeof txParams.from === 'string') ) throw new Error(`Invalid from address ${txParams.from} not a string`) - if (!isValidAddress(txParams.from)) throw new Error('Invalid from address') - } - - validateRecipient (txParams) { - if (txParams.to === '0x' || txParams.to === null ) { - if (txParams.data) { - delete txParams.to - } else { - throw new Error('Invalid recipient address') - } - } else if ( txParams.to !== undefined && !isValidAddress(txParams.to) ) { - throw new Error('Invalid recipient address') - } - return txParams - } } \ No newline at end of file diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js index 6bd010e7a..81d32ae29 100644 --- a/test/unit/tx-controller-test.js +++ b/test/unit/tx-controller-test.js @@ -216,7 +216,7 @@ describe('Transaction Controller', function () { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', value: '0x01', } - txController.txGasUtil.validateTxParams(sample).then(() => { + txController._validateTxParams(sample).then(() => { done() }).catch(done) }) @@ -226,7 +226,7 @@ describe('Transaction Controller', function () { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', value: '-0x01', } - txController.txGasUtil.validateTxParams(sample) + txController._validateTxParams(sample) .then(() => done('expected to thrown on negativity values but didn\'t')) .catch((err) => { assert.ok(err, 'error') @@ -235,6 +235,76 @@ describe('Transaction Controller', function () { }) }) + describe('#_normalizeTxParams', () => { + it('should normalize txParams', () => { + let txParams = { + chainId: '0x1', + from: 'a7df1beDBF813f57096dF77FCd515f0B3900e402', + to: null, + data: '68656c6c6f20776f726c64', + } + + txController._normalizeTxParams(txParams) + + assert(!txParams.chainId, 'their should be no chainId') + assert(!txParams.to, 'their should be no to address if null') + assert.equal(txParams.from.slice(0, 2), '0x', 'from should be hexPrefixd') + assert.equal(txParams.data.slice(0, 2), '0x', 'data should be hexPrefixd') + + txParams.to = 'a7df1beDBF813f57096dF77FCd515f0B3900e402' + + txController._normalizeTxParams(txParams) + assert.equal(txParams.to.slice(0, 2), '0x', 'to should be hexPrefixd') + + }) + }) + + describe('#_validateRecipient', () => { + it('removes recipient for txParams with 0x when contract data is provided', function () { + const zeroRecipientandDataTxParams = { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + to: '0x', + data: 'bytecode', + } + const sanitizedTxParams = txController._validateRecipient(zeroRecipientandDataTxParams) + assert.deepEqual(sanitizedTxParams, { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', data: 'bytecode' }, 'no recipient with 0x') + }) + + it('should error when recipient is 0x', function () { + const zeroRecipientTxParams = { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + to: '0x', + } + assert.throws(() => { txController._validateRecipient(zeroRecipientTxParams) }, Error, 'Invalid recipient address') + }) + }) + + + describe('#_validateFrom', () => { + it('should error when from is not a hex string', function () { + + // where from is undefined + const txParams = {} + assert.throws(() => { txController._validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`) + + // where from is array + txParams.from = [] + assert.throws(() => { txController._validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`) + + // where from is a object + txParams.from = {} + assert.throws(() => { txController._validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`) + + // where from is a invalid address + txParams.from = 'im going to fail' + assert.throws(() => { txController._validateFrom(txParams) }, Error, `Invalid from address`) + + // should run + txParams.from ='0x1678a085c290ebd122dc42cba69373b5953b831d' + txController._validateFrom(txParams) + }) + }) + describe('#addTx', function () { it('should emit updates', function (done) { const txMeta = { diff --git a/test/unit/tx-gas-util-test.js b/test/unit/tx-gas-util-test.js index 15d412c72..40ea8a7d6 100644 --- a/test/unit/tx-gas-util-test.js +++ b/test/unit/tx-gas-util-test.js @@ -11,46 +11,4 @@ describe('Tx Gas Util', function () { provider, }) }) - - it('removes recipient for txParams with 0x when contract data is provided', function () { - const zeroRecipientandDataTxParams = { - from: '0x1678a085c290ebd122dc42cba69373b5953b831d', - to: '0x', - data: 'bytecode', - } - const sanitizedTxParams = txGasUtil.validateRecipient(zeroRecipientandDataTxParams) - assert.deepEqual(sanitizedTxParams, { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', data: 'bytecode' }, 'no recipient with 0x') - }) - - it('should error when recipient is 0x', function () { - const zeroRecipientTxParams = { - from: '0x1678a085c290ebd122dc42cba69373b5953b831d', - to: '0x', - } - assert.throws(() => { txGasUtil.validateRecipient(zeroRecipientTxParams) }, Error, 'Invalid recipient address') - }) - - it('should error when from is not a hex string', function () { - - // where from is undefined - const txParams = {} - assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`) - - // where from is array - txParams.from = [] - assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`) - - // where from is a object - txParams.from = {} - assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`) - - // where from is a invalid address - txParams.from = 'im going to fail' - assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address`) - - // should run - txParams.from ='0x1678a085c290ebd122dc42cba69373b5953b831d' - txGasUtil.validateFrom(txParams) - }) - }) From 8243824c6af97e9b4d44f47b783d789fcf734705 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Wed, 4 Apr 2018 14:22:46 -0700 Subject: [PATCH 218/246] hot-fix - migrate unaproved txParams so that the from is lowercase --- app/scripts/migrations/024.js | 45 ++++++++++++++++++++++++++++++++ app/scripts/migrations/index.js | 1 + test/unit/migrations/024-test.js | 37 ++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 app/scripts/migrations/024.js create mode 100644 test/unit/migrations/024-test.js diff --git a/app/scripts/migrations/024.js b/app/scripts/migrations/024.js new file mode 100644 index 000000000..7a0391805 --- /dev/null +++ b/app/scripts/migrations/024.js @@ -0,0 +1,45 @@ + +const version = 24 + +/* + +This migration ensures that the from address in txParams is to lower case for +all unapproved transactions + +*/ + +const clone = require('clone') + +module.exports = { + version, + + migrate: function (originalVersionedData) { + const versionedData = clone(originalVersionedData) + versionedData.meta.version = version + try { + const state = versionedData.data + const newState = transformState(state) + versionedData.data = newState + } catch (err) { + console.warn(`MetaMask Migration #${version}` + err.stack) + } + return Promise.resolve(versionedData) + }, +} + +function transformState (state) { + const newState = state + const transactions = newState.TransactionController.transactions + + newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => { + if ( + txMeta.status === 'unapproved' && + txMeta.txParams && + txMeta.txParams.from + ) { + txMeta.txParams.from = txMeta.txParams.from.toLowerCase() + } + return txMeta + }) + return newState +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 811e06b6b..7e4542740 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -34,4 +34,5 @@ module.exports = [ require('./021'), require('./022'), require('./023'), + require('./024'), ] diff --git a/test/unit/migrations/024-test.js b/test/unit/migrations/024-test.js new file mode 100644 index 000000000..dab77d4e4 --- /dev/null +++ b/test/unit/migrations/024-test.js @@ -0,0 +1,37 @@ +const assert = require('assert') +const migration24 = require('../../../app/scripts/migrations/024') +const properTime = (new Date()).getTime() +const storage = { + "meta": {}, + "data": { + "TransactionController": { + "transactions": [ + ] + }, + }, +} + +const transactions = [] + + +while (transactions.length <= 10) { + transactions.push({ txParams: { from: '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675' }, status: 'unapproved' }) + transactions.push({ txParams: { from: '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675' }, status: 'confirmed' }) +} + + +storage.data.TransactionController.transactions = transactions + +describe('storage is migrated successfully and the txParams.from are lowercase', () => { + it('should lowercase the from for unapproved txs', (done) => { + migration24.migrate(storage) + .then((migratedData) => { + const migratedTransactions = migratedData.data.TransactionController.transactions + migratedTransactions.forEach((tx) => { + if (tx.status === 'unapproved') assert.equal(tx.txParams.from, '0x8acce2391c0d510a6c5e5d8f819a678f79b7e675') + else assert.equal(tx.txParams.from, '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675') + }) + done() + }).catch(done) + }) +}) From ef21af29f2df31cdd193823e3dc0762a1ef571b4 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Wed, 4 Apr 2018 14:26:00 -0700 Subject: [PATCH 219/246] add to CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 479e422f2..66483df67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Fix bug where checksum address are messing with balance issue [#3843](https://github.com/MetaMask/metamask-extension/issues/3843) + ## 4.5.1 Tue Apr 03 2018 - Fix default network (should be mainnet not Rinkeby) From 245c01bc0fed585c4ac8ed05edf7ebe1a65de80b Mon Sep 17 00:00:00 2001 From: frankiebee Date: Wed, 4 Apr 2018 14:56:30 -0700 Subject: [PATCH 220/246] transactions - make #_validateTxParams not async and "linting" wink wink nudge nudge --- app/scripts/controllers/transactions.js | 19 ++++++++++++------- test/unit/tx-controller-test.js | 19 ++++++++----------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 9568fcbb9..a73a8b36d 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -185,7 +185,7 @@ module.exports = class TransactionController extends EventEmitter { async addUnapprovedTransaction (txParams) { // validate - await this._validateTxParams(txParams) + this._validateTxParams(txParams) this._normalizeTxParams(txParams) // construct txMeta let txMeta = this.txStateManager.generateTxMeta({txParams}) @@ -317,13 +317,18 @@ module.exports = class TransactionController extends EventEmitter { _normalizeTxParams (txParams) { delete txParams.chainId - if ( !txParams.to ) delete txParams.to - else txParams.to = ethUtil.addHexPrefix(txParams.to) - + if ( !txParams.to ) { + delete txParams.to + } else { + txParams.to = ethUtil.addHexPrefix(txParams.to) + } txParams.from = ethUtil.addHexPrefix(txParams.from).toLowerCase() - if (!txParams.data) delete txParams.data - else txParams.data = ethUtil.addHexPrefix(txParams.data) + if (!txParams.data) { + delete txParams.data + } else { + txParams.data = ethUtil.addHexPrefix(txParams.data) + } if (txParams.value) txParams.value = ethUtil.addHexPrefix(txParams.value) @@ -331,7 +336,7 @@ module.exports = class TransactionController extends EventEmitter { if (txParams.gasPrice) txParams.gas = ethUtil.addHexPrefix(txParams.gas) } - async _validateTxParams (txParams) { + _validateTxParams (txParams) { this._validateFrom(txParams) this._validateRecipient(txParams) if ('value' in txParams) { diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js index 81d32ae29..3fec9758f 100644 --- a/test/unit/tx-controller-test.js +++ b/test/unit/tx-controller-test.js @@ -210,28 +210,25 @@ describe('Transaction Controller', function () { }) }) - describe('#validateTxParams', function () { - it('does not throw for positive values', function (done) { + describe('#_validateTxParams', function () { + it('does not throw for positive values', function () { var sample = { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', value: '0x01', } - txController._validateTxParams(sample).then(() => { - done() - }).catch(done) + txController._validateTxParams(sample) }) - it('returns error for negative values', function (done) { + it('returns error for negative values', function () { var sample = { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', value: '-0x01', } - txController._validateTxParams(sample) - .then(() => done('expected to thrown on negativity values but didn\'t')) - .catch((err) => { + try { + txController._validateTxParams(sample) + } catch (err) { assert.ok(err, 'error') - done() - }) + } }) }) From db177c79f6b26c562274c4a12bf567547b4a7489 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 4 Apr 2018 15:20:25 -0700 Subject: [PATCH 221/246] 4.5.3 --- CHANGELOG.md | 2 ++ app/manifest.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae56ad2e5..f427d1e1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +## 4.5.3 Wed Apr 04 2018 + - Fix bug where checksum address are messing with balance issue [#3843](https://github.com/MetaMask/metamask-extension/issues/3843) - new ui: fix the confirm transaction screen diff --git a/app/manifest.json b/app/manifest.json index 2a18bdb2d..61d2c5b5e 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.5.2", + "version": "4.5.3", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From 18e0a7e4f98fcad3c49fecf94bcfdc9bb1b50e0f Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 4 Apr 2018 16:26:05 -0700 Subject: [PATCH 222/246] Add target=_blank exportAsFile --- old-ui/app/util.js | 1 + ui/app/util.js | 1 + 2 files changed, 2 insertions(+) diff --git a/old-ui/app/util.js b/old-ui/app/util.js index 3f8b4dcc3..30ae308d2 100644 --- a/old-ui/app/util.js +++ b/old-ui/app/util.js @@ -231,6 +231,7 @@ function exportAsFile (filename, data) { window.navigator.msSaveBlob(blob, filename) } else { const elem = window.document.createElement('a') + elem.target = "_blank" elem.href = window.URL.createObjectURL(blob) elem.download = filename document.body.appendChild(elem) diff --git a/ui/app/util.js b/ui/app/util.js index 800ccb218..0888bff0a 100644 --- a/ui/app/util.js +++ b/ui/app/util.js @@ -271,6 +271,7 @@ function exportAsFile (filename, data) { window.navigator.msSaveBlob(blob, filename) } else { const elem = window.document.createElement('a') + elem.target = "_blank" elem.href = window.URL.createObjectURL(blob) elem.download = filename document.body.appendChild(elem) From 467629217f9fd7f84790271066df476aee66be57 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 4 Apr 2018 16:34:54 -0700 Subject: [PATCH 223/246] Update Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f427d1e1e..546641db9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Fix Download State Logs button [#3791](https://github.com/MetaMask/metamask-extension/issues/3791) + ## 4.5.3 Wed Apr 04 2018 - Fix bug where checksum address are messing with balance issue [#3843](https://github.com/MetaMask/metamask-extension/issues/3843) From 4ffa74cbe6b5415b11ace8c4c2f32bce40a2e247 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 4 Apr 2018 16:42:54 -0700 Subject: [PATCH 224/246] Change double-quotes to single-quotes --- old-ui/app/util.js | 2 +- ui/app/util.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/old-ui/app/util.js b/old-ui/app/util.js index 30ae308d2..962832ce7 100644 --- a/old-ui/app/util.js +++ b/old-ui/app/util.js @@ -231,7 +231,7 @@ function exportAsFile (filename, data) { window.navigator.msSaveBlob(blob, filename) } else { const elem = window.document.createElement('a') - elem.target = "_blank" + elem.target = '_blank' elem.href = window.URL.createObjectURL(blob) elem.download = filename document.body.appendChild(elem) diff --git a/ui/app/util.js b/ui/app/util.js index 0888bff0a..bbe2bb09e 100644 --- a/ui/app/util.js +++ b/ui/app/util.js @@ -271,7 +271,7 @@ function exportAsFile (filename, data) { window.navigator.msSaveBlob(blob, filename) } else { const elem = window.document.createElement('a') - elem.target = "_blank" + elem.target = '_blank' elem.href = window.URL.createObjectURL(blob) elem.download = filename document.body.appendChild(elem) From 6ecf2c8092e11c9b467dabfad36fb61c6f80e371 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 4 Apr 2018 21:18:12 -0230 Subject: [PATCH 225/246] event object actually passed to this.createKeyringOnEnter in private-key.js --- ui/app/accounts/import/private-key.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/app/accounts/import/private-key.js b/ui/app/accounts/import/private-key.js index 006131bdc..0d2898cda 100644 --- a/ui/app/accounts/import/private-key.js +++ b/ui/app/accounts/import/private-key.js @@ -30,6 +30,7 @@ function mapDispatchToProps (dispatch) { inherits(PrivateKeyImportView, Component) function PrivateKeyImportView () { + this.createKeyringOnEnter = this.createKeyringOnEnter.bind(this) Component.call(this) } @@ -46,7 +47,7 @@ PrivateKeyImportView.prototype.render = function () { h('input.new-account-import-form__input-password', { type: 'password', id: 'private-key-box', - onKeyPress: () => this.createKeyringOnEnter(), + onKeyPress: e => this.createKeyringOnEnter(e), }), ]), From 2199b3720c9422af06fe26cf8de19b79be36987a Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 4 Apr 2018 21:52:12 -0230 Subject: [PATCH 226/246] Allow from and to address to be the same in new-ui. --- ui/app/send-v2.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index 0f2997fb2..c3b81da5b 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -254,7 +254,6 @@ SendTransactionScreen.prototype.handleToChange = function (to, nickname = '') { const { updateSendTo, updateSendErrors, - from: {address: from}, } = this.props let toError = null @@ -262,8 +261,6 @@ SendTransactionScreen.prototype.handleToChange = function (to, nickname = '') { toError = this.context.t('required') } else if (!isValidAddress(to)) { toError = this.context.t('invalidAddressRecipient') - } else if (to === from) { - toError = this.context.t('fromToSame') } updateSendTo(to, nickname) From 343f0e9e80af804f256a5fa1a55b136c8241c368 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Wed, 4 Apr 2018 20:18:44 -0700 Subject: [PATCH 227/246] transactions - remove unnecessary keys on txParams --- app/scripts/controllers/transactions.js | 12 ++++++++++++ test/unit/tx-controller-test.js | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index a73a8b36d..0b78d62f1 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -315,6 +315,18 @@ module.exports = class TransactionController extends EventEmitter { // _normalizeTxParams (txParams) { + const acceptableKeys = [ + 'from', + 'to', + 'nonce', + 'value', + 'data', + 'gas', + 'gasPrice', + ] + Object.keys(txParams).forEach((key) => { + if (!acceptableKeys.includes(key)) delete txParams[key] + }) delete txParams.chainId if ( !txParams.to ) { diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js index 3fec9758f..e552464cf 100644 --- a/test/unit/tx-controller-test.js +++ b/test/unit/tx-controller-test.js @@ -239,6 +239,7 @@ describe('Transaction Controller', function () { from: 'a7df1beDBF813f57096dF77FCd515f0B3900e402', to: null, data: '68656c6c6f20776f726c64', + random: 'hello world', } txController._normalizeTxParams(txParams) @@ -247,7 +248,7 @@ describe('Transaction Controller', function () { assert(!txParams.to, 'their should be no to address if null') assert.equal(txParams.from.slice(0, 2), '0x', 'from should be hexPrefixd') assert.equal(txParams.data.slice(0, 2), '0x', 'data should be hexPrefixd') - + assert(!('random' in txParams), 'their should be no random key in txParams') txParams.to = 'a7df1beDBF813f57096dF77FCd515f0B3900e402' txController._normalizeTxParams(txParams) From 67de7fc0cc05bbfb311fc550c953bbdf6b495ac1 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Thu, 5 Apr 2018 00:46:55 -0700 Subject: [PATCH 228/246] Bump Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f427d1e1e..d8a265817 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Current Master +- Fix link for 'Learn More' in the Add Token Screen to open to a new tab. ## 4.5.3 Wed Apr 04 2018 From 418926ffdfabe8aaefbba5abbf44ebbfd838bbfc Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Thu, 5 Apr 2018 01:04:12 -0700 Subject: [PATCH 229/246] Fix populating txParams with undefined data --- app/scripts/lib/tx-state-manager.js | 4 ++++ ui/app/send-v2.js | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js index 2ab24d6a0..d8ea17400 100644 --- a/app/scripts/lib/tx-state-manager.js +++ b/app/scripts/lib/tx-state-manager.js @@ -108,6 +108,10 @@ module.exports = class TransactionStateManager extends EventEmitter { updateTx (txMeta, note) { // validate txParams if (txMeta.txParams) { + if (typeof txMeta.txParams.data === 'undefined') { + delete txMeta.txParams.data + } + this.validateTxParams(txMeta.txParams) } diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index c3b81da5b..094743ff0 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -576,12 +576,17 @@ SendTransactionScreen.prototype.getEditedTx = function () { data, }) } else { - const data = unapprovedTxs[editingTransactionId].txParams.data + const { data } = unapprovedTxs[editingTransactionId].txParams + Object.assign(editingTx.txParams, { value: ethUtil.addHexPrefix(amount), to: ethUtil.addHexPrefix(to), data, }) + + if (typeof editingTx.txParams.data === 'undefined') { + delete editingTx.txParams.data + } } return editingTx From 4efc718074a819c15beceece5e0f08b49c8b60bb Mon Sep 17 00:00:00 2001 From: frankiebee Date: Thu, 5 Apr 2018 11:28:25 -0700 Subject: [PATCH 230/246] make migration-24 compat with first-time-state --- app/scripts/migrations/024.js | 2 +- test/unit/migrations/024-test.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/scripts/migrations/024.js b/app/scripts/migrations/024.js index 7a0391805..043b47ccc 100644 --- a/app/scripts/migrations/024.js +++ b/app/scripts/migrations/024.js @@ -29,8 +29,8 @@ module.exports = { function transformState (state) { const newState = state + if (!newState.TransactionController) return newState const transactions = newState.TransactionController.transactions - newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => { if ( txMeta.status === 'unapproved' && diff --git a/test/unit/migrations/024-test.js b/test/unit/migrations/024-test.js index dab77d4e4..c3c03d06b 100644 --- a/test/unit/migrations/024-test.js +++ b/test/unit/migrations/024-test.js @@ -1,5 +1,9 @@ const assert = require('assert') const migration24 = require('../../../app/scripts/migrations/024') +const firstTimeState = { + meta: {}, + data: require('../../../app/scripts/first-time-state'), +} const properTime = (new Date()).getTime() const storage = { "meta": {}, @@ -34,4 +38,12 @@ describe('storage is migrated successfully and the txParams.from are lowercase', done() }).catch(done) }) + + it('should migrate first time state', (done) => { + migration24.migrate(firstTimeState) + .then((migratedData) => { + assert.equal(migratedData.meta.version, 24) + done() + }).catch(done) + }) }) From c02da0f27ca4a4239ebae4cfd3348a656e258b86 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Thu, 5 Apr 2018 12:12:02 -0700 Subject: [PATCH 231/246] transactions - _normalizeTxParams will now return a new object for txParams --- app/scripts/controllers/transactions.js | 49 +++++++++---------------- test/unit/tx-controller-test.js | 18 ++++----- 2 files changed, 27 insertions(+), 40 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 0b78d62f1..336b0d8f7 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -185,10 +185,10 @@ module.exports = class TransactionController extends EventEmitter { async addUnapprovedTransaction (txParams) { // validate - this._validateTxParams(txParams) - this._normalizeTxParams(txParams) + const normalizedTxParams = this._normalizeTxParams(txParams) + this._validateTxParams(normalizedTxParams) // construct txMeta - let txMeta = this.txStateManager.generateTxMeta({txParams}) + let txMeta = this.txStateManager.generateTxMeta({ txParams: normalizedTxParams }) this.addTx(txMeta) this.emit('newUnapprovedTx', txMeta) // add default tx params @@ -315,37 +315,24 @@ module.exports = class TransactionController extends EventEmitter { // _normalizeTxParams (txParams) { - const acceptableKeys = [ - 'from', - 'to', - 'nonce', - 'value', - 'data', - 'gas', - 'gasPrice', - ] - Object.keys(txParams).forEach((key) => { - if (!acceptableKeys.includes(key)) delete txParams[key] - }) - delete txParams.chainId - - if ( !txParams.to ) { - delete txParams.to - } else { - txParams.to = ethUtil.addHexPrefix(txParams.to) + // functions that handle normalizing of that key in txParams + const whiteList = { + from: from => ethUtil.addHexPrefix(from).toLowerCase(), + to: to => ethUtil.addHexPrefix(txParams.to).toLowerCase(), + nonce: nonce => ethUtil.addHexPrefix(nonce), + value: value => ethUtil.addHexPrefix(value), + data: data => ethUtil.addHexPrefix(data), + gas: gas => ethUtil.addHexPrefix(gas), + gasPrice: gasPrice => ethUtil.addHexPrefix(gasPrice), } - txParams.from = ethUtil.addHexPrefix(txParams.from).toLowerCase() - if (!txParams.data) { - delete txParams.data - } else { - txParams.data = ethUtil.addHexPrefix(txParams.data) - } - - if (txParams.value) txParams.value = ethUtil.addHexPrefix(txParams.value) + // apply only keys in the whiteList + const normalizedTxParams = {} + Object.keys(whiteList).forEach((key) => { + if (txParams[key]) normalizedTxParams[key] = whiteList[key](txParams[key]) + }) - if (txParams.gas) txParams.gas = ethUtil.addHexPrefix(txParams.gas) - if (txParams.gasPrice) txParams.gas = ethUtil.addHexPrefix(txParams.gas) + return normalizedTxParams } _validateTxParams (txParams) { diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js index e552464cf..824574ff2 100644 --- a/test/unit/tx-controller-test.js +++ b/test/unit/tx-controller-test.js @@ -242,17 +242,17 @@ describe('Transaction Controller', function () { random: 'hello world', } - txController._normalizeTxParams(txParams) + let normalizedTxParams = txController._normalizeTxParams(txParams) - assert(!txParams.chainId, 'their should be no chainId') - assert(!txParams.to, 'their should be no to address if null') - assert.equal(txParams.from.slice(0, 2), '0x', 'from should be hexPrefixd') - assert.equal(txParams.data.slice(0, 2), '0x', 'data should be hexPrefixd') - assert(!('random' in txParams), 'their should be no random key in txParams') - txParams.to = 'a7df1beDBF813f57096dF77FCd515f0B3900e402' + assert(!normalizedTxParams.chainId, 'their should be no chainId') + assert(!normalizedTxParams.to, 'their should be no to address if null') + assert.equal(normalizedTxParams.from.slice(0, 2), '0x', 'from should be hexPrefixd') + assert.equal(normalizedTxParams.data.slice(0, 2), '0x', 'data should be hexPrefixd') + assert(!('random' in normalizedTxParams), 'their should be no random key in normalizedTxParams') - txController._normalizeTxParams(txParams) - assert.equal(txParams.to.slice(0, 2), '0x', 'to should be hexPrefixd') + txParams.to = 'a7df1beDBF813f57096dF77FCd515f0B3900e402' + normalizedTxParams = txController._normalizeTxParams(txParams) + assert.equal(normalizedTxParams.to.slice(0, 2), '0x', 'to should be hexPrefixd') }) }) From 2b880dd4e060f8f7f95afe9ff2a3e2e6d540c922 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 5 Apr 2018 13:15:08 -0700 Subject: [PATCH 232/246] migrations - report migrations errors to sentry with vault structure --- app/scripts/background.js | 20 +++++++++++++++++- app/scripts/lib/getObjStructure.js | 33 ++++++++++++++++++++++++++++++ app/scripts/lib/migrator/index.js | 24 ++++++++++++++++++---- app/scripts/migrations/024.js | 14 +++++-------- 4 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 app/scripts/lib/getObjStructure.js diff --git a/app/scripts/background.js b/app/scripts/background.js index 3ad0a7863..ec586f642 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -20,6 +20,7 @@ const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry') const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics') const EdgeEncryptor = require('./edge-encryptor') const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code') +const getObjStructure = require('./lib/getObjStructure') const STORAGE_KEY = 'metamask-config' const METAMASK_DEBUG = process.env.METAMASK_DEBUG @@ -77,6 +78,16 @@ async function loadStateFromPersistence () { diskStore.getState() || migrator.generateInitialState(firstTimeState) + // report migration errors to sentry + migrator.on('error', (err) => { + // get vault structure without secrets + const vaultStructure = getObjStructure(versionedData) + raven.captureException(err, { + // "extra" key is required by Sentry + extra: { vaultStructure }, + }) + }) + // migrate data versionedData = await migrator.migrateData(versionedData) if (!versionedData) { @@ -84,7 +95,14 @@ async function loadStateFromPersistence () { } // write to disk - if (localStore.isSupported) localStore.set(versionedData) + if (localStore.isSupported) { + localStore.set(versionedData) + } else { + // throw in setTimeout so as to not block boot + setTimeout(() => { + throw new Error('MetaMask - Localstore not supported') + }) + } // return just the data return versionedData.data diff --git a/app/scripts/lib/getObjStructure.js b/app/scripts/lib/getObjStructure.js new file mode 100644 index 000000000..3db389507 --- /dev/null +++ b/app/scripts/lib/getObjStructure.js @@ -0,0 +1,33 @@ +const clone = require('clone') + +module.exports = getObjStructure + +// This will create an object that represents the structure of the given object +// it replaces all values with the result of their type + +// { +// "data": { +// "CurrencyController": { +// "conversionDate": "number", +// "conversionRate": "number", +// "currentCurrency": "string" +// } +// } + +function getObjStructure(obj) { + const structure = clone(obj) + return deepMap(structure, (value) => { + return value === null ? 'null' : typeof value + }) +} + +function deepMap(target = {}, visit) { + Object.entries(target).forEach(([key, value]) => { + if (typeof value === 'object' && value !== null) { + target[key] = deepMap(value, visit) + } else { + target[key] = visit(value) + } + }) + return target +} diff --git a/app/scripts/lib/migrator/index.js b/app/scripts/lib/migrator/index.js index 4fd2cae92..203b2ddc9 100644 --- a/app/scripts/lib/migrator/index.js +++ b/app/scripts/lib/migrator/index.js @@ -1,6 +1,9 @@ -class Migrator { +const EventEmitter = require('events') + +class Migrator extends EventEmitter { constructor (opts = {}) { + super() const migrations = opts.migrations || [] // sort migrations by version this.migrations = migrations.sort((a, b) => a.version - b.version) @@ -12,13 +15,26 @@ class Migrator { // run all pending migrations on meta in place async migrateData (versionedData = this.generateInitialState()) { + // get all migrations that have not yet been run const pendingMigrations = this.migrations.filter(migrationIsPending) + // perform each migration for (const index in pendingMigrations) { const migration = pendingMigrations[index] - versionedData = await migration.migrate(versionedData) - if (!versionedData.data) throw new Error('Migrator - migration returned empty data') - if (versionedData.version !== undefined && versionedData.meta.version !== migration.version) throw new Error('Migrator - Migration did not update version number correctly') + try { + // attempt migration and validate + const migratedData = await migration.migrate(versionedData) + if (!migratedData.data) throw new Error('Migrator - migration returned empty data') + if (migratedData.version !== undefined && migratedData.meta.version !== migration.version) throw new Error('Migrator - Migration did not update version number correctly') + // accept the migration as good + versionedData = migratedData + } catch (err) { + // emit error instead of throw so as to not break the run (gracefully fail) + const error = new Error(`MetaMask Migration Error #${version}:\n${err.stack}`) + this.emit('error', error) + // stop migrating and use state as is + return versionedData + } } return versionedData diff --git a/app/scripts/migrations/024.js b/app/scripts/migrations/024.js index 7a0391805..c917a167c 100644 --- a/app/scripts/migrations/024.js +++ b/app/scripts/migrations/024.js @@ -13,17 +13,13 @@ const clone = require('clone') module.exports = { version, - migrate: function (originalVersionedData) { + migrate: async function (originalVersionedData) { const versionedData = clone(originalVersionedData) versionedData.meta.version = version - try { - const state = versionedData.data - const newState = transformState(state) - versionedData.data = newState - } catch (err) { - console.warn(`MetaMask Migration #${version}` + err.stack) - } - return Promise.resolve(versionedData) + const state = versionedData.data + const newState = transformState(state) + versionedData.data = newState + return versionedData }, } From 7fdf663ea7ae4b3c6bb5cdefb1f33729f5cf4422 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 5 Apr 2018 13:21:00 -0700 Subject: [PATCH 233/246] migrator - fix typo --- app/scripts/lib/migrator/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/migrator/index.js b/app/scripts/lib/migrator/index.js index 203b2ddc9..ea9af3c80 100644 --- a/app/scripts/lib/migrator/index.js +++ b/app/scripts/lib/migrator/index.js @@ -30,7 +30,7 @@ class Migrator extends EventEmitter { versionedData = migratedData } catch (err) { // emit error instead of throw so as to not break the run (gracefully fail) - const error = new Error(`MetaMask Migration Error #${version}:\n${err.stack}`) + const error = new Error(`MetaMask Migration Error #${migration.version}:\n${err.stack}`) this.emit('error', error) // stop migrating and use state as is return versionedData From ffc71ff7d2c27d419bff4ca127ed5219bf9261c3 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 5 Apr 2018 13:38:34 -0700 Subject: [PATCH 234/246] migrator - dont overwrite error stack and warn to console --- app/scripts/lib/migrator/index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/migrator/index.js b/app/scripts/lib/migrator/index.js index ea9af3c80..85c2717ea 100644 --- a/app/scripts/lib/migrator/index.js +++ b/app/scripts/lib/migrator/index.js @@ -29,9 +29,12 @@ class Migrator extends EventEmitter { // accept the migration as good versionedData = migratedData } catch (err) { + // rewrite error message to add context without clobbering stack + const originalErrorMessage = err.message + err.message = `MetaMask Migration Error #${migration.version}: ${originalErrorMessage}` + console.warn(err.stack) // emit error instead of throw so as to not break the run (gracefully fail) - const error = new Error(`MetaMask Migration Error #${migration.version}:\n${err.stack}`) - this.emit('error', error) + this.emit('error', err) // stop migrating and use state as is return versionedData } From d0c7db618d582e2866f1dc2543db3d45c049d84f Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 5 Apr 2018 14:56:39 -0700 Subject: [PATCH 235/246] Commit Metamask QA Guide --- docs/QA_Guide.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 docs/QA_Guide.md diff --git a/docs/QA_Guide.md b/docs/QA_Guide.md new file mode 100644 index 000000000..31a75f2c0 --- /dev/null +++ b/docs/QA_Guide.md @@ -0,0 +1,44 @@ +# QA Guide + +Steps to mark a full pass of QA complete. +* Browsers: Opera, Chrome, Firefox, Edge. +* OS: Ubuntu, Mac OSX, Windows +* Open Developer Console in background and popup +* Vault integrity + * create vault + * Log out + * Log in again + * Log out + * Restore from seed + * Create a second account + * Import a loose account (not related to HD Wallet) + * Import old existing vault seed phrase (pref with test Ether) + * Download State Logs, Priv key file, seed phrase file. +* Open Developer Console in background and popup +* Send Ether + * by address + * by ens name +* Web3 API Stability + * Create a contract from a Ðapp (remix) + * Load a Ðapp that reads using events/logs (ENS) + * Connect to MEW/MyCypto + * Send a transaction from any Ðapp + - MEW + - EtherDelta + - Leeroy + - Aragon + - (https://tmashuang.github.io/demo-dapp) + * Check account balances +* Token Management + * create a token with tokenfactory (http://tokenfactory.surge.sh/#/factory) + * Add that token to the token view + * Send that token to another metamask address. + * confirm the token arrived. +* Send a transaction and sign a message (https://danfinlay.github.io/js-eth-personal-sign-examples/) for each keyring type + * hd keyring + * imported keyring +* Change network from mainnet → ropesten → rinkeby → localhost +* Copy public key to clipboard +* Export private key + +* Explore changes in master, target features that have been changed and break. From 3d9af2770f063842e1ec2a92108adfb100ff3750 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 5 Apr 2018 15:04:17 -0700 Subject: [PATCH 236/246] Update --- docs/QA_Guide.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/QA_Guide.md b/docs/QA_Guide.md index 31a75f2c0..b7ef73119 100644 --- a/docs/QA_Guide.md +++ b/docs/QA_Guide.md @@ -3,7 +3,8 @@ Steps to mark a full pass of QA complete. * Browsers: Opera, Chrome, Firefox, Edge. * OS: Ubuntu, Mac OSX, Windows -* Open Developer Console in background and popup +* Load older version of MetaMask and attempt to simulate updating the extension. +* Open Developer Console in background and popup, inspect errors. * Vault integrity * create vault * Log out @@ -37,7 +38,8 @@ Steps to mark a full pass of QA complete. * Send a transaction and sign a message (https://danfinlay.github.io/js-eth-personal-sign-examples/) for each keyring type * hd keyring * imported keyring -* Change network from mainnet → ropesten → rinkeby → localhost +* Change network from mainnet → ropsten → rinkeby → localhost (ganache) +* Ganache set blocktime to simulate retryTx in MetaMask * Copy public key to clipboard * Export private key From 4e3d38b9c21a48e643da66c72adf5e4e6d2167d2 Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Thu, 5 Apr 2018 15:12:19 -0700 Subject: [PATCH 237/246] Update QA_Guide.md --- docs/QA_Guide.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/QA_Guide.md b/docs/QA_Guide.md index b7ef73119..5a6ac338c 100644 --- a/docs/QA_Guide.md +++ b/docs/QA_Guide.md @@ -15,7 +15,6 @@ Steps to mark a full pass of QA complete. * Import a loose account (not related to HD Wallet) * Import old existing vault seed phrase (pref with test Ether) * Download State Logs, Priv key file, seed phrase file. -* Open Developer Console in background and popup * Send Ether * by address * by ens name From 8ddaafd10b000b1d572ad9ef8d3af34f7fb6ae91 Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Thu, 5 Apr 2018 16:15:55 -0700 Subject: [PATCH 238/246] Update QA_Guide.md --- docs/QA_Guide.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/QA_Guide.md b/docs/QA_Guide.md index 5a6ac338c..0b7c0e023 100644 --- a/docs/QA_Guide.md +++ b/docs/QA_Guide.md @@ -5,6 +5,9 @@ Steps to mark a full pass of QA complete. * OS: Ubuntu, Mac OSX, Windows * Load older version of MetaMask and attempt to simulate updating the extension. * Open Developer Console in background and popup, inspect errors. +* Watch the state logs + * Transactions (unapproved txs -> rejected/submitted -> confirmed) + * Nonces/LocalNonces * Vault integrity * create vault * Log out From b9243cd8b9aab3f7eae07fb29f0f184e9a263ee3 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Thu, 5 Apr 2018 16:22:24 -0700 Subject: [PATCH 239/246] meta - create a migration template --- app/scripts/migrations/template.js | 29 +++++++++++++++++++++++++++ test/unit/migrations/template-test.js | 17 ++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 app/scripts/migrations/template.js create mode 100644 test/unit/migrations/template-test.js diff --git a/app/scripts/migrations/template.js b/app/scripts/migrations/template.js new file mode 100644 index 000000000..0915c6bdf --- /dev/null +++ b/app/scripts/migrations/template.js @@ -0,0 +1,29 @@ +// next version number +const version = 0 + +/* + +description of migration and what it does + +*/ + +const clone = require('clone') + +module.exports = { + version, + + migrate: async function (originalVersionedData) { + const versionedData = clone(originalVersionedData) + versionedData.meta.version = version + const state = versionedData.data + const newState = transformState(state) + versionedData.data = newState + return versionedData + }, +} + +function transformState (state) { + const newState = state + // transform state here + return newState +} diff --git a/test/unit/migrations/template-test.js b/test/unit/migrations/template-test.js new file mode 100644 index 000000000..35060e2fe --- /dev/null +++ b/test/unit/migrations/template-test.js @@ -0,0 +1,17 @@ +const assert = require('assert') +const migrationTemplate = require('../../../app/scripts/migrations/template') +const properTime = (new Date()).getTime() +const storage = { + meta: {}, + data: {}, +} + +describe('storage is migrated successfully', () => { + it('should work', (done) => { + migrationTemplate.migrate(storage) + .then((migratedData) => { + assert.equal(migratedData.meta.version, 0) + done() + }).catch(done) + }) +}) From 1ba74c1566fe67f610a730c362b3989e63787d4c Mon Sep 17 00:00:00 2001 From: frankiebee Date: Thu, 5 Apr 2018 17:49:50 -0700 Subject: [PATCH 240/246] test - run live migrations over first time state --- test/unit/migrator-test.js | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/test/unit/migrator-test.js b/test/unit/migrator-test.js index 16066fefe..9e8b59958 100644 --- a/test/unit/migrator-test.js +++ b/test/unit/migrator-test.js @@ -1,7 +1,8 @@ const assert = require('assert') const clone = require('clone') const Migrator = require('../../app/scripts/lib/migrator/') -const migrations = [ +const liveMigrations = require('../../app/scripts/migrations/') +const stubMigrations = [ { version: 1, migrate: (data) => { @@ -29,13 +30,33 @@ const migrations = [ }, ] const versionedData = {meta: {version: 0}, data: {hello: 'world'}} -describe('Migrator', () => { - const migrator = new Migrator({ migrations }) + +const firstTimeState = { + meta: { version: 0 }, + data: require('../../app/scripts/first-time-state'), +} + +describe.only('Migrator', () => { + const migrator = new Migrator({ migrations: stubMigrations }) it('migratedData version should be version 3', (done) => { + migrator.on('error', console.log) migrator.migrateData(versionedData) .then((migratedData) => { - assert.equal(migratedData.meta.version, migrations[2].version) + assert.equal(migratedData.meta.version, stubMigrations[2].version) done() }).catch(done) }) + + it('should match the last version in live migrations', (done) => { + const migrator = new Migrator({ migrations: liveMigrations }) + migrator.on('error', console.log) + migrator.migrateData(firstTimeState) + .then((migratedData) => { + console.log(migratedData) + const last = liveMigrations.length - 1 + assert.equal(migratedData.meta.version, liveMigrations[last].version) + done() + }).catch(done) + }) + }) From 7d243aacf9db9dc8e3e2e3acfc54298ffc06fe12 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Thu, 5 Apr 2018 18:05:03 -0700 Subject: [PATCH 241/246] create migration 25 --- app/scripts/migrations/025.js | 61 ++++++++++++++++++++++++++++++++ app/scripts/migrations/index.js | 1 + test/unit/migrations/025-test.js | 49 +++++++++++++++++++++++++ test/unit/migrator-test.js | 4 +-- 4 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 app/scripts/migrations/025.js create mode 100644 test/unit/migrations/025-test.js diff --git a/app/scripts/migrations/025.js b/app/scripts/migrations/025.js new file mode 100644 index 000000000..fc3b20a44 --- /dev/null +++ b/app/scripts/migrations/025.js @@ -0,0 +1,61 @@ +// next version number +const version = 25 + +/* + +normalizes txParams on unconfirmed txs + +*/ +const ethUtil = require('ethereumjs-util') +const clone = require('clone') + +module.exports = { + version, + + migrate: async function (originalVersionedData) { + const versionedData = clone(originalVersionedData) + versionedData.meta.version = version + const state = versionedData.data + const newState = transformState(state) + versionedData.data = newState + return versionedData + }, +} + +function transformState (state) { + const newState = state + + if (newState.TransactionController) { + if (newState.TransactionController.transactions) { + const transactions = newState.TransactionController.transactions + newState.TransactionController.transactions = transactions.map((txMeta) => { + if (txMeta.status !== 'unapproved') return txMeta + txMeta.txParams = normalizeTxParams(txMeta.txParams) + return txMeta + }) + } + } + + return newState +} + +function normalizeTxParams (txParams) { + // functions that handle normalizing of that key in txParams + const whiteList = { + from: from => ethUtil.addHexPrefix(from).toLowerCase(), + to: to => ethUtil.addHexPrefix(txParams.to).toLowerCase(), + nonce: nonce => ethUtil.addHexPrefix(nonce), + value: value => ethUtil.addHexPrefix(value), + data: data => ethUtil.addHexPrefix(data), + gas: gas => ethUtil.addHexPrefix(gas), + gasPrice: gasPrice => ethUtil.addHexPrefix(gasPrice), + } + + // apply only keys in the whiteList + const normalizedTxParams = {} + Object.keys(whiteList).forEach((key) => { + if (txParams[key]) normalizedTxParams[key] = whiteList[key](txParams[key]) + }) + + return normalizedTxParams +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 7e4542740..6c4a51b32 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -35,4 +35,5 @@ module.exports = [ require('./022'), require('./023'), require('./024'), + require('./025'), ] diff --git a/test/unit/migrations/025-test.js b/test/unit/migrations/025-test.js new file mode 100644 index 000000000..76c25dbb6 --- /dev/null +++ b/test/unit/migrations/025-test.js @@ -0,0 +1,49 @@ +const assert = require('assert') +const migration25 = require('../../../app/scripts/migrations/025') +const firstTimeState = { + meta: {}, + data: require('../../../app/scripts/first-time-state'), +} + +const storage = { + "meta": {}, + "data": { + "TransactionController": { + "transactions": [ + ] + }, + }, +} + +const transactions = [] + + +while (transactions.length <= 10) { + transactions.push({ txParams: { from: '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675', random: 'stuff', chainId: 2 }, status: 'unapproved' }) + transactions.push({ txParams: { from: '0x8aCce2391c0d510a6c5E5d8f819a678f79b7e675' }, status: 'confirmed' }) +} + + +storage.data.TransactionController.transactions = transactions + +describe('storage is migrated successfully and the txParams.from are lowercase', () => { + it('should lowercase the from for unapproved txs', (done) => { + migration25.migrate(storage) + .then((migratedData) => { + const migratedTransactions = migratedData.data.TransactionController.transactions + migratedTransactions.forEach((tx) => { + if (tx.status === 'unapproved') assert(!tx.txParams.random) + if (tx.status === 'unapproved') assert(!tx.txParams.chainId) + }) + done() + }).catch(done) + }) + + it('should migrate first time state', (done) => { + migration25.migrate(firstTimeState) + .then((migratedData) => { + assert.equal(migratedData.meta.version, 25) + done() + }).catch(done) + }) +}) diff --git a/test/unit/migrator-test.js b/test/unit/migrator-test.js index 9e8b59958..2bad7da51 100644 --- a/test/unit/migrator-test.js +++ b/test/unit/migrator-test.js @@ -36,10 +36,9 @@ const firstTimeState = { data: require('../../app/scripts/first-time-state'), } -describe.only('Migrator', () => { +describe('Migrator', () => { const migrator = new Migrator({ migrations: stubMigrations }) it('migratedData version should be version 3', (done) => { - migrator.on('error', console.log) migrator.migrateData(versionedData) .then((migratedData) => { assert.equal(migratedData.meta.version, stubMigrations[2].version) @@ -49,7 +48,6 @@ describe.only('Migrator', () => { it('should match the last version in live migrations', (done) => { const migrator = new Migrator({ migrations: liveMigrations }) - migrator.on('error', console.log) migrator.migrateData(firstTimeState) .then((migratedData) => { console.log(migratedData) From d4e30040a2186a1320a44f86849506729b2dafad Mon Sep 17 00:00:00 2001 From: frankiebee Date: Thu, 5 Apr 2018 19:28:53 -0700 Subject: [PATCH 242/246] migrations - back fixes --- app/scripts/migrations/013.js | 7 ++++-- app/scripts/migrations/015.js | 15 +++++++----- app/scripts/migrations/016.js | 22 +++++++++++------- app/scripts/migrations/017.js | 21 ++++++++++------- app/scripts/migrations/018.js | 39 +++++++++++++++++-------------- app/scripts/migrations/019.js | 44 +++++++++++++++++++---------------- app/scripts/migrations/022.js | 17 ++++++++------ app/scripts/migrations/023.js | 38 ++++++++++++++++-------------- test/unit/migrator-test.js | 10 +++++++- 9 files changed, 124 insertions(+), 89 deletions(-) diff --git a/app/scripts/migrations/013.js b/app/scripts/migrations/013.js index 8f11e510e..15a9b28d4 100644 --- a/app/scripts/migrations/013.js +++ b/app/scripts/migrations/013.js @@ -27,8 +27,11 @@ module.exports = { function transformState (state) { const newState = state - if (newState.config.provider.type === 'testnet') { - newState.config.provider.type = 'ropsten' + const { config } = newState + if ( config && config.provider ) { + if (config.provider.type === 'testnet') { + newState.config.provider.type = 'ropsten' + } } return newState } diff --git a/app/scripts/migrations/015.js b/app/scripts/migrations/015.js index 4b839580b..5e2f9e63b 100644 --- a/app/scripts/migrations/015.js +++ b/app/scripts/migrations/015.js @@ -28,11 +28,14 @@ module.exports = { function transformState (state) { const newState = state - const transactions = newState.TransactionController.transactions - newState.TransactionController.transactions = transactions.map((txMeta) => { - if (!txMeta.err) return txMeta - else if (txMeta.err.message === 'Gave up submitting tx.') txMeta.status = 'failed' - return txMeta - }) + const { TransactionController } = newState + if (TransactionController && TransactionController.transactions) { + const transactions = TransactionController.transactions + newState.TransactionController.transactions = transactions.map((txMeta) => { + if (!txMeta.err) return txMeta + else if (txMeta.err.message === 'Gave up submitting tx.') txMeta.status = 'failed' + return txMeta + }) + } return newState } diff --git a/app/scripts/migrations/016.js b/app/scripts/migrations/016.js index 4fc534f1c..048c7a40e 100644 --- a/app/scripts/migrations/016.js +++ b/app/scripts/migrations/016.js @@ -28,14 +28,18 @@ module.exports = { function transformState (state) { const newState = state - const transactions = newState.TransactionController.transactions - newState.TransactionController.transactions = transactions.map((txMeta) => { - if (!txMeta.err) return txMeta - if (txMeta.err === 'transaction with the same hash was already imported.') { - txMeta.status = 'submitted' - delete txMeta.err - } - return txMeta - }) + const { TransactionController } = newState + if (TransactionController && TransactionController.transactions) { + const transactions = newState.TransactionController.transactions + + newState.TransactionController.transactions = transactions.map((txMeta) => { + if (!txMeta.err) return txMeta + if (txMeta.err === 'transaction with the same hash was already imported.') { + txMeta.status = 'submitted' + delete txMeta.err + } + return txMeta + }) + } return newState } diff --git a/app/scripts/migrations/017.js b/app/scripts/migrations/017.js index 24959cd3a..5f6d906d6 100644 --- a/app/scripts/migrations/017.js +++ b/app/scripts/migrations/017.js @@ -27,14 +27,17 @@ module.exports = { function transformState (state) { const newState = state - const transactions = newState.TransactionController.transactions - newState.TransactionController.transactions = transactions.map((txMeta) => { - if (!txMeta.status === 'failed') return txMeta - if (txMeta.retryCount > 0 && txMeta.retryCount < 2) { - txMeta.status = 'submitted' - delete txMeta.err - } - return txMeta - }) + const { TransactionController } = newState + if (TransactionController && TransactionController.transactions) { + const transactions = newState.TransactionController.transactions + newState.TransactionController.transactions = transactions.map((txMeta) => { + if (!txMeta.status === 'failed') return txMeta + if (txMeta.retryCount > 0 && txMeta.retryCount < 2) { + txMeta.status = 'submitted' + delete txMeta.err + } + return txMeta + }) + } return newState } diff --git a/app/scripts/migrations/018.js b/app/scripts/migrations/018.js index d27fe3f46..bea1fe3da 100644 --- a/app/scripts/migrations/018.js +++ b/app/scripts/migrations/018.js @@ -29,24 +29,27 @@ module.exports = { function transformState (state) { const newState = state - const transactions = newState.TransactionController.transactions - newState.TransactionController.transactions = transactions.map((txMeta) => { - // no history: initialize - if (!txMeta.history || txMeta.history.length === 0) { - const snapshot = txStateHistoryHelper.snapshotFromTxMeta(txMeta) - txMeta.history = [snapshot] + const { TransactionController } = newState + if (TransactionController && TransactionController.transactions) { + const transactions = newState.TransactionController.transactions + newState.TransactionController.transactions = transactions.map((txMeta) => { + // no history: initialize + if (!txMeta.history || txMeta.history.length === 0) { + const snapshot = txStateHistoryHelper.snapshotFromTxMeta(txMeta) + txMeta.history = [snapshot] + return txMeta + } + // has history: migrate + const newHistory = ( + txStateHistoryHelper.migrateFromSnapshotsToDiffs(txMeta.history) + // remove empty diffs + .filter((entry) => { + return !Array.isArray(entry) || entry.length > 0 + }) + ) + txMeta.history = newHistory return txMeta - } - // has history: migrate - const newHistory = ( - txStateHistoryHelper.migrateFromSnapshotsToDiffs(txMeta.history) - // remove empty diffs - .filter((entry) => { - return !Array.isArray(entry) || entry.length > 0 - }) - ) - txMeta.history = newHistory - return txMeta - }) + }) + } return newState } diff --git a/app/scripts/migrations/019.js b/app/scripts/migrations/019.js index 072c96370..ce5da6859 100644 --- a/app/scripts/migrations/019.js +++ b/app/scripts/migrations/019.js @@ -29,32 +29,36 @@ module.exports = { function transformState (state) { const newState = state - const transactions = newState.TransactionController.transactions + const { TransactionController } = newState + if (TransactionController && TransactionController.transactions) { - newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => { - if (txMeta.status !== 'submitted') return txMeta + const transactions = newState.TransactionController.transactions - const confirmedTxs = txList.filter((tx) => tx.status === 'confirmed') - .filter((tx) => tx.txParams.from === txMeta.txParams.from) - .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from) - const highestConfirmedNonce = getHighestNonce(confirmedTxs) + newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => { + if (txMeta.status !== 'submitted') return txMeta - const pendingTxs = txList.filter((tx) => tx.status === 'submitted') - .filter((tx) => tx.txParams.from === txMeta.txParams.from) - .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from) - const highestContinuousNonce = getHighestContinuousFrom(pendingTxs, highestConfirmedNonce) + const confirmedTxs = txList.filter((tx) => tx.status === 'confirmed') + .filter((tx) => tx.txParams.from === txMeta.txParams.from) + .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from) + const highestConfirmedNonce = getHighestNonce(confirmedTxs) - const maxNonce = Math.max(highestContinuousNonce, highestConfirmedNonce) + const pendingTxs = txList.filter((tx) => tx.status === 'submitted') + .filter((tx) => tx.txParams.from === txMeta.txParams.from) + .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from) + const highestContinuousNonce = getHighestContinuousFrom(pendingTxs, highestConfirmedNonce) - if (parseInt(txMeta.txParams.nonce, 16) > maxNonce + 1) { - txMeta.status = 'failed' - txMeta.err = { - message: 'nonce too high', - note: 'migration 019 custom error', + const maxNonce = Math.max(highestContinuousNonce, highestConfirmedNonce) + + if (parseInt(txMeta.txParams.nonce, 16) > maxNonce + 1) { + txMeta.status = 'failed' + txMeta.err = { + message: 'nonce too high', + note: 'migration 019 custom error', + } } - } - return txMeta - }) + return txMeta + }) + } return newState } diff --git a/app/scripts/migrations/022.js b/app/scripts/migrations/022.js index c3c0d53ef..1fbe241e6 100644 --- a/app/scripts/migrations/022.js +++ b/app/scripts/migrations/022.js @@ -28,12 +28,15 @@ module.exports = { function transformState (state) { const newState = state - const transactions = newState.TransactionController.transactions - - newState.TransactionController.transactions = transactions.map((txMeta) => { - if (txMeta.status !== 'submitted' || txMeta.submittedTime) return txMeta - txMeta.submittedTime = (new Date()).getTime() - return txMeta - }) + const { TransactionController } = newState + if (TransactionController && TransactionController.transactions) { + const transactions = newState.TransactionController.transactions + + newState.TransactionController.transactions = transactions.map((txMeta) => { + if (txMeta.status !== 'submitted' || txMeta.submittedTime) return txMeta + txMeta.submittedTime = (new Date()).getTime() + return txMeta + }) + } return newState } diff --git a/app/scripts/migrations/023.js b/app/scripts/migrations/023.js index bce0a5bea..151496b06 100644 --- a/app/scripts/migrations/023.js +++ b/app/scripts/migrations/023.js @@ -28,23 +28,27 @@ module.exports = { function transformState (state) { const newState = state - const transactions = newState.TransactionController.transactions - - if (transactions.length <= 40) return newState - - let reverseTxList = transactions.reverse() - let stripping = true - while (reverseTxList.length > 40 && stripping) { - let txIndex = reverseTxList.findIndex((txMeta) => { - return (txMeta.status === 'failed' || - txMeta.status === 'rejected' || - txMeta.status === 'confirmed' || - txMeta.status === 'dropped') - }) - if (txIndex < 0) stripping = false - else reverseTxList.splice(txIndex, 1) - } - newState.TransactionController.transactions = reverseTxList.reverse() + const { TransactionController } = newState + if (TransactionController && TransactionController.transactions) { + const transactions = newState.TransactionController.transactions + + if (transactions.length <= 40) return newState + + let reverseTxList = transactions.reverse() + let stripping = true + while (reverseTxList.length > 40 && stripping) { + let txIndex = reverseTxList.findIndex((txMeta) => { + return (txMeta.status === 'failed' || + txMeta.status === 'rejected' || + txMeta.status === 'confirmed' || + txMeta.status === 'dropped') + }) + if (txIndex < 0) stripping = false + else reverseTxList.splice(txIndex, 1) + } + + newState.TransactionController.transactions = reverseTxList.reverse() + } return newState } diff --git a/test/unit/migrator-test.js b/test/unit/migrator-test.js index 2bad7da51..4404e1dc4 100644 --- a/test/unit/migrator-test.js +++ b/test/unit/migrator-test.js @@ -50,11 +50,19 @@ describe('Migrator', () => { const migrator = new Migrator({ migrations: liveMigrations }) migrator.migrateData(firstTimeState) .then((migratedData) => { - console.log(migratedData) const last = liveMigrations.length - 1 assert.equal(migratedData.meta.version, liveMigrations[last].version) done() }).catch(done) }) + it('should emit an error', function (done) { + this.timeout(15000) + const migrator = new Migrator({ migrations: [{ version: 1, migrate: async () => { throw new Error('test') } } ] }) + migrator.on('error', () => done()) + migrator.migrateData({ meta: {version: 0} }) + .then((migratedData) => { + }).catch(done) + }) + }) From 89415e40d529aaf697807846a841c5405e6dcdbd Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 5 Apr 2018 15:13:23 -0700 Subject: [PATCH 243/246] changelog - add missing entries --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4731faffc..c63d4f8f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,11 @@ # Changelog ## Current Master -- Fix link for 'Learn More' in the Add Token Screen to open to a new tab. +- Graceful handling of unknown keys in txParams +- Fix link for 'Learn More' in the Add Token Screen to open to a new tab. - Fix Download State Logs button [#3791](https://github.com/MetaMask/metamask-extension/issues/3791) +- Fix migration error reporting ## 4.5.3 Wed Apr 04 2018 From 000aa55dd32c998acaea63fbaad69bc05179acc0 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 5 Apr 2018 15:14:04 -0700 Subject: [PATCH 244/246] v4.5.4 --- CHANGELOG.md | 2 ++ app/manifest.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c63d4f8f0..815e6b7db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +## 4.5.4 Thu Apr 05 2018 + - Graceful handling of unknown keys in txParams - Fix link for 'Learn More' in the Add Token Screen to open to a new tab. - Fix Download State Logs button [#3791](https://github.com/MetaMask/metamask-extension/issues/3791) diff --git a/app/manifest.json b/app/manifest.json index 61d2c5b5e..5aa14b1e9 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.5.3", + "version": "4.5.4", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From 2953429fedf7582ac6f544b132b9f2a0e2db7580 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 6 Apr 2018 09:58:09 -0700 Subject: [PATCH 245/246] changelog - add changes for v4.5.5 --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 815e6b7db..e15ccca21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,13 @@ ## Current Master -## 4.5.4 Thu Apr 05 2018 +- Graceful handling of unknown keys in txParams +- Fixes buggy handling of historical transactions with unknown keys in txParams +- Fix link for 'Learn More' in the Add Token Screen to open to a new tab. +- Fix Download State Logs button [#3791](https://github.com/MetaMask/metamask-extension/issues/3791) +- Enhanced migration error handling + reporting + +## 4.5.4 (aborted) Thu Apr 05 2018 - Graceful handling of unknown keys in txParams - Fix link for 'Learn More' in the Add Token Screen to open to a new tab. From b91bd818c7c2aec2952036a2f69ab05e0690a06e Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 6 Apr 2018 09:58:51 -0700 Subject: [PATCH 246/246] 4.5.5 --- CHANGELOG.md | 2 ++ app/manifest.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e15ccca21..45eaa6908 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +## 4.5.5 Fri Apr 06 2018 + - Graceful handling of unknown keys in txParams - Fixes buggy handling of historical transactions with unknown keys in txParams - Fix link for 'Learn More' in the Add Token Screen to open to a new tab. diff --git a/app/manifest.json b/app/manifest.json index 5aa14b1e9..dc46f1ca4 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.5.4", + "version": "4.5.5", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__",