Merge pull request #6969 from MetaMask/develop

Master Version Bump
feature/default_network_editable
Dan Finlay 5 years ago committed by GitHub
commit db08881d45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 23
      .babelrc
  2. 142
      .circleci/config.yml
  3. 2
      .circleci/scripts/firefox-install
  4. 12
      .circleci/scripts/npm-audit
  5. 24
      .circleci/scripts/npm-audit-check.js
  6. 44
      .circleci/scripts/release-bump-changelog-version
  7. 38
      .circleci/scripts/release-bump-manifest-version
  8. 51
      .circleci/scripts/release-create-gh-release
  9. 54
      .circleci/scripts/release-create-release-pr
  10. 52
      .circleci/scripts/show-changelog.awk
  11. 20
      .circleci/scripts/yarn-audit
  12. 2
      .eslintignore
  13. 4
      .eslintrc
  14. 7
      .gitattributes
  15. 5
      .github/CODEOWNERS
  16. 8
      .gitignore
  17. 4
      .storybook/README.md
  18. 20
      CHANGELOG.md
  19. 27
      CONTRIBUTING.md
  20. 36
      README.md
  21. 130
      app/_locales/en/messages.json
  22. 1
      app/home.html
  23. 4
      app/images/check-green-solid.svg
  24. 4
      app/images/close-gray.svg
  25. BIN
      app/images/coinswitch_logo.png
  26. BIN
      app/images/ethereum-metamask-chrome.png
  27. BIN
      app/images/icon-64.png
  28. 7
      app/images/icons/connect.svg
  29. 5
      app/images/icons/info.svg
  30. BIN
      app/images/key-32.png
  31. BIN
      app/images/logo.png
  32. 3
      app/images/meta-shield.svg
  33. BIN
      app/images/pw128x128.png
  34. 7
      app/images/qr-blue.svg
  35. 4
      app/images/search-black.svg
  36. BIN
      app/images/shapeshift logo.png
  37. 5
      app/manifest.json
  38. 1
      app/notification.html
  39. 1
      app/popup.html
  40. 2
      app/scripts/background.js
  41. 10
      app/scripts/contentscript.js
  42. 2
      app/scripts/controllers/detect-tokens.js
  43. 43
      app/scripts/controllers/onboarding.js
  44. 22
      app/scripts/controllers/preferences.js
  45. 97
      app/scripts/controllers/provider-approval.js
  46. 4
      app/scripts/edge-encryptor.js
  47. 91
      app/scripts/inpage.js
  48. 13
      app/scripts/lib/createStreamSink.js
  49. 2
      app/scripts/lib/ens-ipfs/setup.js
  50. 100
      app/scripts/metamask-controller.js
  51. 33
      app/scripts/migrations/034.js
  52. 28
      app/scripts/migrations/035.js
  53. 6
      app/scripts/phishing-detect.js
  54. 8
      app/scripts/platforms/extension.js
  55. 77
      app/scripts/popup-core.js
  56. 121
      app/scripts/ui.js
  57. 24
      babel.config.js
  58. 0
      development/.jsdoc.json
  59. 72
      development/auto-changelog.sh
  60. 13
      development/mock-dev.js
  61. 44
      development/mockExtension.js
  62. 0
      development/notices/.gitkeep
  63. 1
      development/require-react-devtools.js
  64. 2
      development/rollback.sh
  65. 28
      development/run-ganache
  66. 1
      development/states.json
  67. 1
      development/states/account-detail-with-shapeshift-tx.json
  68. 1
      development/states/account-detail-with-transaction-history.json
  69. 1
      development/states/account-detail.json
  70. 1
      development/states/conf-tx.json
  71. 4
      development/states/confirm-new-ui.json
  72. 4
      development/states/confirm-sig-requests.json
  73. 3
      development/states/currency-localization.json
  74. 1
      development/states/empty-account-detail.json
  75. 1
      development/states/first-time.json
  76. 1
      development/states/locked.json
  77. 1
      development/states/lost-accounts.json
  78. 1
      development/states/new-account.json
  79. 2
      development/states/pending-crash.json
  80. 1
      development/states/pending-signature.json
  81. 1
      development/states/pending-tx-insufficient.json
  82. 1
      development/states/personal-sign.json
  83. 1
      development/states/private-network.json
  84. 13
      development/states/send-edit.json
  85. 3
      development/states/send-new-ui.json
  86. 1
      development/states/send.json
  87. 1
      development/states/shapeshift.json
  88. 2
      development/states/tx-list-items.json
  89. 15
      development/tools/README.md
  90. 21
      development/tools/appveyor.txt
  91. 96
      development/ui-dev.js
  92. 18
      development/uiStore.js
  93. 1
      docs/README.md
  94. BIN
      docs/architecture.png
  95. 4
      docs/bumping_version.md
  96. 20
      docs/components/account-menu.md
  97. 8
      docs/developing-on-deps.md
  98. 15
      docs/notices.md
  99. 38
      docs/porting_to_new_environment.md
  100. 6
      docs/publishing.md
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,23 +0,0 @@
{
"presets": [
[
"env",
{
"targets": {
"browsers": [
">0.25%",
"not ie 11",
"not op_mini all"
]
}
}
],
"react",
"stage-0"
],
"plugins": [
"transform-runtime",
"transform-async-to-generator",
"transform-class-properties"
]
}

@ -2,48 +2,54 @@ version: 2
workflows:
version: 2
full_test:
test_and_release:
jobs:
- prep-deps-npm
- create_release_pull_request:
filters:
branches:
only:
- /^Version-v(\d+)[.](\d+)[.](\d+)/
- prep-deps
- test-deps
- prep-build:
requires:
- prep-deps-npm
- prep-deps
- create_github_release:
requires:
- prep-build
filters:
branches:
only:
- develop
# - prep-docs:
# requires:
# - prep-deps-npm
# - prep-deps
- prep-scss:
requires:
- prep-deps-npm
- prep-deps
- test-lint:
requires:
- prep-deps-npm
- test-deps:
requires:
- prep-deps-npm
- prep-deps
- test-e2e-chrome:
requires:
- prep-deps-npm
- prep-deps
- test-e2e-firefox:
requires:
- prep-deps-npm
# - test-e2e-beta-drizzle:
# requires:
# - prep-deps-npm
# - prep-build
- prep-deps
- test-unit:
requires:
- prep-deps-npm
- prep-deps
- test-mozilla-lint:
requires:
- prep-deps-npm
- prep-deps
- prep-build
- test-integration-flat-chrome:
requires:
- prep-deps-npm
- prep-deps
- prep-scss
- test-integration-flat-firefox:
requires:
- prep-deps-npm
- prep-deps
- prep-scss
- all-tests-pass:
requires:
@ -52,41 +58,45 @@ workflows:
- test-mozilla-lint
- test-e2e-chrome
- test-e2e-firefox
# - test-e2e-beta-drizzle
- test-integration-flat-chrome
- test-integration-flat-firefox
- job-screens:
requires:
- prep-deps-npm
- prep-build
- all-tests-pass
- job-publish-prerelease:
requires:
- prep-deps-npm
- prep-deps
- prep-build
- job-screens
- all-tests-pass
- job-publish-release:
filters:
branches:
only: master
requires:
- prep-deps-npm
- prep-deps
- prep-build
# - prep-docs
- job-screens
- all-tests-pass
jobs:
prep-deps-npm:
create_release_pull_request:
docker:
- image: circleci/node:8.15.1-browsers
steps:
- checkout
- run:
name: Create GitHub Pull Request for version
command: |
.circleci/scripts/release-bump-changelog-version
.circleci/scripts/release-bump-manifest-version
.circleci/scripts/release-create-release-pr
prep-deps:
docker:
- image: circleci/node:10.16-browsers
steps:
- checkout
- run:
name: Install deps via npm
name: Install deps
command: |
npm ci
yarn --frozen-lockfile
- persist_to_workspace:
root: .
paths:
@ -101,7 +111,7 @@ jobs:
at: .
- run:
name: build:dist
command: npm run dist
command: yarn dist
- run:
name: build:debug
command: find dist/ -type f -exec md5sum {} \; | sort -k 2
@ -120,7 +130,7 @@ jobs:
at: .
- run:
name: build:dist
command: npm run doc
command: yarn doc
- persist_to_workspace:
root: .
paths:
@ -139,7 +149,7 @@ jobs:
command: find ui/app/css -type f -exec md5sum {} \; | sort -k 2 > scss_checksum
- run:
name: Build for integration tests
command: npm run test:integration:build
command: yarn test:integration:build
- persist_to_workspace:
root: .
paths:
@ -154,7 +164,7 @@ jobs:
at: .
- run:
name: Test
command: npm run lint
command: yarn lint
test-deps:
docker:
@ -164,22 +174,9 @@ jobs:
- attach_workspace:
at: .
- run:
name: npm audit
command: .circleci/scripts/npm-audit
name: yarn audit
command: .circleci/scripts/yarn-audit
# test-e2e-beta-drizzle:
# docker:
# - image: circleci/node:8.11.3-browsers
# steps:
# - checkout
# - attach_workspace:
# at: .
# - run:
# name: test:e2e:drizzle:beta
# command: npm run test:e2e:drizzle:beta
# - store_artifacts:
# path: test-artifacts
# destination: test-artifacts
test-e2e-chrome:
docker:
- image: circleci/node:10.16-browsers
@ -189,7 +186,7 @@ jobs:
at: .
- run:
name: test:e2e:chrome
command: npm run build:test && npm run test:e2e:chrome
command: yarn build:test && yarn test:e2e:chrome
no_output_timeout: 20m
- store_artifacts:
path: test-artifacts
@ -207,27 +204,12 @@ jobs:
at: .
- run:
name: test:e2e:firefox
command: npm run build:test && npm run test:e2e:chrome
command: yarn build:test && yarn test:e2e:chrome
no_output_timeout: 20m
- store_artifacts:
path: test-artifacts
destination: test-artifacts
job-screens:
docker:
- image: circleci/node:10.16-browsers
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Test
command: npm run test:screens
- persist_to_workspace:
root: .
paths:
- test-artifacts
job-publish-prerelease:
docker:
- image: circleci/node:10.16-browsers
@ -257,13 +239,13 @@ jobs:
at: .
- run:
name: sentry sourcemaps upload
command: npm run sentry:publish
command: yarn sentry:publish
# - run:
# name: github gh-pages docs publish
# command: >
# git config --global user.name "metamaskbot" &&
# git config --global user.email "admin@metamask.io" &&
# npm run publish-docs
# yarn publish-docs
test-unit:
docker:
@ -274,7 +256,7 @@ jobs:
at: .
- run:
name: test:coverage
command: npm run test:coverage
command: yarn test:coverage
test-mozilla-lint:
docker:
- image: circleci/node:10.16-browsers
@ -284,7 +266,7 @@ jobs:
at: .
- run:
name: test:mozilla-lint
command: npm run mozilla-lint
command: NODE_OPTIONS=--max_old_space_size=3072 yarn mozilla-lint
test-integration-flat-firefox:
docker:
@ -298,7 +280,7 @@ jobs:
command: ./.circleci/scripts/firefox-install
- run:
name: test:integration:flat
command: npm run test:flat
command: yarn test:flat
test-integration-flat-chrome:
environment:
@ -311,7 +293,7 @@ jobs:
at: .
- run:
name: test:integration:flat
command: npm run test:flat
command: yarn test:flat
all-tests-pass:
docker:
@ -320,3 +302,15 @@ jobs:
- run:
name: All Tests Passed
command: echo 'weew - everything passed!'
create_github_release:
docker:
- image: circleci/node:8.15.1-browsers
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Create GitHub release
command: |
.circleci/scripts/release-create-gh-release

@ -4,7 +4,7 @@ set -e
set -u
set -o pipefail
FIREFOX_VERSION='62.0'
FIREFOX_VERSION='68.0'
FIREFOX_BINARY="firefox-${FIREFOX_VERSION}.tar.bz2"
FIREFOX_BINARY_URL="https://ftp.mozilla.org/pub/firefox/releases/${FIREFOX_VERSION}/linux-x86_64/en-US/${FIREFOX_BINARY}"
FIREFOX_PATH='/opt/firefox'

@ -1,12 +0,0 @@
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
if ! npm audit
then
! npm audit --json > audit.json
printf '%s\n' ''
node .circleci/scripts/npm-audit-check.js
fi

@ -1,24 +0,0 @@
const path = require('path')
const audit = require(path.join(__dirname, '..', '..', 'audit.json'))
const error = audit.error
const advisories = Object.keys(audit.advisories || []).map((k) => audit.advisories[k])
if (error) {
process.exit(1)
}
let count = 0
for (const advisory of advisories) {
if (advisory.severity === 'low') {
continue
}
count += advisory.findings.some((finding) => (!finding.dev && !finding.optional))
}
if (count > 0) {
console.log(`Audit shows ${count} moderate or high severity advisories _in the production dependencies_`)
process.exit(1)
} else {
console.log(`Audit shows _zero_ moderate or high severity advisories _in the production dependencies_`)
}

@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
if [[ "${CI:-}" != 'true' ]]
then
printf '%s\n' 'CI environment variable must be set to true'
exit 1
fi
if [[ "${CIRCLECI:-}" != 'true' ]]
then
printf '%s\n' 'CIRCLECI environment variable must be set to true'
exit 1
fi
version="${CIRCLE_BRANCH/Version-v/}"
if ! grep --quiet --fixed-strings "$version" CHANGELOG.md
then
printf '%s\n' 'Adding this release to CHANGELOG.md'
date_str="$(date '+%a %b %d %Y')"
cp CHANGELOG.md{,.bak}
update_headers=$(cat <<END
/## Current Develop Branch/ {
print "## Current Develop Branch\n";
print "## ${version} ${date_str}";
next;
}
{
print;
}
END
)
awk "$update_headers" CHANGELOG.md.bak > CHANGELOG.md
rm CHANGELOG.md.bak
else
printf '%s\n' "CHANGELOG.md already includes a header for ${version}"
exit 0
fi

@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
if [[ "${CI:-}" != 'true' ]]
then
printf '%s\n' 'CI environment variable must be set to true'
exit 1
fi
if [[ "${CIRCLECI:-}" != 'true' ]]
then
printf '%s\n' 'CIRCLECI environment variable must be set to true'
exit 1
fi
printf '%s\n' 'Updating the manifest version if needed'
version="${CIRCLE_BRANCH/Version-v/}"
updated_manifest="$(jq ".version = \"$version\"" app/manifest.json)"
printf '%s\n' "$updated_manifest" > app/manifest.json
if [[ -z $(git status --porcelain) ]]
then
printf '%s\n' 'App manifest version already set'
exit 0
fi
git \
-c user.name='MetaMask Bot' \
-c user.email='metamaskbot@users.noreply.github.com' \
commit --message "${CIRCLE_BRANCH/-/ }" \
CHANGELOG.md app/manifest.json
repo_slug="$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
git push "https://$GITHUB_TOKEN_USER:$GITHUB_TOKEN@github.com/$repo_slug" "$CIRCLE_BRANCH"

