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. 24
      CHANGELOG.md
  19. 27
      CONTRIBUTING.md
  20. 36
      README.md
  21. 132
      app/_locales/en/messages.json
  22. 4
      app/_locales/es/messages.json
  23. 2
      app/_locales/ph/messages.json
  24. 4
      app/_locales/sl/messages.json
  25. 2
      app/_locales/vi/messages.json
  26. 4
      app/_locales/zh_TW/messages.json
  27. 1
      app/home.html
  28. 4
      app/images/check-green-solid.svg
  29. 4
      app/images/close-gray.svg
  30. BIN
      app/images/coinswitch_logo.png
  31. BIN
      app/images/ethereum-metamask-chrome.png
  32. BIN
      app/images/icon-64.png
  33. 7
      app/images/icons/connect.svg
  34. 5
      app/images/icons/info.svg
  35. BIN
      app/images/key-32.png
  36. BIN
      app/images/logo.png
  37. 3
      app/images/meta-shield.svg
  38. BIN
      app/images/pw128x128.png
  39. 7
      app/images/qr-blue.svg
  40. 4
      app/images/search-black.svg
  41. BIN
      app/images/shapeshift logo.png
  42. 7
      app/manifest.json
  43. 1
      app/notification.html
  44. 1
      app/popup.html
  45. 2
      app/scripts/background.js
  46. 10
      app/scripts/contentscript.js
  47. 2
      app/scripts/controllers/computed-balances.js
  48. 4
      app/scripts/controllers/detect-tokens.js
  49. 8
      app/scripts/controllers/network/contract-addresses.js
  50. 43
      app/scripts/controllers/onboarding.js
  51. 58
      app/scripts/controllers/preferences.js
  52. 97
      app/scripts/controllers/provider-approval.js
  53. 26
      app/scripts/controllers/transactions/index.js
  54. 8
      app/scripts/controllers/transactions/lib/tx-state-history-helper.js
  55. 10
      app/scripts/controllers/transactions/lib/util.js
  56. 4
      app/scripts/controllers/transactions/pending-tx-tracker.js
  57. 10
      app/scripts/controllers/transactions/tx-state-manager.js
  58. 92
      app/scripts/edge-encryptor.js
  59. 91
      app/scripts/inpage.js
  60. 18
      app/scripts/lib/account-tracker.js
  61. 10
      app/scripts/lib/backend-metametrics.js
  62. 13
      app/scripts/lib/createStreamSink.js
  63. 2
      app/scripts/lib/ens-ipfs/setup.js
  64. 2
      app/scripts/lib/message-manager.js
  65. 2
      app/scripts/lib/personal-message-manager.js
  66. 202
      app/scripts/metamask-controller.js
  67. 6
      app/scripts/migrations/018.js
  68. 10
      app/scripts/migrations/019.js
  69. 2
      app/scripts/migrations/024.js
  70. 10
      app/scripts/migrations/031.js
  71. 33
      app/scripts/migrations/034.js
  72. 28
      app/scripts/migrations/035.js
  73. 6
      app/scripts/phishing-detect.js
  74. 16
      app/scripts/platforms/extension.js
  75. 77
      app/scripts/popup-core.js
  76. 129
      app/scripts/ui.js
  77. 24
      babel.config.js
  78. 0
      development/.jsdoc.json
  79. 72
      development/auto-changelog.sh
  80. 14
      development/metamaskbot-build-announce.js
  81. 17
      development/mock-dev.js
  82. 44
      development/mockExtension.js
  83. 0
      development/notices/.gitkeep
  84. 1
      development/require-react-devtools.js
  85. 2
      development/rollback.sh
  86. 28
      development/run-ganache
  87. 2
      development/sentry-publish.js
  88. 1
      development/states.json
  89. 1
      development/states/account-detail-with-shapeshift-tx.json
  90. 1
      development/states/account-detail-with-transaction-history.json
  91. 1
      development/states/account-detail.json
  92. 1
      development/states/conf-tx.json
  93. 4
      development/states/confirm-new-ui.json
  94. 4
      development/states/confirm-sig-requests.json
  95. 3
      development/states/currency-localization.json
  96. 1
      development/states/empty-account-detail.json
  97. 1
      development/states/first-time.json
  98. 1
      development/states/locked.json
  99. 1
      development/states/lost-accounts.json
  100. 1
      development/states/new-account.json
  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,20 +2,29 @@
