feature/default_network_editable
Alexander Tseung 7 years ago
commit 34e608e9dc
  1. 38
      .circleci/config.yml
  2. 5
      CHANGELOG.md
  3. 2
      app/_locales/en/messages.json
  4. 2
      app/manifest.json
  5. 4
      app/scripts/background.js
  6. 2
      app/scripts/config.js
  7. 5
      app/scripts/controllers/blacklist.js
  8. 23
      app/scripts/controllers/currency.js
  9. 18
      app/scripts/controllers/infura.js
  10. 15
      app/scripts/controllers/shapeshift.js
  11. 2
      app/scripts/first-time-state.js
  12. 2
      app/scripts/inpage.js
  13. 2
      app/scripts/lib/setupRaven.js
  14. 12
      app/scripts/lib/tx-state-manager.js
  15. 109
      development/metamaskbot-build-announce.js
  16. 55
      development/sentry-publish.js
  17. 16
      gulpfile.js
  18. 8
      package-lock.json
  19. 11
      package.json
  20. 2
      test/integration/lib/add-token.js
  21. 21
      ui/app/components/pages/add-token.js
  22. 29
      ui/app/css/itcss/components/add-token.scss
  23. 2
      ui/app/store.js
  24. 21
      ui/i18n-helper.js

@ -23,7 +23,7 @@ workflows:
requires: requires:
- prep-deps-npm - prep-deps-npm
- prep-build - prep-build
- job-announce: - job-publish:
requires: requires:
- prep-deps-npm - prep-deps-npm
- prep-build - prep-build
@ -67,7 +67,7 @@ jobs:
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ .Revision }}
- run: - run:
name: Install deps via npm name: Install deps via npm
command: npm install command: npm install
@ -75,6 +75,10 @@ jobs:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ checksum "package-lock.json" }}
paths: paths:
- node_modules - node_modules
- save_cache:
key: dependency-cache-{{ .Revision }}
paths:
- node_modules
prep-deps-firefox: prep-deps-firefox:
docker: docker:
@ -97,7 +101,7 @@ jobs:
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ .Revision }}
- run: - run:
name: build:dist name: build:dist
command: npm run dist command: npm run dist
@ -116,7 +120,7 @@ jobs:
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ .Revision }}
- run: - run:
name: Get Scss Cache key name: Get Scss Cache key
# this allows us to checksum against a whole directory # this allows us to checksum against a whole directory
@ -135,7 +139,7 @@ jobs:
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ .Revision }}
- run: - run:
name: Test name: Test
command: npm run lint command: npm run lint
@ -146,7 +150,7 @@ jobs:
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ .Revision }}
- restore_cache: - restore_cache:
key: build-cache-{{ .Revision }} key: build-cache-{{ .Revision }}
- run: - run:
@ -162,7 +166,7 @@ jobs:
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ .Revision }}
- restore_cache: - restore_cache:
key: build-cache-{{ .Revision }} key: build-cache-{{ .Revision }}
- run: - run:
@ -173,13 +177,13 @@ jobs:
paths: paths:
- test-artifacts - test-artifacts
job-announce: job-publish:
docker: docker:
- image: circleci/node:8-browsers - image: circleci/node:8-browsers
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ .Revision }}
- restore_cache: - restore_cache:
key: build-cache-{{ .Revision }} key: build-cache-{{ .Revision }}
- restore_cache: - restore_cache:
@ -187,6 +191,9 @@ jobs:
- store_artifacts: - store_artifacts:
path: dist/mascara path: dist/mascara
destination: builds/mascara destination: builds/mascara
- store_artifacts:
path: dist/sourcemaps
destination: builds/sourcemaps
- store_artifacts: - store_artifacts:
path: builds path: builds
destination: builds destination: builds
@ -196,6 +203,9 @@ jobs:
- run: - run:
name: build:announce name: build:announce
command: ./development/metamaskbot-build-announce.js command: ./development/metamaskbot-build-announce.js
- run:
name: sentry sourcemaps upload
command: npm run sentry:publish
test-unit: test-unit:
docker: docker:
@ -203,7 +213,7 @@ jobs:
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ .Revision }}
- run: - run:
name: test:coverage name: test:coverage
command: npm run test:coverage command: npm run test:coverage
@ -225,7 +235,7 @@ jobs:
&& sudo mv /usr/bin/firefox /usr/bin/firefox-old && sudo mv /usr/bin/firefox /usr/bin/firefox-old
&& sudo ln -s /opt/firefox58/firefox /usr/bin/firefox && sudo ln -s /opt/firefox58/firefox /usr/bin/firefox
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ .Revision }}
- run: - run:
name: Get Scss Cache key name: Get Scss Cache key
# this allows us to checksum against a whole directory # this allows us to checksum against a whole directory
@ -244,7 +254,7 @@ jobs:
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ .Revision }}
- run: - run:
name: Get Scss Cache key name: Get Scss Cache key
# this allows us to checksum against a whole directory # this allows us to checksum against a whole directory
@ -272,7 +282,7 @@ jobs:
&& sudo mv /usr/bin/firefox /usr/bin/firefox-old && sudo mv /usr/bin/firefox /usr/bin/firefox-old
&& sudo ln -s /opt/firefox58/firefox /usr/bin/firefox && sudo ln -s /opt/firefox58/firefox /usr/bin/firefox
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ .Revision }}
- run: - run:
name: Get Scss Cache key name: Get Scss Cache key
# this allows us to checksum against a whole directory # this allows us to checksum against a whole directory
@ -291,7 +301,7 @@ jobs:
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }} key: dependency-cache-{{ .Revision }}
- run: - run:
name: Get Scss Cache key name: Get Scss Cache key
# this allows us to checksum against a whole directory # this allows us to checksum against a whole directory