@ -0,0 +1,51 @@
#!/usr/bin/env bash
set -x
set -e
set -u
set -o pipefail
if [[ "${CI:-}" != 'true' ]]
then
printf '%s\n' 'CI environment variable must be set to true'
exit 1
fi
if [[ "${CIRCLECI:-}" != 'true' ]]
then
printf '%s\n' 'CIRCLECI environment variable must be set to true'
exit 1
fi
function install_github_cli ()
{
printf '%s\n' 'Installing hub CLI'
pushd "$(mktemp -d)"
curl -sSL 'https://github.com/github/hub/releases/download/v2.11.2/hub-linux-amd64-2.11.2.tgz' | tar xz
PATH="$PATH:$PWD/hub-linux-amd64-2.11.2/bin"
popd
}
current_commit_msg=$(git show -s --format='%s' HEAD)
if grep --quiet '^Version v' <<< "$current_commit_msg"
then
install_github_cli
printf '%s\n' 'Creating GitHub Release'
read -ra commit_words <<< "$current_commit_msg"
tag="${commit_words[1]}"
release_body="$(awk -v version="${tag##v}" -f .circleci/scripts/show-changelog.awk CHANGELOG.md)"
pushd builds
hub release create \
--attach metamask-chrome-*.zip \
--attach metamask-firefox-*.zip \
--message "${commit_words[0]} ${commit_words[1]#v}" \
--message "$release_body" \
--commitish "$CIRCLE_SHA1" \
"$tag"
popd
else
printf '%s\n' 'Skipping GitHub Release'
exit 0
fi

@ -0,0 +1,54 @@
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
if [[ "${CI:-}" != 'true' ]]
then
printf '%s\n' 'CI environment variable must be set to true'
exit 1
fi
if [[ "${CIRCLECI:-}" != 'true' ]]
then
printf '%s\n' 'CIRCLECI environment variable must be set to true'
exit 1
fi
if [[ -z "${GITHUB_TOKEN:-}" ]]
then
printf '%s\n' 'GITHUB_TOKEN environment variable must be set'
exit 1
fi
function install_github_cli ()
{
printf '%s\n' 'Installing hub CLI'
pushd "$(mktemp -d)"
curl -sSL 'https://github.com/github/hub/releases/download/v2.11.2/hub-linux-amd64-2.11.2.tgz' | tar xz
PATH="$PATH:$PWD/hub-linux-amd64-2.11.2/bin"
popd
}
version="${CIRCLE_BRANCH/Version-v/}"
base_branch='develop'
if [[ -n "${CI_PULL_REQUEST:-}" ]]
then
printf '%s\n' 'CI_PULL_REQUEST is set, pull request already exists for this build'
exit 0
fi
install_github_cli
printf '%s\n' "Creating a Pull Request for $version on GitHub"
if ! hub pull-request \
--reviewer '@MetaMask/extension-release-team' \
--message "${CIRCLE_BRANCH/-/ } RC" --message ':package: :rocket:' \
--base "$CIRCLE_PROJECT_USERNAME:$base_branch" \
--head "$CIRCLE_PROJECT_USERNAME:$CIRCLE_BRANCH";
then
printf '%s\n' 'Pull Request already exists'
fi

@ -0,0 +1,52 @@
# DESCRIPTION
#
# This script will print out all of the CHANGELOG.md lines for a given version
# with the assumption that the CHANGELOG.md files looks something along the
# lines of:
#
# ```
# ## 6.6.2 Fri Jun 07 2019
#
# - [#6690](https://github.com/MetaMask/metamask-extension/pull/6690): Some words
# - [#6700](https://github.com/MetaMask/metamask-extension/pull/6700): some more words
#
# ## 6.6.1 Thu Jun 06 2019
#
# - [#6691](https://github.com/MetaMask/metamask-extension/pull/6691): Revert other words
#
# ## 6.6.0 Mon Jun 03 2019
#
# - [#6659](https://github.com/MetaMask/metamask-extension/pull/6659): foo
# - [#6671](https://github.com/MetaMask/metamask-extension/pull/6671): bar
# - [#6625](https://github.com/MetaMask/metamask-extension/pull/6625): baz
# - [#6633](https://github.com/MetaMask/metamask-extension/pull/6633): Many many words
#
#
# ```
#
# EXAMPLE
#
# Run this script like so, passing in the version:
#
# ```
# awk -v version='6.6.0' -f .circleci/scripts/show-changelog.awk CHANGELOG.md
# ```
#
BEGIN {
inside_section = 0;
}
$1 == "##" && $2 == version {
inside_section = 1;
next;
}
$1 == "##" && $2 != version {
inside_section = 0;
next;
}
inside_section && !/^$/ {
print $0;
}

@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -u
set -o pipefail
yarn audit --level moderate --groups dependencies
audit_status="$?"
# Use a bitmask to ignore INFO and LOW severity audit results
# See here: https://yarnpkg.com/lang/en/docs/cli/audit/
audit_status="$(( audit_status & 11100 ))"
if [[ "$audit_status" != 0 ]]
then
count="$(yarn audit --level moderate --groups dependencies --json | tail -1 | jq '.data.vulnerabilities.moderate + .data.vulnerabilities.high + .data.vulnerabilities.critical')"
printf "Audit shows %s moderate or high severity advisories _in the production dependencies_\n" "$count"
exit 1
else
printf "Audit shows _zero_ moderate or high severity advisories _in the production dependencies_\n"
fi

@ -17,3 +17,5 @@ ui/lib/blockies.js
test/integration/bundle.js
test/integration/jquery-3.1.0.min.js
test/integration/helpers.js
package-lock.json

@ -59,7 +59,7 @@
"eqeqeq": [2, "allow-null"],
"generator-star-spacing": [2, { "before": true, "after": true }],
"handle-callback-err": [2, "^(err|error)$" ],
"indent": "off",
"indent": [2, 2,{ "SwitchCase": 1 }],
"jsx-quotes": [2, "prefer-double"],
"key-spacing": 2,
"keyword-spacing": [2, { "before": true, "after": true }],
@ -133,7 +133,9 @@
"no-unneeded-ternary": [2, { "defaultAssignment": false }],
"no-unreachable": 2,
"no-unsafe-finally": 2,
"no-unused-expressions": ["error", { "allowShortCircuit" : true, "allowTernary": true }],
"no-unused-vars": [2, { "vars": "all", "args": "all", "argsIgnorePattern": "[_]+" }],
"no-use-before-define": [2, { "functions": false }],
"no-useless-call": 2,
"no-useless-computed-key": 2,
"no-useless-constructor": 2,

7
.gitattributes vendored

@ -1 +1,8 @@
CHANGELOG.md merge=union
# Reviewing the lockfile contents is an important step in verifying that
# we're using the dependencies we expect to be using
package-lock.json linguist-generated=false
yarn.lock linguist-generated=false
test/e2e/send-eth-with-private-key-test/ethereumjs-tx.js linguist-vendored linguist-generated

@ -1,7 +1,8 @@
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners.
package*.json @whymarrh
ui/ @danjm @whymarrh
package.json @danjm @whymarrh @Gudahtt
yarn.lock @danjm @whymarrh @Gudahtt
ui/ @danjm @whymarrh @Gudahtt
app/scripts/controllers/transactions @frankiebee

8
.gitignore vendored

@ -1,6 +1,9 @@
npm-debug.log
yarn-error.log
node_modules
yarn.lock
package-lock.json
audit.json
app/bower_components
test/bower_components
@ -11,6 +14,8 @@ package
.vscode
.sublime-project
*.bak
# VIM
*.swp
*.swo
@ -24,7 +29,6 @@ app/.DS_Store
coverage/
dist
builds/
disc/
builds.zip
docs/jsdocs

@ -1,8 +1,8 @@
# Storybook
We're currently using [Storybook](https://storybook.js.org/) as part of our design system. To run Storybook and test some of our UI components, clone the repo and run the following:
```
npm install
npm run storybook
yarn
yarn storybook
```
You should then see:
> info Storybook started on => http://localhost:6006/

@ -2,6 +2,15 @@
## Current Develop Branch
## 7.0.0 Fri Aug 02 2019
- [#6828](https://github.com/MetaMask/metamask-extension/pull/6828): Capitalized speed up label to match rest of UI
- [#6874](https://github.com/MetaMask/metamask-extension/pull/6928): Allows skipping of seed phrase challenge during onboarding, and completing it at a later time
- [#6900](https://github.com/MetaMask/metamask-extension/pull/6900): Prevent opening of asset dropdown if no tokens in account
- [#6904](https://github.com/MetaMask/metamask-extension/pull/6904): Set privacy mode as default
- [#6914](https://github.com/MetaMask/metamask-extension/pull/6914): Adds Address Book feature
- [#6928](https://github.com/MetaMask/metamask-extension/pull/6928): Disable Copy Tx ID and block explorer link for transactions without hash
- [#6967](https://github.com/MetaMask/metamask-extension/pull/6967): Fix mobile sync
## 6.7.3 Thu Jul 18 2019
- [#6888](https://github.com/MetaMask/metamask-extension/pull/6888): Fix bug with resubmitting unsigned transactions.
@ -10,12 +19,12 @@
- [#6713](https://github.com/MetaMask/metamask-extension/pull/6713): * Normalize and Validate txParams in TransactionStateManager.addTx too
- [#6759](https://github.com/MetaMask/metamask-extension/pull/6759): Update to Node.js v10
- [#Fixes #6694 ](https://github.com/MetaMask/metamask-extension/pull/Fixes #6694 ): Fixes #6694
- [#6694](https://github.com/MetaMask/metamask-extension/pull/6694): Fixes #6694
- [#6743](https://github.com/MetaMask/metamask-extension/pull/6743): * Add tests for ImportWithSeedPhrase#parseSeedPhrase
- [#Fixes #6740](https://github.com/MetaMask/metamask-extension/pull/Fixes #6740): Fixes #6740
- [#Fixes #6741](https://github.com/MetaMask/metamask-extension/pull/Fixes #6741): Fixes #6741
- [#6740](https://github.com/MetaMask/metamask-extension/pull/6740): Fixes #6740
- [#6741](https://github.com/MetaMask/metamask-extension/pull/6741): Fixes #6741
- [#6761](https://github.com/MetaMask/metamask-extension/pull/6761): Fixes #6760, correct PropTypes for nextRoute
- [#6754](https://github.com/MetaMask/metamask-extension/pull/6754): There is currently a bug in chrome that prevents reading source maps
- [#6754](https://github.com/MetaMask/metamask-extension/pull/6754): Use inline source maps in development
- [#6589](https://github.com/MetaMask/metamask-extension/pull/6589): Document hotfix protocol
- [#6738](https://github.com/MetaMask/metamask-extension/pull/6738): Add codeowner for package-lock-old.json package-lock.json package.json packagelock-old.json files
- [#6648](https://github.com/MetaMask/metamask-extension/pull/6648): Add loading view to notification.html
@ -28,11 +37,12 @@
- [#6623](https://github.com/MetaMask/metamask-extension/pull/6623): Improve contract method data fetching (#6623)
- [#6551](https://github.com/MetaMask/metamask-extension/pull/6551): Adds 4byte registry fallback to getMethodData() (#6435)
- [#6718, #6650](https://github.com/MetaMask/metamask-extension/pull/6718, #6650): Add delete to custom RPC form
- [#6718](https://github.com/MetaMask/metamask-extension/pull/6718): Add delete to custom RPC form
- [#6700](https://github.com/MetaMask/metamask-extension/pull/6700): Fix styles on 'import account' page, update help link
- [#6714](https://github.com/MetaMask/metamask-extension/pull/6714): Wrap smaller custom block explorer url text
- [#6706](https://github.com/MetaMask/metamask-extension/pull/6706): Pin ethereumjs-tx
- [#6700](https://github.com/MetaMask/metamask-extension/pull/6700): Fix styles on 'import account' page, update help link
- [#6775](https://github.com/MetaMask/metamask-extension/pull/6775): Started adding visual documentation of MetaMask plugin components with the account menu component first
## 6.6.2 Fri Jun 07 2019

@ -22,30 +22,3 @@ When you're done with your project / bugfix / feature and ready to submit a PR,
- [ ] **Get reviewed by a core contributor**: Make sure you get a `:thumbsup`, `:+1`, or `LGTM` from a user with a `Member` badge before merging.
And that's it! Thanks for helping out.
### Developing inside a node_modules folder
First make sure you are comfortable with [how require works](https://github.com/maxogden/art-of-node#how-require-works) in node.
We recommend creating a folder somewhere manually called `node_modules`. For example in `~/code/node_modules`. Clone all of your git copies of modules that you want to work on into here, so for example:
- `~/code/node_modules/dat`
- `~/code/node_modules/hyperdrive`
When you run `npm install` inside of `~/code/node_modules/dat`, dat will get its own copy of `hyperdrive` (one if its dependencies) inside `~/code/node_modules/dat/node_modules`. However, if you encounter a bug in hyperdrive that you need to fix, but you want to test your fix in dat, you want dat to use your git copy of hyperdrive at `~/code/node_modules/hyperdrive` and not the npm copy of hyperdrive at `~/code/node_modules/dat/node_modules/hyperdrive`.
How do you get dat to use the git copy of hyperdrive? Just delete the npm copy!
```
rm -rf ~/code/node_modules/dat/node_modules/hyperdrive
```
Now when you run dat, and it tries to `require('hyperdrive')` it first looks in its own `node_modules` folder at `~/code/node_modules/dat/node_modules` but doesnt find hyperdrive. So it goes up to `~/code/node_modules` and finds `hyperdrive` there and uses that one, your git copy.
If you want to switch back to an npm copy, just run `npm install` inside `~/code/node_modules/dat/` and npm will download any missing modules into `~/code/node_modules/dat/node_modules` but wont touch anything in `~/code/node_modules`.
This might seem a bit complicated at first, but is simple once you get the hang of it. Here are some rules to help you get started:
- Never make any meaningful edits to code inside an "npm-managed" node_modules folder (such as `~/code/node_modules/dat/node_modules`), because when you run `npm install` inside those folders it could inadvertently delete all of your edits when installing an updated copy of a module. This has happened to me many times, so I just always use my git copy and delete the npm copy (as described above) to make edits to a module.
- You should never need to run any npm commands in terminal when at your "manually managed"" node_modules folder at `~/code/node_modules`. Never running npm commands at that folder also prevents npm from accidentally erasing your git copies of modules
- The location of your "manually managed" node_modules folder should be somewhere isolated from your normal require path. E.g. if you put it at `~/node_modules`, then when you run `npm install dat` at `~/Desktop` npm might decide to erase your git copy of dat at `~/node_modules/dat` and replace it with a copy from npm, which could make you lose work. Putting your manually managed `node_modules` folder in a sub-folder like `~/code` gets it "out of the way" and prevents accidents like that from happening.

@ -3,6 +3,8 @@
You can find the latest version of MetaMask on [our official website](https://metamask.io/). For help using MetaMask, visit our [User Support Site](https://metamask.zendesk.com/hc/en-us).
MetaMask supports Firefox, Google Chrome, and Chromium-based browsers. We recommend using the latest available browser version.
For up to the minute news, follow our [Twitter](https://twitter.com/metamask_io) or [Medium](https://medium.com/metamask) pages.
To learn how to develop MetaMask-compatible applications, visit our [Developer Docs](https://metamask.github.io/metamask-docs/).
@ -11,14 +13,17 @@ To learn how to contribute to the MetaMask project itself, visit our [Internal D
## Building locally
- Install [Node.js](https://nodejs.org) version 10 and the latest available npm@6
- Install [Node.js](https://nodejs.org) version 10
- If you are using [nvm](https://github.com/creationix/nvm#installation) (recommended) running `nvm use` will automatically choose the right node version for you.
- If you install Node.js manually, ensure you're using npm@6
- Install npm@6 using `npm install -g npm@6`
- Install dependencies: `npm ci`
- If you have issues with node-sass compilation, try `npm rebuild node-sass`
- Build the project to the `./dist/` folder with `npm run dist`.
- Optionally, to start a development build (e.g. with logging and file watching) run `npm start` instead.
- Install [Yarn](https://yarnpkg.com/en/docs/install)
- Install dependencies: `yarn`
- Build the project to the `./dist/` folder with `yarn dist`.
- Optionally, to start a development build (e.g. with logging and file watching) run `yarn start` instead.
- To start the [React DevTools](https://github.com/facebook/react-devtools) and [Redux DevTools Extension](http://extension.remotedev.io)
alongside the app, use `yarn start:dev`.
- React DevTools will open in a separate window; no browser extension is required
- Redux DevTools will need to be installed as a browser extension. Open the Redux Remote Devtools to access Redux state logs. This can be done by either right clicking within the web browser to bring up the context menu, expanding the Redux DevTools panel and clicking Open Remote DevTools OR clicking the Redux DevTools extension icon and clicking Open Remote DevTools.
- You will also need to check the "Use custom (local) server" checkbox in the Remote DevTools Settings, using the default server configuration (host `localhost`, port `8000`, secure connection checkbox unchecked)
Uncompressed builds can be found in `/dist`, compressed builds can be found in `/builds` once they're built.
@ -26,15 +31,15 @@ Uncompressed builds can be found in `/dist`, compressed builds can be found in `
You can read [our internal docs here](https://metamask.github.io/metamask-extension/).
You can re-generate the docs locally by running `npm run doc`, and contributors can update the hosted docs by running `npm run publish-docs`.
You can re-generate the docs locally by running `yarn doc`, and contributors can update the hosted docs by running `yarn publish-docs`.
### Running Tests
Run tests with `npm test`.
Run tests with `yarn test`.
You can also test with a continuously watching process, via `npm run watch`.
You can also test with a continuously watching process, via `yarn watch`.
You can run the linter by itself with `npm run lint`.
You can run the linter by itself with `yarn lint`.
## Architecture
@ -43,14 +48,14 @@ You can run the linter by itself with `npm run lint`.
## Development
```bash
npm install
npm start
yarn
yarn start
```
## Build for Publishing
```bash
npm run dist
yarn dist
```
#### Writing Browser Tests
@ -66,9 +71,8 @@ To write tests that will be run in the browser using QUnit, add your test files
- [The MetaMask Team](./docs/team.md)
- [How to live reload on local dependency changes](./docs/developing-on-deps.md)
- [How to add new networks to the Provider Menu](./docs/adding-new-networks.md)
- [How to manage notices that appear when the app starts up](./docs/notices.md)
- [How to port MetaMask to a new platform](./docs/porting_to_new_environment.md)
- [How to use the TREZOR emulator](./docs/trezor-emulator.md)
- [How to generate a visualization of this repository's development](./docs/development-visualization.md)
[1]: http://www.nomnoml.com/#view/%5B%3Cactor%3Euser%5D%0A%0A%5Bmetamask-ui%7C%0A%20%20%20%5Btools%7C%0A%20%20%20%20%20react%0A%20%20%20%20%20redux%0A%20%20%20%20%20thunk%0A%20%20%20%20%20ethUtils%0A%20%20%20%20%20jazzicon%0A%20%20%20%5D%0A%20%20%20%5Bcomponents%7C%0A%20%20%20%20%20app%0A%20%20%20%20%20account-detail%0A%20%20%20%20%20accounts%0A%20%20%20%20%20locked-screen%0A%20%20%20%20%20restore-vault%0A%20%20%20%20%20identicon%0A%20%20%20%20%20config%0A%20%20%20%20%20info%0A%20%20%20%5D%0A%20%20%20%5Breducers%7C%0A%20%20%20%20%20app%0A%20%20%20%20%20metamask%0A%20%20%20%20%20identities%0A%20%20%20%5D%0A%20%20%20%5Bactions%7C%0A%20%20%20%20%20%5BaccountManager%5D%0A%20%20%20%5D%0A%20%20%20%5Bcomponents%5D%3A-%3E%5Bactions%5D%0A%20%20%20%5Bactions%5D%3A-%3E%5Breducers%5D%0A%20%20%20%5Breducers%5D%3A-%3E%5Bcomponents%5D%0A%5D%0A%0A%5Bweb%20dapp%7C%0A%20%20%5Bui%20code%5D%0A%20%20%5Bweb3%5D%0A%20%20%5Bmetamask-inpage%5D%0A%20%20%0A%20%20%5B%3Cactor%3Eui%20developer%5D%0A%20%20%5Bui%20developer%5D-%3E%5Bui%20code%5D%0A%20%20%5Bui%20code%5D%3C-%3E%5Bweb3%5D%0A%20%20%5Bweb3%5D%3C-%3E%5Bmetamask-inpage%5D%0A%5D%0A%0A%5Bmetamask-background%7C%0A%20%20%5Bprovider-engine%5D%0A%20%20%5Bhooked%20wallet%20subprovider%5D%0A%20%20%5Bid%20store%5D%0A%20%20%0A%20%20%5Bprovider-engine%5D%3C-%3E%5Bhooked%20wallet%20subprovider%5D%0A%20%20%5Bhooked%20wallet%20subprovider%5D%3C-%3E%5Bid%20store%5D%0A%20%20%5Bconfig%20manager%7C%0A%20%20%20%20%5Brpc%20configuration%5D%0A%20%20%20%20%5Bencrypted%20keys%5D%0A%20%20%20%20%5Bwallet%20nicknames%5D%0A%20%20%5D%0A%20%20%0A%20%20%5Bprovider-engine%5D%3C-%5Bconfig%20manager%5D%0A%20%20%5Bid%20store%5D%3C-%3E%5Bconfig%20manager%5D%0A%5D%0A%0A%5Buser%5D%3C-%3E%5Bmetamask-ui%5D%0A%0A%5Buser%5D%3C%3A--%3A%3E%5Bweb%20dapp%5D%0A%0A%5Bmetamask-contentscript%7C%0A%20%20%5Bplugin%20restart%20detector%5D%0A%20%20%5Brpc%20passthrough%5D%0A%5D%0A%0A%5Brpc%20%7C%0A%20%20%5Bethereum%20blockchain%20%7C%0A%20%20%20%20%5Bcontracts%5D%0A%20%20%20%20%5Baccounts%5D%0A%20%20%5D%0A%5D%0A%0A%5Bweb%20dapp%5D%3C%3A--%3A%3E%5Bmetamask-contentscript%5D%0A%5Bmetamask-contentscript%5D%3C-%3E%5Bmetamask-background%5D%0A%5Bmetamask-background%5D%3C-%3E%5Bmetamask-ui%5D%0A%5Bmetamask-background%5D%3C-%3E%5Brpc%5D%0A
[1]: http://www.nomnoml.com/#view/%5B%3Cactor%3Euser%5D%0A%0A%5Bmetamask-ui%7C%0A%20%20%20%5Btools%7C%0A%20%20%20%20%20react%0A%20%20%20%20%20redux%0A%20%20%20%20%20thunk%0A%20%20%20%20%20ethUtils%0A%20%20%20%20%20jazzicon%0A%20%20%20%5D%0A%20%20%20%5Bcomponents%7C%0A%20%20%20%20%20app%0A%20%20%20%20%20account-detail%0A%20%20%20%20%20accounts%0A%20%20%20%20%20locked-screen%0A%20%20%20%20%20restore-vault%0A%20%20%20%20%20identicon%0A%20%20%20%20%20config%0A%20%20%20%20%20info%0A%20%20%20%5D%0A%20%20%20%5Breducers%7C%0A%20%20%20%20%20app%0A%20%20%20%20%20metamask%0A%20%20%20%20%20identities%0A%20%20%20%5D%0A%20%20%20%5Bactions%7C%0A%20%20%20%20%20%5BbackgroundConnection%5D%0A%20%20%20%5D%0A%20%20%20%5Bcomponents%5D%3A-%3E%5Bactions%5D%0A%20%20%20%5Bactions%5D%3A-%3E%5Breducers%5D%0A%20%20%20%5Breducers%5D%3A-%3E%5Bcomponents%5D%0A%5D%0A%0A%5Bweb%20dapp%7C%0A%20%20%5Bui%20code%5D%0A%20%20%5Bweb3%5D%0A%20%20%5Bmetamask-inpage%5D%0A%20%20%0A%20%20%5B%3Cactor%3Eui%20developer%5D%0A%20%20%5Bui%20developer%5D-%3E%5Bui%20code%5D%0A%20%20%5Bui%20code%5D%3C-%3E%5Bweb3%5D%0A%20%20%5Bweb3%5D%3C-%3E%5Bmetamask-inpage%5D%0A%5D%0A%0A%5Bmetamask-background%7C%0A%20%20%5Bprovider-engine%5D%0A%20%20%5Bhooked%20wallet%20subprovider%5D%0A%20%20%5Bid%20store%5D%0A%20%20%0A%20%20%5Bprovider-engine%5D%3C-%3E%5Bhooked%20wallet%20subprovider%5D%0A%20%20%5Bhooked%20wallet%20subprovider%5D%3C-%3E%5Bid%20store%5D%0A%20%20%5Bconfig%20manager%7C%0A%20%20%20%20%5Brpc%20configuration%5D%0A%20%20%20%20%5Bencrypted%20keys%5D%0A%20%20%20%20%5Bwallet%20nicknames%5D%0A%20%20%5D%0A%20%20%0A%20%20%5Bprovider-engine%5D%3C-%5Bconfig%20manager%5D%0A%20%20%5Bid%20store%5D%3C-%3E%5Bconfig%20manager%5D%0A%5D%0A%0A%5Buser%5D%3C-%3E%5Bmetamask-ui%5D%0A%0A%5Buser%5D%3C%3A--%3A%3E%5Bweb%20dapp%5D%0A%0A%5Bmetamask-contentscript%7C%0A%20%20%5Bplugin%20restart%20detector%5D%0A%20%20%5Brpc%20passthrough%5D%0A%5D%0A%0A%5Brpc%20%7C%0A%20%20%5Bethereum%20blockchain%20%7C%0A%20%20%20%20%5Bcontracts%5D%0A%20%20%20%20%5Baccounts%5D%0A%20%20%5D%0A%5D%0A%0A%5Bweb%20dapp%5D%3C%3A--%3A%3E%5Bmetamask-contentscript%5D%0A%5Bmetamask-contentscript%5D%3C-%3E%5Bmetamask-background%5D%0A%5Bmetamask-background%5D%3C-%3E%5Bmetamask-ui%5D%0A%5Bmetamask-background%5D%3C-%3E%5Brpc%5D%0A

@ -1,4 +1,16 @@
{
"shareAddress": {
"message": "Share Address"
},
"shareAddressToConnect": {
"message": "Share your address to connect to $1?"
},
"shareAddressInfo": {
"message": "Sharing your address with $1 will allow you to interact with this dapp. This permission is to protect your privacy by default."
},
"privacyModeDefault": {
"message": "Privacy Mode is now enabled by default"
},
"privacyMode": {
"message": "Privacy Mode"
},
@ -80,12 +92,21 @@
"activityLog": {
"message": "activity log"
},
"add": {
"message": "Add"
},
"address": {
"message": "Address"
},
"addNetwork": {
"message": "Add Network"
},
"addRecipient": {
"message": "Add Recipient"
},
"addressBook": {
"message": "Address Book"
},
"advanced": {
"message": "Advanced"
},
@ -98,6 +119,18 @@
"addCustomToken": {
"message": "Add custom token"
},
"addToAddressBook": {
"message": "Add to address book"
},
"addToAddressBookModalPlaceholder": {
"message": "e.g. John D."
},
"addAlias": {
"message": "Add alias"
},
"addEthAddress": {
"message": "Add an Ethereum address"
},
"addToken": {
"message": "Add Token"
},
@ -172,6 +205,18 @@
"back": {
"message": "Back"
},
"backToAll": {
"message": "Back to All"
},
"backupApprovalNotice": {
"message": "Backup your Secret Recovery code to keep your wallet and funds secure."
},
"backupApprovalInfo": {
"message": "This secret code is required to recover your wallet in case you lose your device, forget your password, have to re-install MetaMask, or want to access your wallet on another device."
},
"backupNow": {
"message": "Backup now"
},
"balance": {
"message": "Balance"
},
@ -237,9 +282,15 @@
"bytes": {
"message": "Bytes"
},
"off": {
"message": "Off"
},
"ok": {
"message": "Ok"
},
"on": {
"message": "On"
},
"optionalBlockExplorerUrl": {
"message": "Block Explorer URL (optional)"
},
@ -348,6 +399,12 @@
"connectToTrezor": {
"message": "Connect to Trezor"
},
"contactList": {
"message": "Contact List"
},
"contactListDescription": {
"message": "Add, edit, remove, and manage your contacts"
},
"continue": {
"message": "Continue"
},
@ -457,6 +514,9 @@
"delete": {
"message": "Delete"
},
"deleteAccount": {
"message": "Delete Account"
},
"denExplainer": {
"message": "Your DEN is your password-encrypted storage within MetaMask."
},
@ -496,6 +556,9 @@
"directDepositEtherExplainer": {
"message": "If you already have some Ether, the quickest way to get Ether in your new wallet by direct deposit."
},
"dismiss": {
"message": "Dismiss"
},
"done": {
"message": "Done"
},
@ -523,6 +586,9 @@
"editAccountName": {
"message": "Edit Account Name"
},
"editContact":{
"message": "Edit Contact"
},
"editingTransaction": {
"message": "Make changes to your transaction"
},
@ -556,9 +622,24 @@
"endOfFlowMessage8": {
"message": "MetaMask cannot recover your seedphrase. Learn more."
},
"endOfFlowMessage9": {
"message": "Learn more."
},
"endOfFlowMessage10": {
"message": "All Done"
},
"ensNameNotFound": {
"message": "ENS name not found"
},
"ensRegistrationError": {
"message": "Error in ENS name registration"
},
"ensNotFoundOnCurrentNetwork": {
"message": "ENS name not found on the current network. Try switching to Main Ethereum Network."
},
"enterAnAlias": {
"message": "Enter an alias"
},
"enterPassword": {
"message": "Enter password"
},
@ -571,6 +652,9 @@
"eth": {
"message": "ETH"
},
"ethereumPublicAddress": {
"message": "Ethereum Public Address"
},
"etherscanView": {
"message": "View account on Etherscan"
},
@ -881,6 +965,9 @@
"loadingTokens": {
"message": "Loading Tokens..."
},
"loadMore": {
"message": "Load More"
},
"localhost": {
"message": "Localhost 8545"
},
@ -902,6 +989,9 @@
"memorizePhrase": {
"message": "Memorize this phrase."
},
"memo": {
"message": "memo"
},
"menu": {
"message": "Menu"
},
@ -935,6 +1025,12 @@
"myAccounts": {
"message": "My Accounts"
},
"myWalletAccounts": {
"message": "My Wallet Accounts"
},
"myWalletAccountsDescription": {
"message": "All of your MetaMask created accounts will automatically be added to this section."
},
"mustSelectOne": {
"message": "Must select at least 1 token."
},
@ -967,10 +1063,16 @@
"newAccount": {
"message": "New Account"
},
"newAccountDetectedDialogMessage": {
"message": "New address detected! Click here to add to your address book."
},
"newAccountNumberName": {
"message": "Account $1",
"description": "Default name of next account to be created on create account screen"
},
"newContact": {
"message": "New Contact"
},
"newContract": {
"message": "New Contract"
},
@ -1170,7 +1272,7 @@
"message": "Queue"
},
"readdToken": {
"message": "You can add this token back in the future by going go to “Add token” in your accounts options menu."
"message": "You can add this token back in the future by going to “Add token” in your accounts options menu."
},
"readMore": {
"message": "Read more here."
@ -1181,9 +1283,15 @@
"receive": {
"message": "Receive"
},
"recents": {
"message": "Recents"
},
"recipientAddress": {
"message": "Recipient Address"
},
"recipientAddressPlaceholder": {
"message": "Search, public address (0x), or ENS"
},
"refundAddress": {
"message": "Your Refund Address"
},
@ -1208,6 +1316,15 @@
"resetAccountDescription": {
"message": "Resetting your account will clear your transaction history."
},
"deleteNetwork": {
"message": "Delete Network?"
},
"deleteNetworkDescription": {
"message": "Are you sure you want to delete this network?"
},
"remindMeLater": {
"message": "Remind me later"
},
"restoreFromSeed": {
"message": "Restore account?"
},
@ -1457,7 +1574,7 @@
"message": "there can only be a space between words"
},
"speedUp": {
"message": "speed up"
"message": "Speed Up"
},
"speedUpTitle": {
"message": "Speed Up Transaction"
@ -1652,6 +1769,9 @@
"transfer": {
"message": "Transfer"
},
"transferBetweenAccounts": {
"message": "Transfer between my accounts"
},
"transferFrom": {
"message": "Transfer From"
},
@ -1732,6 +1852,9 @@
"useOldUI": {
"message": "Use old UI"
},
"userName":{
"message": "Username"
},
"validFileImport": {
"message": "You must select a valid file to import."
},
@ -1744,6 +1867,9 @@
"viewinExplorer": {
"message": "View in Explorer"
},
"viewContact": {
"message": "View Contact"
},
"viewOnCustomBlockExplorer": {
"message": "View at $1"
},

@ -4,6 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1 user-scalable=no">
<title>MetaMask</title>
<link rel="stylesheet" type="text/css" href="./index.css">
</head>
<body>
<div id="app-content"></div>

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.833374 10C0.833374 4.9374 4.93743 0.833344 10 0.833344C15.0626 0.833344 19.1667 4.9374 19.1667 10C19.1667 15.0626 15.0626 19.1667 10 19.1667C4.93743 19.1667 0.833374 15.0626 0.833374 10Z" fill="#28A745"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4256 6.70245C14.7511 7.02789 14.7511 7.55553 14.4256 7.88097L9.25303 13.2976C8.9276 13.6231 8.39996 13.6231 8.07452 13.2976L5.57452 10.7976C5.24909 10.4722 5.24909 9.94456 5.57452 9.61912C5.89996 9.29368 6.4276 9.29368 6.75303 9.61912L8.66378 11.5299L13.2471 6.70245C13.5725 6.37702 14.1002 6.37702 14.4256 6.70245Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 745 B

@ -0,0 +1,4 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.14917" y="1.09723" width="1.34076" height="15.4188" rx="0.670381" transform="rotate(-45 0.14917 1.09723)" fill="#A1A5B3"/>
<rect x="0.94812" y="11.8508" width="1.34076" height="15.4188" rx="0.670381" transform="rotate(-135 0.94812 11.8508)" fill="#A1A5B3"/>
</svg>

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.00002 9.57037C8.93767 9.57037 9.69778 8.81026 9.69778 7.8726C9.69778 6.93495 8.93767 6.17484 8.00002 6.17484C7.06236 6.17484 6.30225 6.93495 6.30225 7.8726C6.30225 8.81026 7.06236 9.57037 8.00002 9.57037Z" fill="white"/>
<path d="M11.0582 11.6586C10.872 11.6586 10.6857 11.5876 10.5437 11.4455C10.2595 11.1614 10.2595 10.7007 10.5437 10.4165C11.2232 9.73704 11.5975 8.83356 11.5975 7.87259C11.5975 6.91161 11.2232 6.00813 10.5437 5.32865C10.2595 5.04448 10.2595 4.58381 10.5437 4.29964C10.8278 4.01554 11.2886 4.01554 11.5727 4.29964C12.527 5.25398 13.0527 6.52293 13.0527 7.87259C13.0527 9.22224 12.527 10.4912 11.5727 11.4455C11.4306 11.5876 11.2444 11.6586 11.0582 11.6586Z" fill="white"/>
<path d="M4.94175 11.6586C4.75553 11.6586 4.56929 11.5876 4.42724 11.4455C3.4729 10.4912 2.94727 9.22224 2.94727 7.87259C2.94727 6.52293 3.4729 5.25398 4.42724 4.29964C4.71135 4.01554 5.17215 4.01554 5.45626 4.29964C5.74043 4.58381 5.74043 5.04448 5.45626 5.32865C4.77672 6.00813 4.4025 6.91161 4.4025 7.87259C4.4025 8.83356 4.77672 9.73704 5.45626 10.4165C5.74043 10.7007 5.74043 11.1614 5.45626 11.4455C5.3142 11.5876 5.12798 11.6586 4.94175 11.6586Z" fill="white"/>
<path d="M13.1451 13.7453C12.9589 13.7453 12.7727 13.6742 12.6306 13.5322C12.3464 13.248 12.3464 12.7873 12.6306 12.5031C15.1839 9.94985 15.1839 5.79538 12.6306 3.24209C12.3464 2.95792 12.3464 2.49725 12.6306 2.21308C12.9147 1.92897 13.3755 1.92897 13.6596 2.21308C16.7803 5.33374 16.7803 10.4115 13.6596 13.5322C13.5176 13.6742 13.3313 13.7453 13.1451 13.7453Z" fill="white"/>
<path d="M2.855 13.7453C2.66878 13.7453 2.48255 13.6742 2.3405 13.5322C-0.780166 10.4115 -0.780166 5.33374 2.3405 2.21308C2.62461 1.92897 3.08541 1.92897 3.36951 2.21308C3.65368 2.49725 3.65368 2.95792 3.36951 3.24209C0.816221 5.79538 0.816221 9.94985 3.36951 12.5031C3.65368 12.7873 3.65368 13.248 3.36951 13.5322C3.22745 13.6742 3.04123 13.7453 2.855 13.7453Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.99984 2.00001C4.68613 2.00001 1.99984 4.6863 1.99984 8C1.99984 11.3137 4.68613 14 7.99984 14C11.3135 14 13.9998 11.3137 13.9998 8C13.9998 4.6863 11.3135 2.00001 7.99984 2.00001ZM0.666504 8C0.666504 3.94992 3.94975 0.666672 7.99984 0.666672C12.0499 0.666672 15.3332 3.94992 15.3332 8C15.3332 12.0501 12.0499 15.3333 7.99984 15.3333C3.94975 15.3333 0.666504 12.0501 0.666504 8Z" fill="#6A737D"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.99984 7.33334C8.36803 7.33334 8.6665 7.63181 8.6665 8V10.6667C8.6665 11.0349 8.36803 11.3333 7.99984 11.3333C7.63165 11.3333 7.33317 11.0349 7.33317 10.6667V8C7.33317 7.63181 7.63165 7.33334 7.99984 7.33334Z" fill="#6A737D"/>
<path d="M8.6665 5.33334C8.6665 5.70153 8.36803 6 7.99984 6C7.63165 6 7.33317 5.70153 7.33317 5.33334C7.33317 4.96515 7.63165 4.66667 7.99984 4.66667C8.36803 4.66667 8.6665 4.96515 8.6665 5.33334Z" fill="#6A737D"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

@ -0,0 +1,3 @@
<svg width="20" height="24" viewBox="0 0 20 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 9.71495V3.57158L10 0.872803L20 3.57158V9.71495C20 16.0442 15.7999 21.4041 10 23.2357C4.19995 21.4041 0 16.0442 0 9.71495ZM15.3879 10.7277L15.6232 10.898L15.0819 11.5366L15.9057 14.1001L15.1431 16.7158L12.4738 15.9779L11.956 16.4036L10.9014 17.1367H9.09833L8.04379 16.4036L7.52596 15.9779L4.85671 16.7158L4.09874 14.1001L4.91784 11.5366L4.37644 10.898L4.61188 10.7277L4.23524 10.3825L4.52242 10.1553L4.14578 9.8669L4.4 9.6777L3.99989 7.74783L4.59302 5.95527L8.41104 7.38838H11.5887L15.4067 5.95527L15.9999 7.74783L15.6045 9.6777L15.854 9.8669L15.4773 10.1553L15.7644 10.3825L15.3879 10.7277ZM7.38499 13.1652L8.47065 12.6641L8.92346 13.6225L7.38499 13.1652ZM10.7685 13.6225L11.2197 12.6641L12.307 13.1652L10.7685 13.6225ZM9.24343 14.9001H10.4439L10.6519 15.0662L10.7689 16.178L10.6607 16.0674H9.02677L8.92279 16.178L9.03541 15.0662L9.24343 14.9001Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 69 KiB

@ -0,0 +1,7 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.32 8H8.63997L8.63997 16H16.32V8ZM8.63997 6C7.57958 6 6.71997 6.89543 6.71997 8V16C6.71997 17.1046 7.57958 18 8.63997 18H16.32C17.3804 18 18.24 17.1046 18.24 16V8C18.24 6.89543 17.3804 6 16.32 6H8.63997Z" fill="#037DD6"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.32 1C16.32 0.447715 16.7498 0 17.28 0H21.12C22.7106 0 24 1.34315 24 3V7C24 7.55228 23.5702 8 23.04 8C22.5098 8 22.08 7.55228 22.08 7V3C22.08 2.44772 21.6502 2 21.12 2H17.28C16.7498 2 16.32 1.55228 16.32 1Z" fill="#037DD6"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.04 16C23.5702 16 24 16.4477 24 17L24 21C24 22.6569 22.7106 24 21.12 24L17.28 24C16.7498 24 16.32 23.5523 16.32 23C16.32 22.4477 16.7498 22 17.28 22L21.12 22C21.6502 22 22.08 21.5523 22.08 21L22.08 17C22.08 16.4477 22.5098 16 23.04 16Z" fill="#037DD6"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.67999 23C7.67999 23.5523 7.25019 24 6.71999 24L2.87999 24C1.28941 24 -6.563e-06 22.6569 -6.42394e-06 21L-6.08824e-06 17C-6.04189e-06 16.4477 0.429801 16 0.959994 16C1.49019 16 1.91999 16.4477 1.91999 17L1.91999 21C1.91999 21.5523 2.3498 22 2.87999 22L6.71999 22C7.25019 22 7.67999 22.4477 7.67999 23Z" fill="#037DD6"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.96 8C0.429807 8 5.87108e-08 7.55228 1.31134e-07 7L6.55671e-07 3C8.72941e-07 1.34315 1.28942 1.69087e-07 2.88 3.77666e-07L6.72 8.81222e-07C7.25019 9.50748e-07 7.68 0.447716 7.68 1C7.68 1.55229 7.25019 2 6.72 2L2.88 2C2.34981 2 1.92 2.44772 1.92 3L1.92 7C1.92 7.55229 1.49019 8 0.96 8Z" fill="#037DD6"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.16667 3.33341C5.94501 3.33341 3.33334 5.94509 3.33334 9.16675C3.33334 12.3884 5.94501 15.0001 9.16667 15.0001C12.3883 15.0001 15 12.3884 15 9.16675C15 5.94509 12.3883 3.33341 9.16667 3.33341ZM1.66667 9.16675C1.66667 5.02461 5.02454 1.66675 9.16667 1.66675C13.3088 1.66675 16.6667 5.02461 16.6667 9.16675C16.6667 13.3089 13.3088 16.6667 9.16667 16.6667C5.02454 16.6667 1.66667 13.3089 1.66667 9.16675Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.2857 13.2858C13.6112 12.9604 14.1388 12.9604 14.4642 13.2858L18.0892 16.9108C18.4147 17.2363 18.4147 17.7639 18.0892 18.0893C17.7638 18.4148 17.2362 18.4148 16.9107 18.0893L13.2857 14.4643C12.9603 14.1389 12.9603 13.6113 13.2857 13.2858Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 14 KiB

@ -1,7 +1,7 @@
{
"name": "__MSG_appName__",
"short_name": "__MSG_appName__",
"version": "6.7.3",
"version": "7.0.0",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "__MSG_appDescription__",
@ -21,7 +21,8 @@
},
"applications": {
"gecko": {
"id": "webextension@metamask.io"
"id": "webextension@metamask.io",
"strict_min_version": "60.0"
}
},
"default_locale": "en",

@ -28,6 +28,7 @@
margin-top: 1rem;
}
</style>
<link rel="stylesheet" type="text/css" href="./index.css">
</head>
<body class="notification" style="height:600px;">
<div id="app-content">

@ -4,6 +4,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1 user-scalable=no">
<title>MetaMask</title>
<link rel="stylesheet" type="text/css" href="./index.css">
</head>
<body style="width:357px; height:600px;">
<div id="app-content"></div>

@ -116,7 +116,6 @@ setupMetamaskMeshMetrics()
* @property {boolean} useBlockie - Indicates preferred user identicon format. True for blockie, false for Jazzicon.
* @property {Object} featureFlags - An object for optional feature flags.
* @property {string} networkEndpointType - TODO: Document
* @property {boolean} isRevealingSeedWords - True if seed words are currently being recovered, and should be shown to user.
* @property {boolean} welcomeScreen - True if welcome screen should be shown.
* @property {string} currentLocale - A locale string matching the user's preferred display language.
* @property {Object} provider - The current selected network provider.
@ -253,7 +252,6 @@ function setupController (initState, initLangCode) {
const controller = new MetamaskController({
// User confirmation callbacks:
showUnconfirmedMessage: triggerUi,
unlockAccountMessage: triggerUi,
showUnapprovedTx: triggerUi,
openPopup: openPopup,
closePopup: notificationManager.closePopup.bind(notificationManager),

@ -10,7 +10,7 @@ const extension = require('extensionizer')
const PortStream = require('extension-port-stream')
const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js')).toString()
const inpageSuffix = '//# sourceURL=' + extension.extension.getURL('inpage.js') + '\n'
const inpageSuffix = '//# sourceURL=' + extension.runtime.getURL('inpage.js') + '\n'
const inpageBundle = inpageContent + inpageSuffix
// Eventually this streaming injection could be replaced with:
@ -114,6 +114,7 @@ function forwardTrafficBetweenMuxers (channelName, muxA, muxB) {
async function setupPublicApi (outStream) {
const api = {
forceReloadSite: (cb) => cb(null, forceReloadSite()),
getSiteMetadata: (cb) => cb(null, getSiteMetadata()),
}
const dnode = Dnode(api)
@ -306,3 +307,10 @@ async function domIsReady () {
// wait for load
await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve, { once: true }))
}
/**
* Reloads the site
*/
function forceReloadSite () {
window.location.reload()
}

@ -47,7 +47,7 @@ class DetectTokensController {
}
tokensToDetect.forEach((tokenAddress, index) => {
const balance = result[index]
if (!balance.isZero()) {
if (balance && !balance.isZero()) {
this._preferences.addToken(tokenAddress, contracts[tokenAddress].symbol, contracts[tokenAddress].decimals)
}
})

@ -0,0 +1,43 @@
const ObservableStore = require('obs-store')
const extend = require('xtend')
/**
* @typedef {Object} InitState
* @property {Boolean} seedPhraseBackedUp Indicates whether the user has completed the seed phrase backup challenge
*/
/**
* @typedef {Object} OnboardingOptions
* @property {InitState} initState The initial controller state
*/
/**
* Controller responsible for maintaining
* a cache of account balances in local storage
*/
class OnboardingController {
/**
* Creates a new controller instance
*
* @param {OnboardingOptions} [opts] Controller configuration parameters
*/
constructor (opts = {}) {
const initState = extend({
seedPhraseBackedUp: null,
}, opts.initState)
this.store = new ObservableStore(initState)
}
setSeedPhraseBackedUp (newSeedPhraseBackUpState) {
this.store.updateState({
seedPhraseBackedUp: newSeedPhraseBackUpState,
})
}
getSeedPhraseBackedUp () {
return this.store.getState().seedPhraseBackedUp
}
}
module.exports = OnboardingController

@ -49,13 +49,12 @@ class PreferencesController {
currentLocale: opts.initLangCode,
identities: {},
lostIdentities: {},
seedWords: null,
forgottenPassword: false,
preferences: {
useNativeCurrencyAsPrimaryCurrency: true,
},
completedOnboarding: false,
completedUiMigration: true,
migratedPrivacyMode: false,
metaMetricsId: null,
metaMetricsSendCount: 0,
}, opts.initState)
@ -80,14 +79,6 @@ class PreferencesController {
this.store.updateState({ forgottenPassword })
}
/**
* Sets the {@code seedWords} seed words
* @param {string|null} seedWords the seed words
*/
setSeedWords (seedWords) {
this.store.updateState({ seedWords })
}
/**
* Setter for the `useBlockie` property
*
@ -613,12 +604,11 @@ class PreferencesController {
return Promise.resolve(true)
}
/**
* Sets the {@code completedUiMigration} state to {@code true}, indicating that the user has completed the UI switch.
*/
completeUiMigration () {
this.store.updateState({ completedUiMigration: true })
return Promise.resolve(true)
unsetMigratedPrivacyMode () {
this.store.updateState({
migratedPrivacyMode: false,
})
return Promise.resolve()
}
//

@ -18,12 +18,13 @@ class ProviderApprovalController extends SafeEventEmitter {
*/
constructor ({ closePopup, keyringController, openPopup, preferencesController } = {}) {
super()
this.approvedOrigins = {}
this.closePopup = closePopup
this.keyringController = keyringController
this.openPopup = openPopup
this.preferencesController = preferencesController
this.store = new ObservableStore({
approvedOrigins: {},
dismissedOrigins: {},
providerRequests: [],
})
}
@ -45,7 +46,7 @@ class ProviderApprovalController extends SafeEventEmitter {
}
// register the provider request
const metadata = await getSiteMetadata(origin)
this._handleProviderRequest(origin, metadata.name, metadata.icon, false, null)
this._handleProviderRequest(origin, metadata.name, metadata.icon)
// wait for resolution of request
const approved = await new Promise(resolve => this.once(`resolvedRequest:${origin}`, ({ approved }) => resolve(approved)))
if (approved) {
@ -63,10 +64,12 @@ class ProviderApprovalController extends SafeEventEmitter {
* @param {string} siteTitle - The title of the document requesting full provider access
* @param {string} siteImage - The icon of the window requesting full provider access
*/
_handleProviderRequest (origin, siteTitle, siteImage, force, tabID) {
this.store.updateState({ providerRequests: [{ origin, siteTitle, siteImage, tabID }] })
_handleProviderRequest (origin, siteTitle, siteImage) {
this.store.updateState({ providerRequests: [{ origin, siteTitle, siteImage }] })
const isUnlocked = this.keyringController.memStore.getState().isUnlocked
if (!force && this.approvedOrigins[origin] && this.caching && isUnlocked) {
const { approvedOrigins, dismissedOrigins } = this.store.getState()
const originAlreadyHandled = approvedOrigins[origin] || dismissedOrigins[origin]
if (originAlreadyHandled && this.caching && isUnlocked) {
return
}
this.openPopup && this.openPopup()
@ -78,11 +81,27 @@ class ProviderApprovalController extends SafeEventEmitter {
* @param {string} origin - origin of the domain that had provider access approved
*/
approveProviderRequestByOrigin (origin) {
this.closePopup && this.closePopup()
const requests = this.store.getState().providerRequests
const providerRequests = requests.filter(request => request.origin !== origin)
this.store.updateState({ providerRequests })
this.approvedOrigins[origin] = true
if (this.closePopup) {
this.closePopup()
}
const { approvedOrigins, dismissedOrigins, providerRequests } = this.store.getState()
let _dismissedOrigins = dismissedOrigins
if (dismissedOrigins[origin]) {
_dismissedOrigins = Object.assign({}, dismissedOrigins)
delete _dismissedOrigins[origin]
}
const remainingProviderRequests = providerRequests.filter(request => request.origin !== origin)
this.store.updateState({
approvedOrigins: {
...approvedOrigins,
[origin]: true,
},
dismissedOrigins: _dismissedOrigins,
providerRequests: remainingProviderRequests,
})
this.emit(`resolvedRequest:${origin}`, { approved: true })
}
@ -92,19 +111,62 @@ class ProviderApprovalController extends SafeEventEmitter {
* @param {string} origin - origin of the domain that had provider access approved
*/
rejectProviderRequestByOrigin (origin) {
this.closePopup && this.closePopup()
const requests = this.store.getState().providerRequests
const providerRequests = requests.filter(request => request.origin !== origin)
this.store.updateState({ providerRequests })
delete this.approvedOrigins[origin]
if (this.closePopup) {
this.closePopup()
}
const { approvedOrigins, providerRequests, dismissedOrigins } = this.store.getState()
const remainingProviderRequests = providerRequests.filter(request => request.origin !== origin)
// We're cloning and deleting keys here because we don't want to keep unneeded keys
const _approvedOrigins = Object.assign({}, approvedOrigins)
delete _approvedOrigins[origin]
this.store.putState({
approvedOrigins: _approvedOrigins,
providerRequests: remainingProviderRequests,
dismissedOrigins: {
...dismissedOrigins,
[origin]: true,
},
})
this.emit(`resolvedRequest:${origin}`, { approved: false })
}
/**
* Silently approves access to a full Ethereum provider API for the origin
*
* @param {string} origin - origin of the domain that had provider access approved
*/
forceApproveProviderRequestByOrigin (origin) {
const { approvedOrigins, dismissedOrigins, providerRequests } = this.store.getState()
const remainingProviderRequests = providerRequests.filter(request => request.origin !== origin)
let _dismissedOrigins = dismissedOrigins
if (dismissedOrigins[origin]) {
_dismissedOrigins = Object.assign({}, dismissedOrigins)
delete _dismissedOrigins[origin]
}
this.store.updateState({
approvedOrigins: {
...approvedOrigins,
[origin]: true,
},
dismissedOrigins: _dismissedOrigins,
providerRequests: remainingProviderRequests,
})
this.emit(`forceResolvedRequest:${origin}`, { approved: true, forced: true })
}
/**
* Clears any cached approvals for user-approved origins
*/
clearApprovedOrigins () {
this.approvedOrigins = {}
this.store.updateState({
approvedOrigins: {},
})
}
/**
@ -115,8 +177,7 @@ class ProviderApprovalController extends SafeEventEmitter {
*/
shouldExposeAccounts (origin) {
const privacyMode = this.preferencesController.getFeatureFlags().privacyMode
const result = !privacyMode || Boolean(this.approvedOrigins[origin])
return result
return !privacyMode || Boolean(this.store.getState().approvedOrigins[origin])
}
}

@ -74,8 +74,10 @@ class EdgeEncryptor {
var passBuffer = Unibabel.utf8ToBuffer(password)
var saltBuffer = Unibabel.base64ToBuffer(salt)
const iterations = 10000
const length = 32 // SHA256 hash size
return new Promise((resolve) => {
var key = asmcrypto.PBKDF2_HMAC_SHA256.bytes(passBuffer, saltBuffer, 10000)
var key = asmcrypto.Pbkdf2HmacSha256(passBuffer, saltBuffer, iterations, length)
resolve(key)
})
}

@ -1,4 +1,36 @@
/*global Web3*/
// need to make sure we aren't affected by overlapping namespaces
// and that we dont affect the app with our namespace
// mostly a fix for web3's BigNumber if AMD's "define" is defined...
let __define
/**
* Caches reference to global define object and deletes it to
* avoid conflicts with other global define objects, such as
* AMD's define function
*/
const cleanContextForImports = () => {
__define = global.define
try {
global.define = undefined
} catch (_) {
console.warn('MetaMask - global.define could not be deleted.')
}
}
/**
* Restores global define object from cached reference
*/
const restoreContextAfterImports = () => {
try {
global.define = __define
} catch (_) {
console.warn('MetaMask - global.define could not be overwritten.')
}
}
cleanContextForImports()
require('web3/dist/web3.min.js')
const log = require('loglevel')
@ -46,6 +78,20 @@ inpageProvider.enable = function ({ force } = {}) {
// this will be default true so it does not break any old apps.
inpageProvider.autoRefreshOnNetworkChange = true
// publicConfig isn't populated until we get a message from background.
// Using this getter will ensure the state is available
const getPublicConfigWhenReady = async () => {
const store = inpageProvider.publicConfigStore
let state = store.getState()
// if state is missing, wait for first update
if (!state.networkVersion) {
state = await new Promise(resolve => store.once('update', resolve))
console.log('new state', state)
}
return state
}
// add metamask-specific convenience methods
inpageProvider._metamask = new Proxy({
/**
@ -87,21 +133,8 @@ inpageProvider._metamask = new Proxy({
},
})
// publicConfig isn't populated until we get a message from background.
// Using this getter will ensure the state is available
async function getPublicConfigWhenReady () {
const store = inpageProvider.publicConfigStore
let state = store.getState()
// if state is missing, wait for first update
if (!state.networkVersion) {
state = await new Promise(resolve => store.once('update', resolve))
console.log('new state', state)
}
return state
}
// Work around for web3@1.0 deleting the bound `sendAsync` but not the unbound
// `sendAsync` method on the prototype, causing `this` reference issues with drizzle
// `sendAsync` method on the prototype, causing `this` reference issues
const proxiedInpageProvider = new Proxy(inpageProvider, {
// straight up lie that we deleted the property so that it doesnt
// throw an error in strict mode
@ -161,33 +194,3 @@ inpageProvider.publicConfigStore.subscribe(function (state) {
window.postMessage('onboardingcomplete', '*')
}
})
// need to make sure we aren't affected by overlapping namespaces
// and that we dont affect the app with our namespace
// mostly a fix for web3's BigNumber if AMD's "define" is defined...
let __define
/**
* Caches reference to global define object and deletes it to
* avoid conflicts with other global define objects, such as
* AMD's define function
*/
function cleanContextForImports () {
__define = global.define
try {
global.define = undefined
} catch (_) {
console.warn('MetaMask - global.define could not be deleted.')
}
}
/**
* Restores global define object from cached reference
*/
function restoreContextAfterImports () {
try {
global.define = __define
} catch (_) {
console.warn('MetaMask - global.define could not be overwritten.')
}
}

@ -1,13 +1,6 @@
const WritableStream = require('readable-stream').Writable
const promiseToCallback = require('promise-to-callback')
module.exports = createStreamSink
function createStreamSink (asyncWriteFn, _opts) {
return new AsyncWritableStream(asyncWriteFn, _opts)
}
class AsyncWritableStream extends WritableStream {
constructor (asyncWriteFn, _opts) {
@ -22,3 +15,9 @@ class AsyncWritableStream extends WritableStream {
}
}
function createStreamSink (asyncWriteFn, _opts) {
return new AsyncWritableStream(asyncWriteFn, _opts)
}
module.exports = createStreamSink

@ -51,6 +51,8 @@ function setupEnsIpfsResolver ({ provider }) {
}
} else if (type === 'swarm-ns') {
url = `https://swarm-gateways.net/bzz:/${hash}${path}${search || ''}`
} else if (type === 'onion' || type === 'onion3') {
url = `http://${hash}.onion${path}${search || ''}`
}
} catch (err) {
console.warn(err)

@ -28,6 +28,7 @@ const PreferencesController = require('./controllers/preferences')
const AppStateController = require('./controllers/app-state')
const InfuraController = require('./controllers/infura')
const CachedBalancesController = require('./controllers/cached-balances')
const OnboardingController = require('./controllers/onboarding')
const RecentBlocksController = require('./controllers/recent-blocks')
const MessageManager = require('./lib/message-manager')
const PersonalMessageManager = require('./lib/personal-message-manager')
@ -158,6 +159,10 @@ module.exports = class MetamaskController extends EventEmitter {
initState: initState.CachedBalancesController,
})
this.onboardingController = new OnboardingController({
initState: initState.OnboardingController,
})
// ensure accountTracker updates balances after network change
this.networkController.on('networkDidChange', () => {
this.accountTracker._updateAccounts()
@ -262,6 +267,7 @@ module.exports = class MetamaskController extends EventEmitter {
NetworkController: this.networkController.store,
InfuraController: this.infuraController.store,
CachedBalancesController: this.cachedBalancesController.store,
OnboardingController: this.onboardingController.store,
})
this.memStore = new ComposableObservableStore(null, {
@ -283,6 +289,7 @@ module.exports = class MetamaskController extends EventEmitter {
ShapeshiftController: this.shapeshiftController,
InfuraController: this.infuraController.store,
ProviderApprovalController: this.providerApprovalController.store,
OnboardingController: this.onboardingController.store,
})
this.memStore.subscribe(this.sendUpdate.bind(this))
}
@ -398,6 +405,7 @@ module.exports = class MetamaskController extends EventEmitter {
const txController = this.txController
const networkController = this.networkController
const providerApprovalController = this.providerApprovalController
const onboardingController = this.onboardingController
return {
// etc
@ -420,9 +428,7 @@ module.exports = class MetamaskController extends EventEmitter {
// primary HD keyring management
addNewAccount: nodeify(this.addNewAccount, this),
placeSeedWords: this.placeSeedWords.bind(this),
verifySeedPhrase: nodeify(this.verifySeedPhrase, this),
clearSeedWordCache: this.clearSeedWordCache.bind(this),
resetAccount: nodeify(this.resetAccount, this),
removeAccount: nodeify(this.removeAccount, this),
importAccountWithStrategy: nodeify(this.importAccountWithStrategy, this),
@ -454,15 +460,16 @@ module.exports = class MetamaskController extends EventEmitter {
setAccountLabel: nodeify(preferencesController.setAccountLabel, preferencesController),
setFeatureFlag: nodeify(preferencesController.setFeatureFlag, preferencesController),
setPreference: nodeify(preferencesController.setPreference, preferencesController),
completeUiMigration: nodeify(preferencesController.completeUiMigration, preferencesController),
completeOnboarding: nodeify(preferencesController.completeOnboarding, preferencesController),
addKnownMethodData: nodeify(preferencesController.addKnownMethodData, preferencesController),
unsetMigratedPrivacyMode: nodeify(preferencesController.unsetMigratedPrivacyMode, preferencesController),
// BlacklistController
whitelistPhishingDomain: this.whitelistPhishingDomain.bind(this),
// AddressController
setAddressBook: this.addressBookController.set.bind(this.addressBookController),
removeFromAddressBook: this.addressBookController.delete.bind(this.addressBookController),
// AppStateController
setLastActiveTime: nodeify(this.appStateController.setLastActiveTime, this.appStateController),
@ -500,7 +507,11 @@ module.exports = class MetamaskController extends EventEmitter {
// provider approval
approveProviderRequestByOrigin: providerApprovalController.approveProviderRequestByOrigin.bind(providerApprovalController),
rejectProviderRequestByOrigin: providerApprovalController.rejectProviderRequestByOrigin.bind(providerApprovalController),
forceApproveProviderRequestByOrigin: providerApprovalController.forceApproveProviderRequestByOrigin.bind(providerApprovalController),
clearApprovedOrigins: providerApprovalController.clearApprovedOrigins.bind(providerApprovalController),
// onboarding controller
setSeedPhraseBackedUp: nodeify(onboardingController.setSeedPhraseBackedUp, onboardingController),
}
}
@ -845,26 +856,6 @@ module.exports = class MetamaskController extends EventEmitter {
return {...keyState, identities}
}
/**
* 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.
*
* @param {Function} cb - A callback called on completion.
*/
placeSeedWords (cb) {
this.verifySeedPhrase()
.then((seedWords) => {
this.preferencesController.setSeedWords(seedWords)
return cb(null, seedWords)
})
.catch((err) => {
return cb(err)
})
}
/**
* Verifies the validity of the current vault's seed phrase.
*
@ -898,18 +889,6 @@ 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.
*
* @param {function} cb Callback function called with the current address.
*/
clearSeedWordCache (cb) {
this.preferencesController.setSeedWords(null)
cb(null, this.preferencesController.getSelectedAddress())
}
/**
* Clears the transaction history, to allow users to force-reset their nonces.
* Mostly used in development environments, when networks are restarted with
@ -1319,6 +1298,8 @@ module.exports = class MetamaskController extends EventEmitter {
const publicApi = this.setupPublicApi(mux.createStream('publicApi'), originDomain)
this.setupProviderConnection(mux.createStream('provider'), originDomain, publicApi)
this.setupPublicConfig(mux.createStream('publicConfig'), originDomain)
this.providerApprovalController.on(`forceResolvedRequest:${originDomain}`, publicApi.forceReloadSite)
}
/**
@ -1392,6 +1373,32 @@ module.exports = class MetamaskController extends EventEmitter {
* @param {string} origin - The URI of the requesting resource.
*/
setupProviderConnection (outStream, origin, publicApi) {
const getSiteMetadata = publicApi && publicApi.getSiteMetadata
const engine = this.setupProviderEngine(origin, getSiteMetadata)
// setup connection
const providerStream = createEngineStream({ engine })
pump(
outStream,
providerStream,
outStream,
(err) => {
// cleanup filter polyfill middleware
engine._middleware.forEach((mid) => {
if (mid.destroy && typeof mid.destroy === 'function') {
mid.destroy()
}
})
if (err) log.error(err)
}
)
}
/**
* A method for creating a provider that is safely restricted for the requesting domain.
**/
setupProviderEngine (origin, getSiteMetadata) {
// setup json rpc engine stack
const engine = new RpcEngine()
const provider = this.provider
@ -1399,6 +1406,7 @@ module.exports = class MetamaskController extends EventEmitter {
// create filter polyfill middleware
const filterMiddleware = createFilterMiddleware({ provider, blockTracker })
// create subscription polyfill middleware
const subscriptionManager = createSubscriptionManager({ provider, blockTracker })
subscriptionManager.events.on('notification', (message) => engine.emit('notification', message))
@ -1414,24 +1422,11 @@ module.exports = class MetamaskController extends EventEmitter {
// requestAccounts
engine.push(this.providerApprovalController.createMiddleware({
origin,
getSiteMetadata: publicApi && publicApi.getSiteMetadata,
getSiteMetadata,
}))
// forward to metamask primary provider
engine.push(providerAsMiddleware(provider))
// setup connection
const providerStream = createEngineStream({ engine })
pump(
outStream,
providerStream,
outStream,
(err) => {
// cleanup filter polyfill middleware
filterMiddleware.destroy()
if (err) log.error(err)
}
)
return engine
}
/**
@ -1485,6 +1480,10 @@ module.exports = class MetamaskController extends EventEmitter {
const publicApi = {
// wrap with an await remote
forceReloadSite: async () => {
const remote = await getRemote()
return await pify(remote.forceReloadSite)()
},
getSiteMetadata: async () => {
const remote = await getRemote()
return await pify(remote.getSiteMetadata)()
@ -1798,3 +1797,4 @@ module.exports = class MetamaskController extends EventEmitter {
return this.keyringController.setLocked()
}
}

@ -0,0 +1,33 @@
const version = 34
const clone = require('clone')
/**
* The purpose of this migration is to enable the {@code privacyMode} feature flag and set the user as being migrated
* if it was {@code false}.
*/
module.exports = {
version,
migrate: async function (originalVersionedData) {
const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data
versionedData.data = transformState(state)
return versionedData
},
}
function transformState (state) {
const { PreferencesController } = state
if (PreferencesController) {
const featureFlags = PreferencesController.featureFlags || {}
if (!featureFlags.privacyMode && typeof PreferencesController.migratedPrivacyMode === 'undefined') {
// Mark the state has being migrated and enable Privacy Mode
PreferencesController.migratedPrivacyMode = true
featureFlags.privacyMode = true
}
}
return state
}

@ -0,0 +1,28 @@
// next version number
const version = 35
/*
Removes the deprecated 'seedWords' state
*/
const clone = require('clone')
module.exports = {
version,
migrate: async function (originalVersionedData) {
const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
versionedData.data = transformState(versionedData.data)
return versionedData
},
}
function transformState (state) {
if (state.PreferencesController && state.PreferencesController.seedWords !== undefined) {
delete state.PreferencesController.seedWords
}
return state
}

@ -37,11 +37,11 @@ function start () {
function setupControllerConnection (connectionStream, cb) {
const eventEmitter = new EventEmitter()
const accountManagerDnode = dnode({
const metaMaskControllerDnode = dnode({
sendUpdate (state) {
eventEmitter.emit('update', state)
},
})
connectionStream.pipe(accountManagerDnode).pipe(connectionStream)
accountManagerDnode.once('remote', (accountManager) => cb(null, accountManager))
connectionStream.pipe(metaMaskControllerDnode).pipe(connectionStream)
metaMaskControllerDnode.once('remote', (backgroundConnection) => cb(null, backgroundConnection))
}

@ -68,7 +68,7 @@ class ExtensionPlatform {
const nonce = parseInt(txMeta.txParams.nonce, 16)
const title = 'Confirmed transaction'
const message = `Transaction ${nonce} confirmed! View on EtherScan`
const message = `Transaction ${nonce} confirmed! View on Etherscan`
this._showNotification(title, message, url)
}
@ -92,12 +92,12 @@ class ExtensionPlatform {
}
_subscribeToNotificationClicked () {
if (!extension.notifications.onClicked.hasListener(this._viewOnEtherScan)) {
extension.notifications.onClicked.addListener(this._viewOnEtherScan)
if (!extension.notifications.onClicked.hasListener(this._viewOnEtherscan)) {
extension.notifications.onClicked.addListener(this._viewOnEtherscan)
}
}
_viewOnEtherScan (txId) {
_viewOnEtherscan (txId) {
if (txId.startsWith('http://')) {
extension.tabs.create({ url: txId })
}

@ -1,77 +0,0 @@
const {EventEmitter} = require('events')
const async = require('async')
const Dnode = require('dnode')
const Eth = require('ethjs')
const EthQuery = require('eth-query')
const launchMetamaskUi = require('../../ui')
const StreamProvider = require('web3-stream-provider')
const {setupMultiplex} = require('./lib/stream-utils.js')
module.exports = initializePopup
/**
* Asynchronously initializes the MetaMask popup UI
*
* @param {{ container: Element, connectionStream: * }} config Popup configuration object
* @param {Function} cb Called when initialization is complete
*/
function initializePopup ({ container, connectionStream }, cb) {
// setup app
async.waterfall([
(cb) => connectToAccountManager(connectionStream, cb),
(accountManager, cb) => launchMetamaskUi({ container, accountManager }, cb),
], cb)
}
/**
* Establishes streamed connections to background scripts and a Web3 provider
*
* @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
* @param {Function} cb Called when controller connection is established
*/
function connectToAccountManager (connectionStream, cb) {
// setup communication with background
// setup multiplexing
const mx = setupMultiplex(connectionStream)
// connect features
setupControllerConnection(mx.createStream('controller'), cb)
setupWeb3Connection(mx.createStream('provider'))
}
/**
* Establishes a streamed connection to a Web3 provider
*
* @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
*/
function setupWeb3Connection (connectionStream) {
const providerStream = new StreamProvider()
providerStream.pipe(connectionStream).pipe(providerStream)
connectionStream.on('error', console.error.bind(console))
providerStream.on('error', console.error.bind(console))
global.ethereumProvider = providerStream
global.ethQuery = new EthQuery(providerStream)
global.eth = new Eth(providerStream)
}
/**
* Establishes a streamed connection to the background account manager
*
* @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
* @param {Function} cb Called when the remote account manager connection is established
*/
function setupControllerConnection (connectionStream, cb) {
// this is a really sneaky way of adding EventEmitter api
// to a bi-directional dnode instance
const eventEmitter = new EventEmitter()
const accountManagerDnode = Dnode({
sendUpdate: function (state) {
eventEmitter.emit('update', state)
},
})
connectionStream.pipe(accountManagerDnode).pipe(connectionStream)
accountManagerDnode.once('remote', function (accountManager) {
// setup push events
accountManager.on = eventEmitter.on.bind(eventEmitter)
cb(null, accountManager)
})
}

@ -1,14 +1,19 @@
const injectCss = require('inject-css')
const NewMetaMaskUiCss = require('../../ui/css')
const startPopup = require('./popup-core')
const PortStream = require('extension-port-stream')
const { getEnvironmentType } = require('./lib/util')
const { ENVIRONMENT_TYPE_NOTIFICATION, ENVIRONMENT_TYPE_FULLSCREEN } = require('./lib/enums')
const { ENVIRONMENT_TYPE_NOTIFICATION, ENVIRONMENT_TYPE_FULLSCREEN, ENVIRONMENT_TYPE_POPUP } = require('./lib/enums')
const extension = require('extensionizer')
const ExtensionPlatform = require('./platforms/extension')
const NotificationManager = require('./lib/notification-manager')
const notificationManager = new NotificationManager()
const setupSentry = require('./lib/setupSentry')
const {EventEmitter} = require('events')
const Dnode = require('dnode')
const Eth = require('ethjs')
const EthQuery = require('eth-query')
const urlUtil = require('url')
const launchMetaMaskUi = require('../../ui')
const StreamProvider = require('web3-stream-provider')
const {setupMultiplex} = require('./lib/stream-utils.js')
const log = require('loglevel')
start().catch(log.error)
@ -41,35 +46,117 @@ async function start () {
const extensionPort = extension.runtime.connect({ name: windowType })
const connectionStream = new PortStream(extensionPort)
// start ui
const activeTab = await queryCurrentActiveTab(windowType)
initializeUiWithTab(activeTab)
function closePopupIfOpen (windowType) {
if (windowType !== ENVIRONMENT_TYPE_NOTIFICATION) {
// should close only chrome popup
notificationManager.closePopup()
}
}
function displayCriticalError (container, err) {
container.innerHTML = '<div class="critical-error">The MetaMask app failed to load: please open and close MetaMask again to restart.</div>'
container.style.height = '80px'
log.error(err.stack)
throw err
}
function initializeUiWithTab (tab) {
const container = document.getElementById('app-content')
startPopup({ container, connectionStream }, (err, store) => {
if (err) return displayCriticalError(err)
initializeUi(tab, container, connectionStream, (err, store) => {
if (err) {
return displayCriticalError(container, err)
}
const state = store.getState()
const { metamask: { completedOnboarding } = {} } = state
if (!completedOnboarding && windowType !== ENVIRONMENT_TYPE_FULLSCREEN) {
global.platform.openExtensionInBrowser()
}
})
}
}
async function queryCurrentActiveTab (windowType) {
return new Promise((resolve) => {
// At the time of writing we only have the `activeTab` permission which means
// that this query will only succeed in the popup context (i.e. after a "browserAction")
if (windowType !== ENVIRONMENT_TYPE_POPUP) {
resolve({})
return
}
injectCss(NewMetaMaskUiCss())
extension.tabs.query({active: true, currentWindow: true}, (tabs) => {
const [activeTab] = tabs
const {title, url} = activeTab
const { hostname: origin, protocol } = url ? urlUtil.parse(url) : {}
resolve({
title, origin, protocol, url,
})
})
})
}
function initializeUi (activeTab, container, connectionStream, cb) {
connectToAccountManager(connectionStream, (err, backgroundConnection) => {
if (err) {
return cb(err)
}
function closePopupIfOpen (windowType) {
if (windowType !== ENVIRONMENT_TYPE_NOTIFICATION) {
// should close only chrome popup
notificationManager.closePopup()
launchMetaMaskUi({
activeTab,
container,
backgroundConnection,
}, cb)
})
}
/**
* Establishes a connection to the background and a Web3 provider
*
* @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
* @param {Function} cb Called when controller connection is established
*/
function connectToAccountManager (connectionStream, cb) {
const mx = setupMultiplex(connectionStream)
setupControllerConnection(mx.createStream('controller'), cb)
setupWeb3Connection(mx.createStream('provider'))
}
function displayCriticalError (err) {
container.innerHTML = '<div class="critical-error">The MetaMask app failed to load: please open and close MetaMask again to restart.</div>'
container.style.height = '80px'
log.error(err.stack)
throw err
/**
* Establishes a streamed connection to a Web3 provider
*
* @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
*/
function setupWeb3Connection (connectionStream) {
const providerStream = new StreamProvider()
providerStream.pipe(connectionStream).pipe(providerStream)
connectionStream.on('error', console.error.bind(console))
providerStream.on('error', console.error.bind(console))
global.ethereumProvider = providerStream
global.ethQuery = new EthQuery(providerStream)
global.eth = new Eth(providerStream)
}
/**
* Establishes a streamed connection to the background account manager
*
* @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
* @param {Function} cb Called when the remote account manager connection is established
*/
function setupControllerConnection (connectionStream, cb) {
const eventEmitter = new EventEmitter()
const backgroundDnode = Dnode({
sendUpdate: function (state) {
eventEmitter.emit('update', state)
},
})
connectionStream.pipe(backgroundDnode).pipe(connectionStream)
backgroundDnode.once('remote', function (backgroundConnection) {
backgroundConnection.on = eventEmitter.on.bind(eventEmitter)
cb(null, backgroundConnection)
})
}

@ -0,0 +1,24 @@
module.exports = function (api) {
api.cache(false)
return {
presets: [
[
'@babel/preset-env',
{
targets: {
browsers: [
'chrome >= 58',
'firefox >= 60',
],
},
},
],
'@babel/preset-react',
],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-object-rest-spread',
],
}
}

@ -1,26 +1,60 @@
#! /bin/bash
# update tags
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
readonly URL='https://github.com/MetaMask/metamask-extension'
git fetch --tags
# get origin
URL='https://github.com/MetaMask/metamask-extension'
# get git logs from last tag until HEAD, pretty by 'subject::body' filtered by grep for PRs made with Github squash merge or Github regular merge
LOG=$(git log $(git describe --tags $(git rev-list --tags --max-count=1))..HEAD --pretty="%s::%b" --reverse --grep="Merge pull request #" --grep="(#");
while read -r line; do
# get git log subject
SUBJECT=$(echo $line | sed -E 's/(.*):{2}(.*)/\1/')
# get git log PR id, PR made with Github squash merge or Github regular merge
PR=$(echo $SUBJECT | sed 's/^.*(#\([^&]*\)).*/\1/' | sed 's/^.*#\([^&]*\) from.*/\1/')
# if PR made with Github squash merge, subject is the body
if [ -z "$(echo $line | sed -E 's/(.*):{2}(.*)/\2/')" ]; then
BODY=$(echo $SUBJECT | sed "s/(#$PR)//g"); else
BODY=$(echo $line | sed -E 's/(.*):{2}(.*)/\2/')
most_recent_tag="$(git describe --tags "$(git rev-list --tags --max-count=1)")"
git rev-list "${most_recent_tag}"..HEAD | while read commit
do
subject="$(git show -s --format="%s" "$commit")"
# Squash & Merge: the commit subject is parsed as `<description> (#<PR ID>)`
if grep -E -q '\(#[[:digit:]]+\)' <<< "$subject"
then
pr="$(awk '{print $NF}' <<< "$subject" | tr -d '()')"
prefix="[$pr]($URL/pull/${pr###}): "
description="$(awk '{NF--; print $0}' <<< "$subject")"
# Merge: the PR ID is parsed from the git subject (which is of the form `Merge pull request
# #<PR ID> from <branch>`, and the description is assumed to be the first line of the body.
# If no body is found, the description is set to the commit subject
elif grep -E -q '#[[:digit:]]+\sfrom' <<< "$subject"
then
pr="$(awk '{print $4}' <<< "$subject")"
prefix="[$pr]($URL/pull/${pr###}): "
first_line_of_body="$(git show -s --format="%b" "$commit" | head -n 1 | tr -d '\r')"
if [[ -z "$first_line_of_body" ]]
then
description="$subject"
else
description="$first_line_of_body"
fi
# Normal commits: The commit subject is the description, and the PR ID is omitted.
else
pr=''
prefix=''
description="$subject"
fi
# add entry to CHANGELOG
if [[ "$OSTYPE" == "linux-gnu" ]]; then
if [[ "$OSTYPE" == "linux-gnu" ]]
then
# shellcheck disable=SC1004
sed -i'' '/## Current Develop Branch/a\
- [#'"$PR"']('"$URL"'/pull/'"$PR"'): '"$BODY"''$'\n' CHANGELOG.md; else
- '"$prefix$description"''$'\n' CHANGELOG.md
else
# shellcheck disable=SC1004
sed -i '' '/## Current Develop Branch/a\
- [#'"$PR"']('"$URL"'/pull/'"$PR"'): '"$BODY"''$'\n' CHANGELOG.md;
- '"$prefix$description"''$'\n' CHANGELOG.md
fi
done <<< "$LOG"
done
echo 'CHANGELOG updated'

@ -8,8 +8,6 @@
*
* This is a convenient way to develop and test the plugin
* without having to re-open the plugin or even re-build it.
*
* To use, run `npm run mock`.
*/
const render = require('react-dom').render
@ -58,13 +56,6 @@ function updateQueryParams (newView) {
}
}
//
// CSS
//
const MetaMaskUiCss = require('../ui/css')
const injectCss = require('inject-css')
//
// MetaMask Controller
//
@ -72,7 +63,6 @@ const injectCss = require('inject-css')
const controller = new MetamaskController({
// User confirmation callbacks:
showUnconfirmedMessage: noop,
unlockAccountMessage: noop,
showUnapprovedTx: noop,
platform: {},
// initial state
@ -101,9 +91,6 @@ function modifyBackgroundConnection (backgroundConnectionModifier) {
actions._setBackgroundConnection(modifiedBackgroundConnection)
}
var css = MetaMaskUiCss()
injectCss(css)
// parse opts
var store = configureStore(firstState)

@ -1,44 +0,0 @@
/* MockExtension
*
* A module for importing the global extension polyfiller
* and stubbing out all the extension methods with appropriate mocks.
*/
const extension = require('extensionizer')
const noop = function () {}
const apis = [
'alarms',
'bookmarks',
'browserAction',
'commands',
'contextMenus',
'cookies',
'downloads',
'events',
'extension',
'extensionTypes',
'history',
'i18n',
'idle',
'notifications',
'pageAction',
'runtime',
'storage',
'tabs',
'webNavigation',
'webRequest',
'windows',
]
apis.forEach(function (api) {
extension[api] = {}
})
extension.runtime.reload = noop
extension.tabs.create = noop
extension.runtime.getManifest = function () {
return {
version: 'development',
}
}

@ -0,0 +1 @@
require('react-devtools')

@ -5,7 +5,7 @@ echo "Rolling back to version $1"
# Checkout branch to increment version
git checkout -b version-increment-$1
npm run version:bump patch
yarn version:bump patch
# Store the new version name
NEW_VERSION=$(cat app/manifest.json | jq -r .version)

@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
ganache_cli="$(npm bin)/ganache-cli"
seed_phrase="${GANACHE_SEED_PHRASE:-phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent}"
_term () {
printf '%s\n' "Received SIGTERM, sending SIGKILL to Ganache"
kill -KILL "$child" 2>/dev/null
exit 42
}
_int () {
printf '%s\n' "Received SIGINT, sending SIGKILL to Ganache"
kill -KILL "$child" 2>/dev/null
exit 42
}
trap _term SIGTERM
trap _int SIGINT
$ganache_cli --noVMErrorsOnRPCResponse --networkId 5777 --mnemonic "$seed_phrase" ${GANACHE_ARGS:-} &
child=$!
wait "$child"

File diff suppressed because one or more lines are too long

@ -133,7 +133,6 @@
"address": "0x704107d04affddd9b66ab9de3dd7b095852e9b69"
}
},
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"network": "1",
"seedWords": null,
"unconfMsgs": {},

@ -99,7 +99,6 @@
"status": "confirmed",
"containsDelegateCall": false
}],
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"network": "2",
"seedWords": null,
"unconfMsgs": {},

@ -57,7 +57,6 @@
}
},
"transactions": [],
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"network": "2",
"seedWords": null,
"unconfMsgs": {},

@ -48,7 +48,6 @@
"gasPrice": "4a817c800"
}
},
"currentCurrency": "USD",
"conversionRate": 12.7200827,
"conversionDate": 1487363041,
"noActiveNotices": true,

@ -22,8 +22,6 @@
"name": "Send Account 4"
}
},
"unapprovedTxs": {},
"currentCurrency": "USD",
"conversionRate": 1200.88200327,
"conversionDate": 1489013762,
"noActiveNotices": true,
@ -134,7 +132,6 @@
"useNativeCurrencyAsPrimaryCurrency": true,
"showFiatInTestnets": true
},
"completedUiMigration": true,
"frequentRpcListDetail": []
},
"appState": {
@ -203,7 +200,6 @@
},
"basicEstimateIsLoading": false,
"gasEstimatesLoading": false,
"basicPriceAndTimeEstimates": [],
"priceAndTimeEstimates": [
{
"expectedTime": "1374.1168296452973076627",

@ -24,8 +24,6 @@
}
},
"cachedBalances": {},
"unapprovedTxs": {},
"currentCurrency": "USD",
"conversionRate": 1200.88200327,
"conversionDate": 1489013762,
"noActiveNotices": true,
@ -157,7 +155,6 @@
"preferences": {
"useNativeCurrencyAsPrimaryCurrency": true
},
"completedUiMigration": true,
"frequentRpcListDetail": []
},
"appState": {
@ -229,7 +226,6 @@
},
"basicEstimateIsLoading": false,
"gasEstimatesLoading": false,
"basicPriceAndTimeEstimates": [],
"priceAndTimeEstimates": [
{
"expectedTime": "1374.1168296452973076627",

@ -25,7 +25,6 @@
},
"cachedBalances": {},
"unapprovedTxs": {},
"currentCurrency": "USD",
"conversionRate": 19855,
"conversionDate": 1489013762,
"noActiveNotices": true,
@ -116,7 +115,6 @@
"useNativeCurrencyAsPrimaryCurrency": true,
"showFiatInTestnets": true
},
"completedUiMigration": true,
"frequentRpcListDetail": []
},
"appState": {
@ -179,7 +177,6 @@
},
"basicEstimateIsLoading": false,
"gasEstimatesLoading": false,
"basicPriceAndTimeEstimates": [],
"priceAndTimeEstimates": [
{
"expectedTime": "1374.1168296452973076627",

@ -54,7 +54,6 @@
}
},
"transactions": [],
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"network": "2",
"seedWords": null,
"unconfMsgs": {},

@ -7,7 +7,6 @@
"computedBalances": {},
"frequentRpcList": [],
"unapprovedTxs": {},
"currentCurrency": "USD",
"featureFlags": {"betaUI": false},
"conversionRate": 12.7527416,
"conversionDate": 1487624341,

@ -11,7 +11,6 @@
"conversionDate": 1473358355,
"accounts": {},
"transactions": [],
"selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"network": "1473186153102",
"seedWords": null,
"unconfMsgs": {},

@ -61,7 +61,6 @@
}
},
"transactions": [],
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"network": "2",
"seedWords": null,
"unconfMsgs": {},

@ -36,7 +36,6 @@
"provider": {
"type": "testnet"
},
"selectedAddress": "0xa6ef573d60594731178b7f85d80da13cc2af52dd",
"unconfMsgs": {},
"messages": [],
"selectedAddress": "0xa6ef573d60594731178b7f85d80da13cc2af52dd",

File diff suppressed because one or more lines are too long

@ -351,7 +351,6 @@
"hash": "0xb6e6ff57e7b5f6bd7f2e6dc44c39f4e858a227c9509586634ca547179345a13e"
}
],
"selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"network": "1471904489432",
"seedWords": null,
"unconfMsgs": {

@ -31,7 +31,6 @@
"maxCost": "de234b52e4a0800"
}
},
"currentCurrency": "USD",
"conversionRate": 12.59854817,
"conversionDate": 1487662141,
"noActiveNotices": true,

@ -18,7 +18,6 @@
}
},
"unapprovedTxs": {},
"currentCurrency": "USD",
"conversionRate": 13.2126613,
"conversionDate": 1487888522,
"noActiveNotices": true,

@ -52,7 +52,6 @@
"hash": "0xad609a6931f54a575ad71222ffc27cd6746017106d5b89f4ad300b37b273f8ac"
}
],
"selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"network": "1479753732793",
"isEthConfirmed": true,
"unconfMsgs": {},

@ -1,9 +1,4 @@
{
"confirmTransaction": {
"txData": {
"id": 4768706228115573
}
},
"metamask": {
"completedOnboarding": true,
"isInitialized": true,
@ -30,8 +25,6 @@
},
"cachedBalances": {},
"assetImages": {},
"unapprovedTxs": {},
"currentCurrency": "USD",
"conversionRate": 1200.88200327,
"conversionDate": 1489013762,
"noActiveNotices": true,
@ -158,7 +151,6 @@
"useNativeCurrencyAsPrimaryCurrency": true,
"showFiatInTestnets": true
},
"completedUiMigration": true,
"frequentRpcListDetail": []
},
"appState": {
@ -190,7 +182,9 @@
"warnings": {}
},
"confirmTransaction": {
"txData": {},
"txData": {
"id": 4768706228115573
},
"tokenData": {},
"methodData": {},
"tokenProps": {
@ -227,7 +221,6 @@
},
"basicEstimateIsLoading": false,
"gasEstimatesLoading": false,
"basicPriceAndTimeEstimates": [],
"priceAndTimeEstimates": [
{
"expectedTime": "1374.1168296452973076627",

@ -25,7 +25,6 @@
},
"cachedBalances": {},
"unapprovedTxs": {},
"currentCurrency": "USD",
"conversionRate": 1200.88200327,
"conversionDate": 1489013762,
"noActiveNotices": true,
@ -117,7 +116,6 @@
"useNativeCurrencyAsPrimaryCurrency": true,
"showFiatInTestnets": true
},
"completedUiMigration": true,
"frequentRpcListDetail": []
},
"appState": {
@ -187,7 +185,6 @@
},
"basicEstimateIsLoading": false,
"gasEstimatesLoading": false,
"basicPriceAndTimeEstimates": [],
"priceAndTimeEstimates": [
{
"expectedTime": "1374.1168296452973076627",

@ -23,7 +23,6 @@
},
"assetImages": {},
"unapprovedTxs": {},
"currentCurrency": "USD",
"conversionRate": 16.88200327,
"conversionDate": 1489013762,
"noActiveNotices": true,

@ -46,7 +46,6 @@
}
},
"transactions": [],
"selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"network": "1",
"seedWords": null,
"unconfMsgs": {},

@ -1059,7 +1059,6 @@
"preferences": {
"useNativeCurrencyAsPrimaryCurrency": true
},
"completedUiMigration": true,
"frequentRpcListDetail": []
},
"appState": {
@ -1110,7 +1109,6 @@
},
"basicEstimateIsLoading": false,
"gasEstimatesLoading": false,
"basicPriceAndTimeEstimates": [],
"priceAndTimeEstimates": [
{
"expectedTime": "1374.1168296452973076627",

@ -1,15 +0,0 @@
# Development Tools & Configurations
This folder contains configuration files which are used by the the different
development-tools, like e.g. JsDoc.
## Appveyor
https://www.appveyor.com/docs/build-configuration/#alternative-yaml-file-location
Withtin the configuration, point to a weblocation of a txt config file:
https://ci.appveyor.com/project/lazaridiscom/mm-vault/settings
https://raw.githubusercontent.com/lazaridiscom/mm-vault/master/dev/tools/appveyor.txt

@ -1,21 +0,0 @@
# Test against the latest version of this Node.js version
environment:
nodejs_version: "8"
# Install scripts. (runs after repo cloning)
install:
# Get the latest stable version of Node.js or io.js
- ps: Install-Product node $env:nodejs_version
# install modules
- npm install
# Post-install test scripts.
test_script:
# Output useful info for debugging.
- node --version
- npm --version
# run tests
- npm test
# Don't actually build.
build: off

@ -1,96 +0,0 @@
/* UI DEV
*
* This is a utility module.
* It initializes a minimalist browserifiable project
* that contains the Metamask UI, with a mocked state.
*
* Includes a state menu for switching between different
* mocked states, along with query param support,
* so those states are preserved when live-reloading.
*
* This is a convenient way to develop on the UI
* without having to re-enter your password
* every time the plugin rebuilds.
*
* To use, run `npm run ui`.
*/
const render = require('react-dom').render
const h = require('react-hyperscript')
const Root = require('../ui/app/pages')
const configureStore = require('./uiStore')
const states = require('./states')
const Selector = require('./selector')
// logger
const log = require('loglevel')
window.log = log
log.setDefaultLevel(1)
// Query String
const qs = require('qs')
const queryString = qs.parse(window.location.href.split('#')[1])
let selectedView = queryString.view || 'first time'
updateQueryParams(selectedView)
// CSS
const MetaMaskUiCss = require('../ui/css')
const injectCss = require('inject-css')
function updateQueryParams (newView) {
queryString.view = newView
const params = qs.stringify(queryString)
window.location.href = window.location.href.split('#')[0] + `#${params}`
}
const actions = {
_setBackgroundConnection () {},
update: function (stateName) {
selectedView = stateName
updateQueryParams(stateName)
const newState = states[selectedView]
return {
type: 'GLOBAL_FORCE_UPDATE',
value: newState,
}
},
}
var css = MetaMaskUiCss()
injectCss(css)
// parse opts
var store = configureStore(states[selectedView])
// start app
startApp()
function startApp () {
const body = document.body
const container = document.createElement('div')
container.id = 'test-container'
body.appendChild(container)
render(
h('.super-dev-container', [
h(Selector, { actions, selectedKey: selectedView, states, store }),
h('#app-content', {
style: {
height: '500px',
width: '360px',
boxShadow: 'grey 0px 2px 9px',
margin: '20px',
},
}, [
h(Root, {
store: store,
}),
]),
]
), container)
}

@ -1,18 +0,0 @@
const createStore = require('redux').createStore
const applyMiddleware = require('redux').applyMiddleware
const thunkMiddleware = require('redux-thunk').default
const createLogger = require('redux-logger').createLogger
const rootReducer = require('../ui/app/ducks')
module.exports = configureStore
const loggerMiddleware = createLogger()
const createStoreWithMiddleware = applyMiddleware(
thunkMiddleware,
loggerMiddleware
)(createStore)
function configureStore (initialState) {
return createStoreWithMiddleware(rootReducer, initialState)
}

@ -15,7 +15,6 @@ To learn how to develop MetaMask-compatible applications, visit our [Developer D
- [Publishing Guide](./publishing.md)
- [How to live reload on local dependency changes](./developing-on-deps.md)
- [How to add new networks to the Provider Menu](./adding-new-networks.md)
- [How to manage notices that appear when the app starts up](./notices.md)
- [How to port MetaMask to a new platform](./porting_to_new_environment.md)
- [How to generate a visualization of this repository's development](./development-visualization.md)
- [How to add a feature behind a secret feature flag](./secret-preferences.md)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 214 KiB

@ -1,7 +1,7 @@
# How to Bump MetaMask's Version Automatically
```
npm run version:bump patch
yarn version:bump patch
```
MetaMask publishes using a loose [semver](https://semver.org/) interpretation. We divide the three segments of our version into three types of version bump:
@ -20,7 +20,7 @@ Means a fix for a bug, or correcting something that should have been assumed to
# Bumping the version
`npm run version:bump $BUMP_TYPE` where `$BUMP_TYPE` is one of `major`, `minor`, or `patch`.
`yarn version:bump $BUMP_TYPE` where `$BUMP_TYPE` is one of `major`, `minor`, or `patch`.
This will increment the version in the `app/manifest.json` and `CHANGELOG.md` files according to our current protocol, where the manifest's version is updated, and any line items currently under the changelog's "master" section are now under the new dated version section.

@ -0,0 +1,20 @@
# Account Menu
The account menu is the popup menu which contains options such as:
- Logging out
- Switching accounts
- Creating a new account
- Importing an account
- Connecting a HW wallet
- Looking up info & help
- Adjusting settings
It can be seen below where it has been outlined with a red box
![Screenshot of account menu](https://i.imgur.com/xpkfIuR.png)
Above screenshot showing the menu bar in MetaMask 6.7.1

@ -3,7 +3,7 @@
To enjoy the live-reloading that `gulp dev` offers while working on the dependencies:
1. Clone the dependency locally.
2. `npm install` in its folder.
3. Run `npm link` in its folder.
4. Run `npm link $DEP_NAME` in this project folder.
5. Next time you `npm start` it will watch the dependency for changes as well!
2. `npm install` or `yarn install` in its folder.
3. Run `yarn link` in its folder.
4. Run `yarn link $DEP_NAME` in this project folder.
5. Next time you `yarn start` it will watch the dependency for changes as well!

@ -1,15 +0,0 @@
## Generating Notices
To add a notice:
```
npm run generateNotice
```
Enter the body of your notice into the text editor that pops up, without including the body. Be sure to save the file before closing the window!
Afterwards, enter the title of the notice in the command line and press enter. Afterwards, add and commit the new changes made.
To delete a notice:
```
npm run deleteNotice
```
A list of active notices will pop up. Enter the corresponding id in the command line prompt and add and commit the new changes afterwards.

@ -10,6 +10,41 @@ The `metamask-background` describes the file at `app/scripts/background.js`, whi
When a new site is visited, the WebExtension creates a new `ContentScript` in that page's context, which can be seen at `app/scripts/contentscript.js`. This script represents a per-page setup process, which creates the per-page `web3` api, connects it to the background script via the Port API (wrapped in a [stream abstraction](https://github.com/substack/stream-handbook)), and injected into the DOM before anything loads.
You can choose to use this streaming interface to connect to the MetaMask controller over any transport you can wrap with a stream, by connecting it to the [metamask-inpage-provider](https://github.com/MetaMask/metamask-inpage-provider), but you can also construct a provider per domain like this:
```javascript
const providerFromEngine = require('eth-json-rpc-middleware/providerFromEngine')
/**
* returns a provider restricted to the requesting domain
**/
function incomingConnection (domain, getSiteMetadata) {
const engine = metamaskController.setupProviderEngine(domain, getSiteMetadata)
const provider = providerFromEngine(engine)
return provider
}
```
Please note if you take this approach, you are responsible for cleaning up the filters when the page is closed:
```
const filterMiddleware = engine._middleware.filter(mid => mid.name === 'filterMiddleware')[0]
filterMiddleware.destroy()
```
### getSiteMetadata()
This method is used to enhance our confirmation screens with images and text representing the requesting domain.
It should return a promise that resolves with an object with the following properties:
- `name`: The requesting site's name.
- `icon`: A URI representing the site's logo.
### Using the Streams Interface
Only use this if you intend to construct the [metamask-inpage-provider](https://github.com/MetaMask/metamask-inpage-provider) over a stream!
The most confusing part about porting MetaMask to a new platform is the way we provide the Web3 API over a series of streams between contexts. Once you understand how we create the [MetamaskInpageProvider](https://github.com/MetaMask/metamask-inpage-provider/blob/master/index.js) in the [inpage.js script](../app/scripts/inpage.js), you will be able to understand how the [port-stream](../app/scripts/lib/port-stream.js) is just a thin wrapper around the [postMessage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage), and a similar stream API can be wrapped around any communication channel to communicate with the `MetaMaskController` via its `setupUntrustedCommunication(stream, domain)` method.
### The MetaMask Controller
@ -52,7 +87,7 @@ Returns a JavaScript object filled with callback functions representing every op
The MetaMask UI is essentially just a website that can be configured by passing it the API and state subscriptions from above. Anyone could make a UI that consumes these, effectively reskinning MetaMask.
You can see this in action in our file [ui/index.js](https://github.com/MetaMask/metamask-extension/blob/master/ui/index.js). There you can see an argument being passed in named `accountManager`, which is essentially a MetaMask controller (forgive its really outdated parameter name!). With access to that object, the UI is able to initialize a whole React/Redux app that relies on this API for its account/blockchain-related/persistent states.
You can see this in action in our file [ui/index.js](https://github.com/MetaMask/metamask-extension/blob/master/ui/index.js). There you can see the background connection being passed in, which is essentially the MetaMask controller. With access to that object, the UI is able to initialize a whole React/Redux app that relies on this API for its account/blockchain-related/persistent states.
## Putting it Together
@ -64,7 +99,6 @@ In that file, there's a lot going on, so it's maybe worth focusing on our MetaMa
const controller = new MetamaskController({
// User confirmation callbacks:
showUnconfirmedMessage: triggerUi,
unlockAccountMessage: triggerUi,
showUnapprovedTx: triggerUi,
// initial state
initState,

@ -20,9 +20,9 @@ We try to ensure certain criteria are met before deploying:
## Incrementing Version & Changelog
Version can be automatically incremented [using our bump script](./bumping-version.md).
Version can be automatically incremented by creating a branch with the name `Version-vX.Y.Z`, where `X`, `Y`, and `Z` are numbers. Branches should be created off of the main branch. [Branches can be created on GitHub.](https://help.github.com/en/articles/creating-and-deleting-branches-within-your-repository)
npm run version:bump `$BUMP_TYPE` where `$BUMP_TYPE` is one of `major`, `minor`, or `patch`.
Once a version branch has been created, a build on CircleCI will create a Pull Request for the release with the app manifest and changelog versions bumped.
## Preparing for Sensitive Changes
@ -41,7 +41,7 @@ With each pull request, the @MetaMaskBot will comment with a build of that new p
3. Publish to [firefox addon marketplace](http://addons.mozilla.org/en-us/firefox/addon/ether-metamask).
4. Publish to [Opera store](https://addons.opera.com/en/extensions/details/metamask/).
5. Post on [Github releases](https://github.com/MetaMask/metamask-extension/releases) page.
6. Run the `npm run announce` script, and post that announcement in our public places.
6. Run the `yarn announce` script, and post that announcement in our public places.
## Hotfix Differences

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

Loading…
Cancel
Save