## 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.
## 6.7.2 Mon Jul 01 2019
- [#6713](https://github.com/MetaMask/metamask-extension/pull/6713): * Normalize and Validate txParams in TransactionStateManager.addTx too
- [#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
- [#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
- [#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
- [#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"
},
@ -1802,6 +1928,6 @@
"message": "MetaMask will never ask for your seed phrase!"
},
"zeroGasPriceOnSpeedUpError": {
"message":"Zero gas price on speed up"
"message": "Zero gas price on speed up"
}
}

@ -1235,7 +1235,7 @@
},
"pending": {
"message": "pendiente"
},
},
"popularTokens": {
"message": "Tokens Corrientes"
},
@ -1504,7 +1504,7 @@
"message": "Tu frase semilla privada"
},
"zeroGasPriceOnSpeedUpError": {
"message":"No hubo precio de gas al agilizar"
"message": "No hubo precio de gas al agilizar"
},
"currencyConversion": {
"message": "Cambio de Monedas"

@ -318,7 +318,7 @@
"message": "i-click ito",
"description": "tulad ng -i-click dito- para sa mas maraming impormasyon (kasama ng troubleTokenBalances)"
},
"hide": {
"hide": {
"message": "Itago"
},
"hideToken": {

@ -1145,7 +1145,7 @@
},
"seedPhraseAlert": {
"message": "Opozorilo o seed phrase"
},
},
"select": {
"message": "Izberi"
},
@ -1549,6 +1549,6 @@
"message": "Vaš zasebni seed phrase"
},
"zeroGasPriceOnSpeedUpError": {
"message":"Ničelni gas price na pospešitvi"
"message": "Ničelni gas price na pospešitvi"
}
}

@ -655,5 +655,5 @@
},
"yourSigRequested": {
"message": "Chữ ký của bạn đang được yêu cầu"
}
}
}

@ -651,7 +651,7 @@
"description": "status showing that an account has been fully loaded into the keyring"
},
"importUsingSeed": {
"message": "利用助憶詞匯入帳戶" ,
"message": "利用助憶詞匯入帳戶",
"description": "登入頁面下方"
},
"importWithSeedPhrase": {
@ -1584,6 +1584,6 @@
"message": "您每一次在交易時,都會看到這個圖案。"
},
"zeroGasPriceOnSpeedUpError": {
"message":"加速的 Gas 價格為 0"
"message": "加速的 Gas 價格為 0"
}
}

@ -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",
@ -85,4 +86,4 @@
"*"
]
}
}
}

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