@ -2,6 +2,11 @@
## Current Master ## Current Master
## 4.5.1 Tue Apr 03 2018
- Fix default network (should be mainnet not Rinkeby)
- Fix Sentry automated error reporting endpoint
## 4.5.0 Mon Apr 02 2018 ## 4.5.0 Mon Apr 02 2018
- (beta ui) Internationalization: Select your preferred language in the settings screen - (beta ui) Internationalization: Select your preferred language in the settings screen

@ -56,7 +56,7 @@
"message": "Balance:" "message": "Balance:"
}, },
"balances": { "balances": {
"message": "Your balances" "message": "Token balance(s)"
}, },
"balanceIsInsufficientGas": { "balanceIsInsufficientGas": {
"message": "Insufficient balance for current gas total" "message": "Insufficient balance for current gas total"

@ -1,7 +1,7 @@
{ {
"name": "__MSG_appName__", "name": "__MSG_appName__",
"short_name": "__MSG_appName__", "short_name": "__MSG_appName__",
"version": "4.5.0", "version": "4.5.1",
"manifest_version": 2, "manifest_version": 2,
"author": "https://metamask.io", "author": "https://metamask.io",
"description": "__MSG_appDescription__", "description": "__MSG_appDescription__",

@ -22,7 +22,7 @@ const EdgeEncryptor = require('./edge-encryptor')
const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code') const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code')
const STORAGE_KEY = 'metamask-config' const STORAGE_KEY = 'metamask-config'
const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' const METAMASK_DEBUG = process.env.METAMASK_DEBUG
window.log = log window.log = log
log.setDefaultLevel(METAMASK_DEBUG ? 'debug' : 'warn') log.setDefaultLevel(METAMASK_DEBUG ? 'debug' : 'warn')
@ -94,7 +94,7 @@ function setupController (initState, initLangCode) {
// //
// MetaMask Controller // MetaMask Controller
// //
const controller = new MetamaskController({ const controller = new MetamaskController({
// User confirmation callbacks: // User confirmation callbacks:
showUnconfirmedMessage: triggerUi, showUnconfirmedMessage: triggerUi,

@ -13,7 +13,7 @@ const DEFAULT_RPC = 'rinkeby'
const OLD_UI_NETWORK_TYPE = 'network' const OLD_UI_NETWORK_TYPE = 'network'
const BETA_UI_NETWORK_TYPE = 'networkBeta' const BETA_UI_NETWORK_TYPE = 'networkBeta'
global.METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' global.METAMASK_DEBUG = process.env.METAMASK_DEBUG
module.exports = { module.exports = {
network: { network: {

@ -41,9 +41,9 @@ class BlacklistController {
scheduleUpdates () { scheduleUpdates () {
if (this._phishingUpdateIntervalRef) return if (this._phishingUpdateIntervalRef) return
this.updatePhishingList() this.updatePhishingList().catch(log.warn)
this._phishingUpdateIntervalRef = setInterval(() => { this._phishingUpdateIntervalRef = setInterval(() => {
this.updatePhishingList() this.updatePhishingList().catch(log.warn)
}, POLLING_INTERVAL) }, POLLING_INTERVAL)
} }
@ -57,4 +57,3 @@ class BlacklistController {
} }
module.exports = BlacklistController module.exports = BlacklistController

@ -43,20 +43,19 @@ class CurrencyController {
this.store.updateState({ conversionDate }) this.store.updateState({ conversionDate })
} }
updateConversionRate () { async updateConversionRate () {
const currentCurrency = this.getCurrentCurrency() let currentCurrency
return fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`) try {
.then(response => response.json()) currentCurrency = this.getCurrentCurrency()
.then((parsedResponse) => { const response = await fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`)
const parsedResponse = await response.json()
this.setConversionRate(Number(parsedResponse.bid)) this.setConversionRate(Number(parsedResponse.bid))
this.setConversionDate(Number(parsedResponse.timestamp)) this.setConversionDate(Number(parsedResponse.timestamp))
}).catch((err) => { } catch (err) {
if (err) { log.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err)
console.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err) this.setConversionRate(0)
this.setConversionRate(0) this.setConversionDate('N/A')
this.setConversionDate('N/A') }
}
})
} }
scheduleConversionInterval () { scheduleConversionInterval () {

@ -19,15 +19,13 @@ class InfuraController {
// Responsible for retrieving the status of Infura's nodes. Can return either // Responsible for retrieving the status of Infura's nodes. Can return either
// ok, degraded, or down. // ok, degraded, or down.
checkInfuraNetworkStatus () { async checkInfuraNetworkStatus () {
return fetch('https://api.infura.io/v1/status/metamask') const response = await fetch('https://api.infura.io/v1/status/metamask')
.then(response => response.json()) const parsedResponse = await response.json()
.then((parsedResponse) => { this.store.updateState({
this.store.updateState({ infuraNetworkStatus: parsedResponse,
infuraNetworkStatus: parsedResponse, })
}) return parsedResponse
return parsedResponse
})
} }
scheduleInfuraNetworkCheck () { scheduleInfuraNetworkCheck () {
@ -35,7 +33,7 @@ class InfuraController {
clearInterval(this.conversionInterval) clearInterval(this.conversionInterval)
} }
this.conversionInterval = setInterval(() => { this.conversionInterval = setInterval(() => {
this.checkInfuraNetworkStatus() this.checkInfuraNetworkStatus().catch(log.warn)
}, POLLING_INTERVAL) }, POLLING_INTERVAL)
} }
} }

@ -45,18 +45,19 @@ class ShapeshiftController {
}) })
} }
updateTx (tx) { async updateTx (tx) {
const url = `https://shapeshift.io/txStat/${tx.depositAddress}` try {
return fetch(url) const url = `https://shapeshift.io/txStat/${tx.depositAddress}`
.then((response) => { const response = await fetch(url)
return response.json() const json = await response.json()
}).then((json) => {
tx.response = json tx.response = json
if (tx.response.status === 'complete') { if (tx.response.status === 'complete') {
tx.time = new Date().getTime() tx.time = new Date().getTime()
} }
return tx return tx
}) } catch (err) {
log.warn(err)
}
} }
saveTx (tx) { saveTx (tx) {

@ -1,6 +1,6 @@
// test and development environment variables // test and development environment variables
const env = process.env.METAMASK_ENV const env = process.env.METAMASK_ENV
const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' const METAMASK_DEBUG = process.env.METAMASK_DEBUG
// //
// The default state of MetaMask // The default state of MetaMask

@ -9,7 +9,7 @@ const setupDappAutoReload = require('./lib/auto-reload.js')
const MetamaskInpageProvider = require('./lib/inpage-provider.js') const MetamaskInpageProvider = require('./lib/inpage-provider.js')
restoreContextAfterImports() restoreContextAfterImports()
const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' const METAMASK_DEBUG = process.env.METAMASK_DEBUG
window.log = log window.log = log
log.setDefaultLevel(METAMASK_DEBUG ? 'debug' : 'warn') log.setDefaultLevel(METAMASK_DEBUG ? 'debug' : 'warn')

@ -1,5 +1,5 @@
const Raven = require('raven-js') const Raven = require('raven-js')
const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' const METAMASK_DEBUG = process.env.METAMASK_DEBUG
const extractEthjsErrorMessage = require('./extractEthjsErrorMessage') const extractEthjsErrorMessage = require('./extractEthjsErrorMessage')
const PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505' const PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505'
const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496' const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496'

@ -140,8 +140,16 @@ module.exports = class TransactionStateManager extends EventEmitter {
validateTxParams(txParams) { validateTxParams(txParams) {
Object.keys(txParams).forEach((key) => { Object.keys(txParams).forEach((key) => {
const value = txParams[key] const value = txParams[key]
if (typeof value !== 'string') throw new Error(`${key}: ${value} in txParams is not a string`) // validate types
if (!ethUtil.isHexPrefixed(value)) throw new Error('is not hex prefixed, everything on txParams must be hex prefixed') 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
}
}) })
} }

@ -1,51 +1,62 @@
#!/usr/bin/env node #!/usr/bin/env node
const request = require('request-promise') 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 start().catch(console.error)
const CIRCLE_PULL_REQUEST = process.env.CIRCLE_PULL_REQUEST
console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST) async function start() {
const CIRCLE_SHA1 = process.env.CIRCLE_SHA1
console.log('CIRCLE_SHA1', CIRCLE_SHA1) const GITHUB_COMMENT_TOKEN = process.env.GITHUB_COMMENT_TOKEN
const CIRCLE_BUILD_NUM = process.env.CIRCLE_BUILD_NUM const CIRCLE_PULL_REQUEST = process.env.CIRCLE_PULL_REQUEST
console.log('CIRCLE_BUILD_NUM', CIRCLE_BUILD_NUM) console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST)
const CIRCLE_SHA1 = process.env.CIRCLE_SHA1
const CIRCLE_PR_NUMBER = CIRCLE_PULL_REQUEST.split('/').pop() console.log('CIRCLE_SHA1', CIRCLE_SHA1)
const SHORT_SHA1 = CIRCLE_SHA1.slice(0,7) const CIRCLE_BUILD_NUM = process.env.CIRCLE_BUILD_NUM
const BUILD_LINK_BASE = `https://${CIRCLE_BUILD_NUM}-42009758-gh.circle-artifacts.com/0` console.log('CIRCLE_BUILD_NUM', CIRCLE_BUILD_NUM)
const MASCARA = `${BUILD_LINK_BASE}/builds/mascara/home.html` if (!CIRCLE_PULL_REQUEST) {
const CHROME = `${BUILD_LINK_BASE}/builds/metamask-chrome-${version}.zip` console.warn(`No pull request detected for commit "${CIRCLE_SHA1}"`)
const FIREFOX = `${BUILD_LINK_BASE}/builds/metamask-firefox-${version}.zip` return
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 CIRCLE_PR_NUMBER = CIRCLE_PULL_REQUEST.split('/').pop()
const SHORT_SHA1 = CIRCLE_SHA1.slice(0,7)
const commentBody = ` const BUILD_LINK_BASE = `https://${CIRCLE_BUILD_NUM}-42009758-gh.circle-artifacts.com/0`
<details>
<summary> const MASCARA = `${BUILD_LINK_BASE}/builds/mascara/home.html`
Builds ready [${SHORT_SHA1}]: const CHROME = `${BUILD_LINK_BASE}/builds/metamask-chrome-${VERSION}.zip`
<a href="${MASCARA}">mascara</a>, const FIREFOX = `${BUILD_LINK_BASE}/builds/metamask-firefox-${VERSION}.zip`
<a href="${CHROME}">chrome</a>, const EDGE = `${BUILD_LINK_BASE}/builds/metamask-edge-${VERSION}.zip`
<a href="${FIREFOX}">firefox</a>, const OPERA = `${BUILD_LINK_BASE}/builds/metamask-opera-${VERSION}.zip`
<a href="${EDGE}">edge</a>, const WALKTHROUGH = `${BUILD_LINK_BASE}/test-artifacts/screens/walkthrough%20%28en%29.gif`
<a href="${OPERA}">opera</a>
</summary> const commentBody = `
<image src="${WALKTHROUGH}"> <details>
</details> <summary>
` Builds ready [${SHORT_SHA1}]:
<a href="${MASCARA}">mascara</a>,
const JSON_PAYLOAD = JSON.stringify({ body: commentBody }) <a href="${CHROME}">chrome</a>,
const POST_COMMENT_URI = `https://api.github.com/repos/metamask/metamask-extension/issues/${CIRCLE_PR_NUMBER}/comments` <a href="${FIREFOX}">firefox</a>,
console.log(`Announcement:\n${commentBody}`) <a href="${EDGE}">edge</a>,
console.log(`Posting to: ${POST_COMMENT_URI}`) <a href="${OPERA}">opera</a>
</summary>
request({ <image src="${WALKTHROUGH}">
method: 'POST', </details>
uri: POST_COMMENT_URI, `
body: JSON_PAYLOAD,
headers: { const JSON_PAYLOAD = JSON.stringify({ body: commentBody })
'User-Agent': 'metamaskbot', const POST_COMMENT_URI = `https://api.github.com/repos/metamask/metamask-extension/issues/${CIRCLE_PR_NUMBER}/comments`
'Authorization': `token ${GITHUB_COMMENT_TOKEN}`, 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}`,
},
})
}

@ -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
}
}

@ -1,5 +1,6 @@
const watchify = require('watchify') const watchify = require('watchify')
const browserify = require('browserify') const browserify = require('browserify')
const envify = require('envify/custom')
const disc = require('disc') const disc = require('disc')
const gulp = require('gulp') const gulp = require('gulp')
const source = require('vinyl-source-stream') 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:opera', zipTask('opera'))
gulp.task('zip', gulp.parallel('zip:chrome', 'zip:firefox', 'zip:edge', 'zip: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 // high level tasks
gulp.task('dev', gulp.task('dev',
@ -458,7 +453,6 @@ gulp.task('build:mascara',
gulp.task('dist', gulp.task('dist',
gulp.series( gulp.series(
'apply-prod-environment',
'build', 'build',
'zip' 'zip'
) )
@ -484,6 +478,12 @@ function generateBundler(opts, performBundle) {
let bundler = browserify(browserifyOpts) let bundler = browserify(browserifyOpts)
// inject variables into bundle
bundler.transform(envify({
METAMASK_DEBUG: opts.devMode,
NODE_ENV: opts.devMode ? 'development' : 'production',
}))
// Minification // Minification
if (opts.minifyBuild) { if (opts.minifyBuild) {
bundler.transform('uglifyify', { bundler.transform('uglifyify', {
@ -557,8 +557,6 @@ function bundleTask(opts) {
buildStream = buildStream buildStream = buildStream
// convert bundle stream to gulp vinyl stream // convert bundle stream to gulp vinyl stream
.pipe(source(opts.filename)) .pipe(source(opts.filename))
// inject variables into bundle
.pipe(replace('\'GULP_METAMASK_DEBUG\'', opts.devMode))
// buffer file contents (?) // buffer file contents (?)
.pipe(buffer()) .pipe(buffer())

8
package-lock.json generated

@ -188,7 +188,7 @@
"integrity": "sha1-AtD3eBwe5eG+WkMSoyX76LGzcjE=", "integrity": "sha1-AtD3eBwe5eG+WkMSoyX76LGzcjE=",
"dev": true, "dev": true,
"requires": { "requires": {
"https-proxy-agent": "2.2.0", "https-proxy-agent": "2.2.1",
"node-fetch": "1.7.3", "node-fetch": "1.7.3",
"progress": "2.0.0", "progress": "2.0.0",
"proxy-from-env": "1.0.0" "proxy-from-env": "1.0.0"
@ -213,9 +213,9 @@
} }
}, },
"https-proxy-agent": { "https-proxy-agent": {
"version": "2.2.0", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.0.tgz", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
"integrity": "sha512-uUWcfXHvy/dwfM9bqa6AozvAjS32dZSTUYd/4SEpYKRg6LEcPLshksnQYRudM9AyNvUARMfAg5TLjUDyX/K4vA==", "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"agent-base": "4.2.0", "agent-base": "4.2.0",

@ -5,7 +5,7 @@
"private": true, "private": true,
"scripts": { "scripts": {
"start": "gulp dev:extension", "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", "dist": "gulp dist",
"test": "npm run test:unit && npm run test:integration && npm run lint", "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:unit": "cross-env METAMASK_ENV=test mocha --exit --require babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"",
@ -31,13 +31,7 @@
"test:mascara:build:background": "browserify mascara/src/background.js -o dist/mascara/background.js", "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", "test:mascara:build:tests": "browserify test/integration/lib/first-time.js -o dist/mascara/tests.js",
"ganache:start": "ganache-cli -m 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'", "ganache:start": "ganache-cli -m 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'",
"sentry": "export RELEASE=`cat app/manifest.json| jq -r .version` && npm run sentry:release && npm run sentry:upload", "sentry:publish": "node ./development/sentry-publish.js",
"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",
"lint": "gulp lint", "lint": "gulp lint",
"lint:fix": "gulp lint:fix", "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 ./", "ui": "npm run test:flat:build:states && beefy development/ui-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
@ -61,7 +55,6 @@
} }
], ],
"reactify", "reactify",
"envify",
"brfs" "brfs"
] ]
}, },

@ -75,7 +75,7 @@ async function runAddTokenFlowTest (assert, done) {
// Confirm Add token // Confirm Add token
assert.equal( assert.equal(
$('.add-token__description')[0].textContent, $('.add-token__description')[0].textContent,
'Would you like to add these tokens?', 'Token balance(s)',
'confirm add token rendered' 'confirm add token rendered'
) )
assert.ok($('button.btn-primary--lg')[0], 'confirm add token button found') assert.ok($('button.btn-primary--lg')[0], 'confirm add token button found')

@ -56,6 +56,7 @@ inherits(AddTokenScreen, Component)
function AddTokenScreen () { function AddTokenScreen () {
this.state = { this.state = {
isShowingConfirmation: false, isShowingConfirmation: false,
isShowingInfoBox: true,
customAddress: '', customAddress: '',
customSymbol: '', customSymbol: '',
customDecimals: '', customDecimals: '',
@ -310,9 +311,6 @@ AddTokenScreen.prototype.renderConfirmation = function () {
return ( return (
h('div.add-token', [ h('div.add-token', [
h('div.add-token__wrapper', [ 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__content-container.add-token__confirmation-content', [
h('div.add-token__description.add-token__confirmation-description', this.context.t('balances')), h('div.add-token__description.add-token__confirmation-description', this.context.t('balances')),
h('div.add-token__confirmation-token-list', h('div.add-token__confirmation-token-list',
@ -347,18 +345,22 @@ AddTokenScreen.prototype.displayTab = function (selectedTab) {
} }
AddTokenScreen.prototype.renderTabs = function () { AddTokenScreen.prototype.renderTabs = function () {
const { displayedTab, errors } = this.state const { isShowingInfoBox, displayedTab, errors } = this.state
return displayedTab === 'CUSTOM_TOKEN' return displayedTab === 'CUSTOM_TOKEN'
? this.renderCustomForm() ? this.renderCustomForm()
: h('div', [ : h('div', [
h('div.add-token__wrapper', [ h('div.add-token__wrapper', [
h('div.add-token__content-container', [ h('div.add-token__content-container', [
h('div.add-token__info-box', [ isShowingInfoBox && h('div.add-token__info-box', [
h('div.add-token__info-box__close'), 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__title', this.context.t('whatsThis')),
h('div.add-token__info-box__copy', this.context.t('keepTrackTokens')), 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('div.add-token__input-container', [
h('input.add-token__input', { h('input.add-token__input', {
@ -390,12 +392,13 @@ AddTokenScreen.prototype.render = function () {
h('span', this.context.t('cancel')), h('span', this.context.t('cancel')),
]), ]),
h('div.add-token__header__title', this.context.t('addTokens')), 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', [ !isShowingConfirmation && h('div.add-token__header__tabs', [
h('div.add-token__header__tabs__tab', { h('div.add-token__header__tabs__tab', {
className: classnames('add-token__header__tabs__tab', { className: classnames('add-token__header__tabs__tab', {
'add-token__header__tabs__selected': displayedTab === 'SEARCH', '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'), onClick: () => this.displayTab('SEARCH'),
}, this.context.t('search')), }, this.context.t('search')),
@ -403,7 +406,7 @@ AddTokenScreen.prototype.render = function () {
h('div.add-token__header__tabs__tab', { h('div.add-token__header__tabs__tab', {
className: classnames('add-token__header__tabs__tab', { className: classnames('add-token__header__tabs__tab', {
'add-token__header__tabs__selected': displayedTab === 'CUSTOM_TOKEN', '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'), onClick: () => this.displayTab('CUSTOM_TOKEN'),
}, this.context.t('customToken')), }, this.context.t('customToken')),

@ -8,6 +8,7 @@
font-family: 'Roboto'; font-family: 'Roboto';
background: white; background: white;
border-radius: 8px; border-radius: 8px;
box-shadow: 0 0 7px 0 rgba(0, 0, 0, 0.08);
&__wrapper { &__wrapper {
background-color: $white; background-color: $white;
@ -20,7 +21,7 @@
&__header { &__header {
display: flex; display: flex;
flex-flow: column nowrap; flex-flow: column nowrap;
padding: 16px 16px 0px; padding: 20px 20px 0px;
border-bottom: 1px solid $geyser; border-bottom: 1px solid $geyser;
flex: 0 0 auto; flex: 0 0 auto;
@ -31,7 +32,8 @@
span { span {
font-family: Roboto; font-family: Roboto;
font-size: 16px; font-size: 16px;
font-weight: 400;
line-height: 21px; line-height: 21px;
margin-left: 8px; margin-left: 8px;
} }
@ -44,8 +46,13 @@
margin-top: 4px; margin-top: 4px;
} }
&__subtitle {
font-weight: 400;
margin-top: 15px;
margin-bottom: 21px;
}
&__tabs { &__tabs {
margin-left: 22px;
display: flex; display: flex;
&__tab { &__tab {
@ -54,6 +61,7 @@
color: $dusty-gray; color: $dusty-gray;
font-family: Roboto; font-family: Roboto;
font-size: 18px; font-size: 18px;
font-weight: 400;
line-height: 24px; line-height: 24px;
text-align: center; text-align: center;
} }
@ -65,6 +73,7 @@
&__unselected:hover { &__unselected:hover {
color: $black; color: $black;
border-bottom: none; border-bottom: none;
cursor: pointer;
} }
&__selected { &__selected {
@ -76,7 +85,7 @@
&__info-box { &__info-box {
height: 96px; height: 96px;
margin: 20px 24px 0px; margin: 20px 20px 0px;
border-radius: 4px; border-radius: 4px;
background-color: $alabaster; background-color: $alabaster;
position: relative; position: relative;
@ -98,6 +107,7 @@
color: $mid-gray; color: $mid-gray;
font-family: Roboto; font-family: Roboto;
font-size: 14px; font-size: 14px;
font-weight: 400;
margin-top: 15px; margin-top: 15px;
margin-bottom: 9px; margin-bottom: 9px;
} }
@ -107,6 +117,7 @@
color: $mid-gray; color: $mid-gray;
font-family: Roboto; font-family: Roboto;
font-size: 12px; font-size: 12px;
font-weight: 400;
line-height: 18px; line-height: 18px;
} }
@ -124,7 +135,8 @@
} }
&__confirmation-description { &__confirmation-description {
margin: 12px 0; font-weight: 400;
margin: 20px 0 40px 0;
} }
&__content-container { &__content-container {
@ -151,7 +163,7 @@
&__input, &__input,
&__add-custom-input { &__add-custom-input {
height: 54px; height: 54px;
padding: 21px 6px; padding: 0px 20px;
border: 1px solid $geyser; border: 1px solid $geyser;
border-radius: 4px; border-radius: 4px;
margin: 22px 24px; margin: 22px 24px;
@ -232,6 +244,7 @@
&__add-custom-label { &__add-custom-label {
font-size: 16px; font-size: 16px;
font-weight: 400;
line-height: 21px; line-height: 21px;
margin-left: 22px; margin-left: 22px;
color: $scorpion; color: $scorpion;
@ -274,9 +287,11 @@
color: #5B5D67; color: #5B5D67;
font-family: Roboto; font-family: Roboto;
font-size: 18px; font-size: 18px;
font-weight: 400;
line-height: 24px; line-height: 24px;
margin-left: 24px; margin-left: 24px;
margin-top: 8px; margin-top: 8px;
margin-bottom: 20px;
} }
&__token-icons-container { &__token-icons-container {
@ -317,6 +332,7 @@
} }
&__token-name { &__token-name {
font-weight: 400;
font-size: 14px; font-size: 14px;
line-height: 19px; line-height: 19px;
} }
@ -368,6 +384,7 @@
&__symbol { &__symbol {
color: $scorpion; color: $scorpion;
font-size: 16px; font-size: 16px;
font-weight: 400;
line-height: 24px; line-height: 24px;
} }
} }

@ -4,7 +4,7 @@ const thunkMiddleware = require('redux-thunk').default
const rootReducer = require('./reducers') const rootReducer = require('./reducers')
const createLogger = require('redux-logger').createLogger const createLogger = require('redux-logger').createLogger
global.METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' global.METAMASK_DEBUG = process.env.METAMASK_DEBUG
module.exports = configureStore module.exports = configureStore

@ -25,18 +25,15 @@ const getMessage = (locale, key, substitutions) => {
return phrase return phrase
} }
function fetchLocale (localeName) { async function fetchLocale (localeName) {
return new Promise((resolve, reject) => { try {
return fetch(`./_locales/${localeName}/messages.json`) const response = await fetch(`./_locales/${localeName}/messages.json`)
.then(response => response.json()) const locale = await response.json()
.then( return locale
locale => resolve(locale), } catch (error) {
error => { log.error(`failed to fetch ${localeName} locale because of ${error}`)
log.error(`failed to fetch ${localeName} locale because of ${error}`) return {}
resolve({}) }
}
)
})
} }
module.exports = { module.exports = {

Loading…
Cancel
Save