@ -65,7 +65,7 @@ class ComputedbalancesController {
syncAllAccountsFromStore (store) {
const upstream = Object.keys(store.accounts)
const balances = Object.keys(this.balances)
.map(address => this.balances[address])
.map(address => this.balances[address])
// Follow new addresses
for (const address in balances) {

@ -47,14 +47,14 @@ 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)
}
})
})
}
/**
/**
* Find if selectedAddress has tokens with contract in contractAddress.
*
* @param {string} contractAddress Hex address of the token contract to explore.

@ -4,8 +4,8 @@ const SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN = '0xb8e671734ce5c8d7dfbbea5574fa4cf3
const SINGLE_CALL_BALANCES_ADDRESS_KOVAN = '0xb1d3fbb2f83aecd196f474c16ca5d9cffa0d0ffc'
module.exports = {
SINGLE_CALL_BALANCES_ADDRESS,
SINGLE_CALL_BALANCES_ADDRESS_RINKEBY,
SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN,
SINGLE_CALL_BALANCES_ADDRESS_KOVAN,
SINGLE_CALL_BALANCES_ADDRESS,
SINGLE_CALL_BALANCES_ADDRESS_RINKEBY,
SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN,
SINGLE_CALL_BALANCES_ADDRESS_KOVAN,
}

@ -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)
@ -70,7 +69,7 @@ class PreferencesController {
return this.setFeatureFlag(key, value)
}
}
// PUBLIC METHODS
// PUBLIC METHODS
/**
* Sets the {@code forgottenPassword} state property
@ -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
*
@ -139,9 +130,9 @@ class PreferencesController {
* @param {String} type Indicates the type of first time flow - create or import - the user wishes to follow
*
*/
setFirstTimeFlowType (type) {
this.store.updateState({ firstTimeFlowType: type })
}
setFirstTimeFlowType (type) {
this.store.updateState({ firstTimeFlowType: type })
}
getSuggestedTokens () {
@ -503,22 +494,22 @@ class PreferencesController {
* @returns {Promise<array>} Promise resolving to updated frequentRpcList.
*
*/
addToFrequentRpcList (url, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) {
const rpcList = this.getFrequentRpcListDetail()
const index = rpcList.findIndex((element) => { return element.rpcUrl === url })
if (index !== -1) {
rpcList.splice(index, 1)
}
if (url !== 'http://localhost:8545') {
let checkedChainId
if (!!chainId && !Number.isNaN(parseInt(chainId))) {
checkedChainId = chainId
}
rpcList.push({ rpcUrl: url, chainId: checkedChainId, ticker, nickname, rpcPrefs })
addToFrequentRpcList (url, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) {
const rpcList = this.getFrequentRpcListDetail()
const index = rpcList.findIndex((element) => { return element.rpcUrl === url })
if (index !== -1) {
rpcList.splice(index, 1)
}
if (url !== 'http://localhost:8545') {
let checkedChainId
if (!!chainId && !Number.isNaN(parseInt(chainId))) {
checkedChainId = chainId
}
this.store.updateState({ frequentRpcListDetail: rpcList })
return Promise.resolve(rpcList)
rpcList.push({ rpcUrl: url, chainId: checkedChainId, ticker, nickname, rpcPrefs })
}
this.store.updateState({ frequentRpcListDetail: rpcList })
return Promise.resolve(rpcList)
}
/**
* Removes custom RPC url from state.
@ -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])
}
}

@ -129,7 +129,7 @@ class TransactionController extends EventEmitter {
}
}
/**
/**
Adds a tx to the txlist
@emits ${txMeta.id}:unapproved
*/
@ -220,7 +220,7 @@ class TransactionController extends EventEmitter {
return txMeta
}
/**
/**
adds the tx gas defaults: gas && gasPrice
@param txMeta {Object} - the txMeta object
@returns {Promise<object>} resolves with txMeta
@ -495,9 +495,9 @@ class TransactionController extends EventEmitter {
this.txStateManager.updateTx(txMeta, 'transactions#setTxHash')
}
//
// PRIVATE METHODS
//
//
// PRIVATE METHODS
//
/** maps methods for convenience*/
_mapMethods () {
/** @returns the state in transaction controller */
@ -537,14 +537,14 @@ class TransactionController extends EventEmitter {
loadingDefaults: true,
}).forEach((tx) => {
this.addTxGasDefaults(tx)
.then((txMeta) => {
txMeta.loadingDefaults = false
this.txStateManager.updateTx(txMeta, 'transactions: gas estimation for tx on boot')
}).catch((error) => {
tx.loadingDefaults = false
this.txStateManager.updateTx(tx, 'failed to estimate gas during boot cleanup.')
this.txStateManager.setTxStatusFailed(tx.id, error)
})
.then((txMeta) => {
txMeta.loadingDefaults = false
this.txStateManager.updateTx(txMeta, 'transactions: gas estimation for tx on boot')
}).catch((error) => {
tx.loadingDefaults = false
this.txStateManager.updateTx(tx, 'failed to estimate gas during boot cleanup.')
this.txStateManager.setTxStatusFailed(tx.id, error)
})
})
this.txStateManager.getFilteredTxList({

@ -17,10 +17,10 @@ function migrateFromSnapshotsToDiffs (longHistory) {
return (
longHistory
// convert non-initial history entries into diffs
.map((entry, index) => {
if (index === 0) return entry
return generateHistoryEntry(longHistory[index - 1], entry)
})
.map((entry, index) => {
if (index === 0) return entry
return generateHistoryEntry(longHistory[index - 1], entry)
})
)
}

@ -26,7 +26,7 @@ const normalizers = {
gasPrice: gasPrice => addHexPrefix(gasPrice),
}
/**
/**
normalizes txParams
@param txParams {object}
@returns {object} normalized txParams
@ -40,7 +40,7 @@ function normalizeTxParams (txParams, LowerCase) {
return normalizedTxParams
}
/**
/**
validates txParams
@param txParams {object}
*/
@ -59,7 +59,7 @@ function validateTxParams (txParams) {
}
}
/**
/**
validates the from field in txParams
@param txParams {object}
*/
@ -68,7 +68,7 @@ function validateFrom (txParams) {
if (!isValidAddress(txParams.from)) throw new Error('Invalid from address')
}
/**
/**
validates the to field in txParams
@param txParams {object}
*/
@ -85,7 +85,7 @@ function validateRecipient (txParams) {
return txParams
}
/**
/**
@returns an {array} of states that can be considered final
*/
function getFinalStates () {

@ -186,7 +186,7 @@ class PendingTransactionTracker extends EventEmitter {
this.emit('tx:warning', txMeta, err)
}
}
/**
/**
checks to see if if the tx's nonce has been used by another transaction
@param txMeta {Object} - txMeta object
@emits tx:dropped
@ -198,7 +198,7 @@ class PendingTransactionTracker extends EventEmitter {
const nextNonce = await this.query.getTransactionCount(from)
const { blockNumber } = await this.query.getTransactionByHash(hash) || {}
if (!blockNumber && parseInt(nextNonce) > parseInt(nonce)) {
return true
return true
}
return false
}

@ -34,7 +34,7 @@ class TransactionStateManager extends EventEmitter {
this.store = new ObservableStore(
extend({
transactions: [],
}, initState))
}, initState))
this.txHistoryLimit = txHistoryLimit
this.getNetwork = getNetwork
}
@ -245,7 +245,7 @@ class TransactionStateManager extends EventEmitter {
})
}
/**
/**
@param opts {object} - an object of fields to search for eg:<br>
let <code>thingsToLookFor = {<br>
to: '0x0..',<br>
@ -403,9 +403,9 @@ class TransactionStateManager extends EventEmitter {
// Update state
this._saveTxList(otherAccountTxs)
}
//
// PRIVATE METHODS
//
//
// PRIVATE METHODS
//
// STATUS METHODS
// statuses:

@ -14,23 +14,23 @@ class EdgeEncryptor {
* @returns {Promise<string>} Promise resolving to an object with ciphertext
*/
encrypt (password, dataObject) {
var salt = this._generateSalt()
return this._keyFromPassword(password, salt)
.then(function (key) {
var data = JSON.stringify(dataObject)
var dataBuffer = Unibabel.utf8ToBuffer(data)
var vector = global.crypto.getRandomValues(new Uint8Array(16))
var resultbuffer = asmcrypto.AES_GCM.encrypt(dataBuffer, key, vector)
var salt = this._generateSalt()
return this._keyFromPassword(password, salt)
.then(function (key) {
var data = JSON.stringify(dataObject)
var dataBuffer = Unibabel.utf8ToBuffer(data)
var vector = global.crypto.getRandomValues(new Uint8Array(16))
var resultbuffer = asmcrypto.AES_GCM.encrypt(dataBuffer, key, vector)
var buffer = new Uint8Array(resultbuffer)
var vectorStr = Unibabel.bufferToBase64(vector)
var vaultStr = Unibabel.bufferToBase64(buffer)
return JSON.stringify({
data: vaultStr,
iv: vectorStr,
salt: salt,
})
})
var buffer = new Uint8Array(resultbuffer)
var vectorStr = Unibabel.bufferToBase64(vector)
var vaultStr = Unibabel.bufferToBase64(buffer)
return JSON.stringify({
data: vaultStr,
iv: vectorStr,
salt: salt,
})
})
}
/**
@ -41,25 +41,25 @@ class EdgeEncryptor {
* @returns {Promise<Object>} Promise resolving to copy of decrypted object
*/
decrypt (password, text) {
const payload = JSON.parse(text)
const salt = payload.salt
return this._keyFromPassword(password, salt)
.then(function (key) {
const encryptedData = Unibabel.base64ToBuffer(payload.data)
const vector = Unibabel.base64ToBuffer(payload.iv)
return new Promise((resolve, reject) => {
var result
try {
result = asmcrypto.AES_GCM.decrypt(encryptedData, key, vector)
} catch (err) {
return reject(new Error('Incorrect password'))
}
const decryptedData = new Uint8Array(result)
const decryptedStr = Unibabel.bufferToUtf8(decryptedData)
const decryptedObj = JSON.parse(decryptedStr)
resolve(decryptedObj)
})
})
const payload = JSON.parse(text)
const salt = payload.salt
return this._keyFromPassword(password, salt)
.then(function (key) {
const encryptedData = Unibabel.base64ToBuffer(payload.data)
const vector = Unibabel.base64ToBuffer(payload.iv)
return new Promise((resolve, reject) => {
var result
try {
result = asmcrypto.AES_GCM.decrypt(encryptedData, key, vector)
} catch (err) {
return reject(new Error('Incorrect password'))
}
const decryptedData = new Uint8Array(result)
const decryptedStr = Unibabel.bufferToUtf8(decryptedData)
const decryptedObj = JSON.parse(decryptedStr)
resolve(decryptedObj)
})
})
}
/**
@ -72,12 +72,14 @@ class EdgeEncryptor {
*/
_keyFromPassword (password, salt) {
var passBuffer = Unibabel.utf8ToBuffer(password)
var saltBuffer = Unibabel.base64ToBuffer(salt)
return new Promise((resolve) => {
var key = asmcrypto.PBKDF2_HMAC_SHA256.bytes(passBuffer, saltBuffer, 10000)
resolve(key)
})
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.Pbkdf2HmacSha256(passBuffer, saltBuffer, iterations, length)
resolve(key)
})
}
/**
@ -87,10 +89,10 @@ class EdgeEncryptor {
* @returns {string} Randomized base64 encoded data
*/
_generateSalt (byteCount = 32) {
var view = new Uint8Array(byteCount)
global.crypto.getRandomValues(view)
var b64encoded = btoa(String.fromCharCode.apply(null, view))
return b64encoded
var view = new Uint8Array(byteCount)
global.crypto.getRandomValues(view)
var b64encoded = btoa(String.fromCharCode.apply(null, view))
return b64encoded
}
}

@ -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.')
}
}

@ -183,23 +183,23 @@ class AccountTracker {
switch (currentNetwork) {
case MAINNET_CODE:
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS)
break
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS)
break
case RINKEYBY_CODE:
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS_RINKEBY)
break
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS_RINKEBY)
break
case ROPSTEN_CODE:
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN)
break
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN)
break
case KOVAN_CODE:
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS_KOVAN)
break
await this._updateAccountsViaBalanceChecker(addresses, SINGLE_CALL_BALANCES_ADDRESS_KOVAN)
break
default:
await Promise.all(addresses.map(this._updateAccount.bind(this)))
await Promise.all(addresses.map(this._updateAccount.bind(this)))
}
}

@ -15,11 +15,11 @@ function backEndMetaMetricsEvent (metaMaskState, eventData) {
const stateEventData = getMetaMetricState({ metamask: metaMaskState })
if (stateEventData.participateInMetaMetrics) {
sendMetaMetricsEvent({
...stateEventData,
...eventData,
url: METAMETRICS_TRACKING_URL + '/backend',
})
sendMetaMetricsEvent({
...stateEventData,
...eventData,
url: METAMETRICS_TRACKING_URL + '/backend',
})
}
}

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

@ -61,7 +61,7 @@ module.exports = class MessageManager extends EventEmitter {
*/
getUnapprovedMsgs () {
return this.messages.filter(msg => msg.status === 'unapproved')
.reduce((result, msg) => { result[msg.id] = msg; return result }, {})
.reduce((result, msg) => { result[msg.id] = msg; return result }, {})
}
/**

@ -64,7 +64,7 @@ module.exports = class PersonalMessageManager extends EventEmitter {
*/
getUnapprovedMsgs () {
return this.messages.filter(msg => msg.status === 'unapproved')
.reduce((result, msg) => { result[msg.id] = msg; return result }, {})
.reduce((result, msg) => { result[msg.id] = msg; return result }, {})
}
/**

@ -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')
@ -68,7 +69,7 @@ module.exports = class MetamaskController extends EventEmitter {
* @constructor
* @param {Object} opts
*/
constructor (opts) {
constructor (opts) {
super()
this.defaultMaxListeners = 20
@ -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))
}
@ -362,9 +369,9 @@ module.exports = class MetamaskController extends EventEmitter {
return publicConfigStore
}
//=============================================================================
// EXPOSED TO THE UI SUBSYSTEM
//=============================================================================
//=============================================================================
// EXPOSED TO THE UI SUBSYSTEM
//=============================================================================
/**
* The metamask-state of the various controllers, made available to the UI
@ -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,14 +507,18 @@ 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),
}
}
//=============================================================================
// VAULT / KEYRING RELATED METHODS
//=============================================================================
//=============================================================================
// VAULT / KEYRING RELATED METHODS
//=============================================================================
/**
* Creates a new Vault and create a new keychain.
@ -617,7 +628,7 @@ module.exports = class MetamaskController extends EventEmitter {
* with the mobile client for syncing purposes
* @returns Promise<Object> Parts of the state that we want to syncx
*/
async fetchInfoToSync () {
async fetchInfoToSync () {
// Preferences
const {
accountTokens,
@ -746,14 +757,14 @@ module.exports = class MetamaskController extends EventEmitter {
const keyring = await this.getKeyringForDevice(deviceName, hdPath)
let accounts = []
switch (page) {
case -1:
accounts = await keyring.getPreviousPage()
break
case 1:
accounts = await keyring.getNextPage()
break
default:
accounts = await keyring.getFirstPage()
case -1:
accounts = await keyring.getPreviousPage()
break
case 1:
accounts = await keyring.getNextPage()
break
default:
accounts = await keyring.getFirstPage()
}
// Merge with existing accounts
@ -810,7 +821,7 @@ module.exports = class MetamaskController extends EventEmitter {
const { identities } = this.preferencesController.store.getState()
return { ...keyState, identities }
}
}
//
@ -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
@ -1009,16 +988,16 @@ module.exports = class MetamaskController extends EventEmitter {
// sets the status op the message to 'approved'
// and removes the metamaskId for signing
return this.messageManager.approveMessage(msgParams)
.then((cleanMsgParams) => {
.then((cleanMsgParams) => {
// signs the message
return this.keyringController.signMessage(cleanMsgParams)
})
.then((rawSig) => {
return this.keyringController.signMessage(cleanMsgParams)
})
.then((rawSig) => {
// tells the listener that the message has been signed
// and can be returned to the dapp
this.messageManager.setMsgStatusSigned(msgId, rawSig)
return this.getState()
})
this.messageManager.setMsgStatusSigned(msgId, rawSig)
return this.getState()
})
}
/**
@ -1067,16 +1046,16 @@ module.exports = class MetamaskController extends EventEmitter {
// sets the status op the message to 'approved'
// and removes the metamaskId for signing
return this.personalMessageManager.approveMessage(msgParams)
.then((cleanMsgParams) => {
.then((cleanMsgParams) => {
// signs the message
return this.keyringController.signPersonalMessage(cleanMsgParams)
})
.then((rawSig) => {
return this.keyringController.signPersonalMessage(cleanMsgParams)
})
.then((rawSig) => {
// tells the listener that the message has been signed
// and can be returned to the dapp
this.personalMessageManager.setMsgStatusSigned(msgId, rawSig)
return this.getState()
})
this.personalMessageManager.setMsgStatusSigned(msgId, rawSig)
return this.getState()
})
}
/**
@ -1176,7 +1155,7 @@ module.exports = class MetamaskController extends EventEmitter {
restoreOldVaultAccounts (migratorOutput) {
const { serialized } = migratorOutput
return this.keyringController.restoreKeyring(serialized)
.then(() => migratorOutput)
.then(() => migratorOutput)
}
/**
@ -1219,9 +1198,9 @@ module.exports = class MetamaskController extends EventEmitter {
})
}
//=============================================================================
// END (VAULT / KEYRING RELATED METHODS)
//=============================================================================
//=============================================================================
// END (VAULT / KEYRING RELATED METHODS)
//=============================================================================
/**
* Allows a user to try to speed up a transaction by retrying it
@ -1270,9 +1249,9 @@ module.exports = class MetamaskController extends EventEmitter {
})
}
//=============================================================================
// PASSWORD MANAGEMENT
//=============================================================================
//=============================================================================
// PASSWORD MANAGEMENT
//=============================================================================
/**
* Allows a user to begin the seed phrase recovery process.
@ -1294,9 +1273,9 @@ module.exports = class MetamaskController extends EventEmitter {
cb()
}
//=============================================================================
// SETUP
//=============================================================================
//=============================================================================
// SETUP
//=============================================================================
/**
* Used to create a multiplexed stream for connecting to an untrusted context
@ -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)()
@ -1551,13 +1550,13 @@ module.exports = class MetamaskController extends EventEmitter {
return GWEI_BN
}
return block.gasPrices
.map(hexPrefix => hexPrefix.substr(2))
.map(hex => new BN(hex, 16))
.sort((a, b) => {
return a.gt(b) ? 1 : -1
})[0]
.map(hexPrefix => hexPrefix.substr(2))
.map(hex => new BN(hex, 16))
.sort((a, b) => {
return a.gt(b) ? 1 : -1
})[0]
})
.map(number => number.div(GWEI_BN).toNumber())
.map(number => number.div(GWEI_BN).toNumber())
const percentileNum = percentile(65, lowestPrices)
const percentileNumBn = new BN(percentileNum)
@ -1577,9 +1576,9 @@ module.exports = class MetamaskController extends EventEmitter {
return pendingNonce
}
//=============================================================================
// CONFIG
//=============================================================================
//=============================================================================
// CONFIG
//=============================================================================
// Log blocks
@ -1774,7 +1773,7 @@ module.exports = class MetamaskController extends EventEmitter {
this.tokenRatesController.isActive = active
}
/**
/**
* Creates RPC engine middleware for processing eth_signTypedData requests
*
* @param {Object} req - request object
@ -1798,3 +1797,4 @@ module.exports = class MetamaskController extends EventEmitter {
return this.keyringController.setLocked()
}
}

@ -43,9 +43,9 @@ function transformState (state) {
const newHistory = (
txStateHistoryHelper.migrateFromSnapshotsToDiffs(txMeta.history)
// remove empty diffs
.filter((entry) => {
return !Array.isArray(entry) || entry.length > 0
})
.filter((entry) => {
return !Array.isArray(entry) || entry.length > 0
})
)
txMeta.history = newHistory
return txMeta

@ -38,13 +38,13 @@ function transformState (state) {
if (txMeta.status !== 'submitted') return txMeta
const confirmedTxs = txList.filter((tx) => tx.status === 'confirmed')
.filter((tx) => tx.txParams.from === txMeta.txParams.from)
.filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
.filter((tx) => tx.txParams.from === txMeta.txParams.from)
.filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
const highestConfirmedNonce = getHighestNonce(confirmedTxs)
const pendingTxs = txList.filter((tx) => tx.status === 'submitted')
.filter((tx) => tx.txParams.from === txMeta.txParams.from)
.filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
.filter((tx) => tx.txParams.from === txMeta.txParams.from)
.filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from)
const highestContinuousNonce = getHighestContinuousFrom(pendingTxs, highestConfirmedNonce)
const maxNonce = Math.max(highestContinuousNonce, highestConfirmedNonce)
@ -78,7 +78,7 @@ function getHighestContinuousFrom (txList, startPoint) {
function getHighestNonce (txList) {
const nonces = txList.map((txMeta) => {
const nonce = txMeta.txParams.nonce
const nonce = txMeta.txParams.nonce
return parseInt(nonce || '0x0', 16)
})
const highestNonce = Math.max.apply(null, nonces)

@ -32,7 +32,7 @@ function transformState (state) {
txMeta.status === 'unapproved' &&
txMeta.txParams &&
txMeta.txParams.from
) {
) {
txMeta.txParams.from = txMeta.txParams.from.toLowerCase()
}
return txMeta

@ -2,14 +2,14 @@
const version = 31
const clone = require('clone')
/*
/*
* The purpose of this migration is to properly set the completedOnboarding flag baesd on the state
* of the KeyringController.
*/
module.exports = {
version,
migrate: async function (originalVersionedData) {
migrate: async function (originalVersionedData) {
const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data
@ -19,13 +19,13 @@ module.exports = {
},
}
function transformState (state) {
function transformState (state) {
const { KeyringController, PreferencesController } = state
if (KeyringController && PreferencesController) {
if (KeyringController && PreferencesController) {
const { vault } = KeyringController
PreferencesController.completedOnboarding = Boolean(vault)
}
return state
return state
}

@ -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)
}
@ -84,20 +84,20 @@ class ExtensionPlatform {
extension.notifications.create(
url,
{
'type': 'basic',
'title': title,
'iconUrl': extension.extension.getURL('../../images/icon-64.png'),
'message': message,
'type': 'basic',
'title': title,
'iconUrl': extension.extension.getURL('../../images/icon-64.png'),
'message': message,
})
}
_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,22 +46,8 @@ async function start () {
const extensionPort = extension.runtime.connect({ name: windowType })
const connectionStream = new PortStream(extensionPort)
// start ui
const container = document.getElementById('app-content')
startPopup({ container, connectionStream }, (err, store) => {
if (err) return displayCriticalError(err)
const state = store.getState()
const { metamask: { completedOnboarding } = {} } = state
if (!completedOnboarding && windowType !== ENVIRONMENT_TYPE_FULLSCREEN) {
global.platform.openExtensionInBrowser()
return
}
injectCss(NewMetaMaskUiCss())
})
const activeTab = await queryCurrentActiveTab(windowType)
initializeUiWithTab(activeTab)
function closePopupIfOpen (windowType) {
if (windowType !== ENVIRONMENT_TYPE_NOTIFICATION) {
@ -65,11 +56,107 @@ async function start () {
}
}
function displayCriticalError (err) {
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')
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
}
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)
}
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'))
}
/**
* 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'

@ -36,13 +36,13 @@ async function start () {
console.log(`Posting to: ${POST_COMMENT_URI}`)
await request({
method: 'POST',
uri: POST_COMMENT_URI,
body: JSON_PAYLOAD,
headers: {
'User-Agent': 'metamaskbot',
'Authorization': `token ${GITHUB_COMMENT_TOKEN}`,
},
method: 'POST',
uri: POST_COMMENT_URI,
body: JSON_PAYLOAD,
headers: {
'User-Agent': 'metamaskbot',
'Authorization': `token ${GITHUB_COMMENT_TOKEN}`,
},
})
}

@ -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)
@ -147,10 +134,10 @@ function startApp () {
},
}, [
h(Root, {
store: store,
store: store,
}),
]),
]
), container)
), container)
}

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

@ -16,7 +16,7 @@ async function start () {
if (versionAlreadyExists) {
console.log(`Version "${VERSION}" already exists on Sentry, skipping version creation`)
} else {
// create sentry release
// create sentry release
console.log(`creating Sentry release for "${VERSION}"...`)
await exec(`sentry-cli releases --org 'metamask' --project 'metamask' new ${VERSION}`)
console.log(`removing any existing files from Sentry release "${VERSION}"...`)

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",

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

Loading…
Cancel
Save