1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-10-22 19:26:13 +02:00

Merge branch 'develop' into removeNonceTrackerFunction

This commit is contained in:
Thomas 2018-07-10 11:34:00 -07:00
commit 5188b727d4
214 changed files with 36148 additions and 34399 deletions

View File

@ -97,43 +97,45 @@ workflows:
jobs:
prep-deps-npm:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
keys:
- dependency-cache-{{ checksum "package-lock.json" }}
# fallback to using the latest cache if no exact match is found
- dependency-cache-
- run:
name: Install deps via npm
command: npm install
name: Install npm 6 + deps via npm
command: |
sudo npm install -g npm@6.1.0 && npm install
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- node_modules
- save_cache:
key: dependency-cache-{{ .Revision }}
paths:
- node_modules
prep-deps-firefox:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-firefox-
- run:
name: Download Firefox
name: Download Firefox If needed
command: ./.circleci/scripts/firefox-download.sh
- save_cache:
key: dependency-cache-firefox-{{ .Revision }}
key: dependency-cache-firefox-
paths:
- firefox
prep-build:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: build:dist
command: npm run dist
@ -148,11 +150,11 @@ jobs:
prep-docs:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: build:dist
command: npm run doc
@ -163,11 +165,11 @@ jobs:
prep-scss:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Get Scss Cache key
# this allows us to checksum against a whole directory
@ -182,33 +184,33 @@ jobs:
test-lint:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Test
command: npm run lint
test-deps:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Test
command: npx nsp check
test-e2e-chrome:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- restore_cache:
key: build-cache-{{ .Revision }}
- run:
@ -220,16 +222,16 @@ jobs:
test-e2e-firefox:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-firefox-{{ .Revision }}
key: dependency-cache-firefox-
- run:
name: Install firefox
command: ./.circleci/scripts/firefox-install.sh
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- restore_cache:
key: build-cache-{{ .Revision }}
- run:
@ -241,11 +243,11 @@ jobs:
test-e2e-beta-chrome:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- restore_cache:
key: build-cache-{{ .Revision }}
- run:
@ -257,16 +259,16 @@ jobs:
test-e2e-beta-firefox:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-firefox-{{ .Revision }}
key: dependency-cache-firefox-
- run:
name: Install firefox
command: ./.circleci/scripts/firefox-install.sh
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- restore_cache:
key: build-cache-{{ .Revision }}
- run:
@ -278,11 +280,11 @@ jobs:
job-screens:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- restore_cache:
key: build-cache-{{ .Revision }}
- run:
@ -295,11 +297,11 @@ jobs:
job-publish-prerelease:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- restore_cache:
key: build-cache-{{ .Revision }}
- restore_cache:
@ -322,11 +324,11 @@ jobs:
job-publish-release:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- restore_cache:
key: build-cache-{{ .Revision }}
- restore_cache:
@ -345,11 +347,11 @@ jobs:
test-unit:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: test:coverage
command: npm run test:coverage
@ -358,16 +360,16 @@ jobs:
environment:
browsers: '["Firefox"]'
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-firefox-{{ .Revision }}
key: dependency-cache-firefox-
- run:
name: Install firefox
command: ./.circleci/scripts/firefox-install.sh
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Get Scss Cache key
# this allows us to checksum against a whole directory
@ -382,11 +384,11 @@ jobs:
environment:
browsers: '["Chrome"]'
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Get Scss Cache key
# this allows us to checksum against a whole directory
@ -401,16 +403,16 @@ jobs:
environment:
browsers: '["Firefox"]'
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-firefox-{{ .Revision }}
key: dependency-cache-firefox-
- run:
name: Install firefox
command: ./.circleci/scripts/firefox-install.sh
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Get Scss Cache key
# this allows us to checksum against a whole directory
@ -425,11 +427,11 @@ jobs:
environment:
browsers: '["Chrome"]'
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ .Revision }}
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Get Scss Cache key
# this allows us to checksum against a whole directory
@ -442,7 +444,7 @@ jobs:
all-tests-pass:
docker:
- image: circleci/node:8-browsers
- image: circleci/node:8.11.3-browsers
steps:
- run:
name: All Tests Passed

View File

@ -1,6 +1,13 @@
#!/usr/bin/env bash
echo "Downloading firefox..."
wget https://ftp.mozilla.org/pub/firefox/releases/58.0/linux-x86_64/en-US/firefox-58.0.tar.bz2 \
&& tar xjf firefox-58.0.tar.bz2
echo "firefox download complete"
echo "Checking if firefox was already downloaded"
if [ -d "firefox" ]
then
echo "Firefox found. No need to download"
else
FIREFOX_VERSION="61.0.1"
FIREFOX_BINARY="firefox-$FIREFOX_VERSION.tar.bz2"
echo "Downloading firefox..."
wget "https://ftp.mozilla.org/pub/firefox/releases/$FIREFOX_VERSION/linux-x86_64/en-US/$FIREFOX_BINARY" \
&& tar xjf "$FIREFOX_BINARY"
echo "firefox download complete"
fi

View File

@ -2,7 +2,7 @@
echo "Installing firefox..."
sudo rm -r /opt/firefox
sudo mv firefox /opt/firefox58
sudo mv firefox /opt/firefox61
sudo mv /usr/bin/firefox /usr/bin/firefox-old
sudo ln -s /opt/firefox58/firefox /usr/bin/firefox
sudo ln -s /opt/firefox61/firefox /usr/bin/firefox
echo "Firefox installed."

View File

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

View File

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

3
.nsprc
View File

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

2
.nvmrc
View File

@ -1 +1 @@
v6.3.1
v8.11.3

View File

@ -2,31 +2,26 @@
If you're submitting code to MetaMask, there are some simple things we'd appreciate you doing to help us stay organized!
## Submitting pull requests
### Finding the right project
Before taking the time to code and implement something, feel free to open an issue and discuss it! There may even be an issue already open, and together we may come up with a specific strategy before you take your precious time to write code.
### Tests
There are also plenty of open issues we'd love help with. Search the [`good first issue`](https://github.com/MetaMask/metamask-extension/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) label, or head to Gitcoin and earn ETH for completing projects we've posted bounties on.
For any new programmatic functionality, we like unit tests when possible, so if you can keep your code cleanly isolated, please do add a test file to the `tests` folder.
If you're picking up a bounty or an existing issue, feel free to ask clarifying questions on the issue as you go about your work.
### PR Format
### Submitting a pull request
When you're done with your project / bugfix / feature and ready to submit a PR, there are a couple guidelines we ask you to follow:
If this PR closes the issue, add the line `Fixes #$ISSUE_NUMBER`. Ex. For closing issue 418, include the line `Fixes #418`.
- [ ] **Test it**: For any new programmatic functionality, we like unit tests when possible, so if you can keep your code cleanly isolated, please do add a test file to the `tests` folder.
- [ ] **Add to the CHANGELOG**: Help us keep track of all the moving pieces by adding an entry to the [`CHANGELOG.md`](https://github.com/MetaMask/metamask-extension/blob/develop/CHANGELOG.md) with a link to your PR.
- [ ] **Meet the spec**: Make sure the PR adds functionality that matches the issue you're closing. This is especially important for bounties: sometimes design or implementation details are included in the conversation, so read carefully!
- [ ] **Close the issue**: If this PR closes an open issue, add the line `Fixes #$ISSUE_NUMBER`. Ex. For closing issue 418, include the line `Fixes #418`. If it doesn't close the issue but addresses it partially, just include a reference to the issue number, like `#418`.
- [ ] **Keep it simple**: Try not to include multiple features in a single PR, and don't make extraneous changes outside the scope of your contribution. All those touched files make things harder to review ;)
- [ ] **PR against `develop`**: Submit your PR against the `develop` branch. This is where we merge new features so they get some time to receive extra testing before being pushed to `master` for production. If your PR is a hot-fix that needs to be published urgently, you may submit a PR against the `master` branch, but this PR will receive tighter scrutiny before merging.
- [ ] **Get reviewed by a core contributor**: Make sure you get a `:thumbsup`, `:+1`, or `LGTM` from a user with a `Member` badge before merging.
If it doesn't close the issue but addresses it partially, just include a reference to the issue number, like `#418`.
Submit your PR against the `develop` branch. This is where we merge new features so they get some time to receive extra testing before being pushed to `master` for production.
If your PR is a hot-fix that needs to be published urgently, you may submit a PR against the `master` branch, but this PR will receive tighter scrutiny before merging.
## Before Merging
Make sure you get a `:thumbsup`, `:+1`, or `LGTM` from another collaborator before merging.
## Before Closing Issues
Make sure the relevant code has been reviewed and merged.
And that's it! Thanks for helping out.
### Developing inside a node_modules folder

View File

@ -9,7 +9,7 @@ If you're a user seeking support, [here is our support site](https://metamask.he
[Mission Statement](./MISSION.md)
[Internal documentation](./docs/jsdocs)
[Internal documentation](./docs#documentation)
## Developing Compatible Dapps

52
app/404.html Normal file
View File

@ -0,0 +1,52 @@
<html>
<head>
<title>MetaMask</title>
<style>
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
img{
display: block;
}
html, body{
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.app{
position: relative;
width: 100%;
height: auto;
overflow: hidden;
}
img{
display: block;
width: 100%;
height: auto;
}
h2{
display: block;
width: 100%;
overflow: hidden;
position: absolute;
bottom: 20%;
left: 0;
color: #1b243d;
text-align: center;
}
h2 > a{
color: #1b243d;
}
</style>
</head>
<body>
<div class="app">
<img src="./images/404.png" alt="">
<h2>Powered by <a href="https://www.portal.network/">Portal Network</a></h2>
</div>
</body>
</html>

View File

@ -265,6 +265,9 @@
"encryptNewDen": {
"message": "Encrypt your new DEN"
},
"ensNameNotFound": {
"message": "ENS name not found"
},
"enterPassword": {
"message": "Enter password"
},
@ -661,6 +664,9 @@
"restoreVault": {
"message": "Restore Vault"
},
"restoreAccountWithSeed": {
"message": "Restore your Account with Seed Phrase"
},
"required": {
"message": "Required"
},
@ -670,6 +676,9 @@
"walletSeed": {
"message": "Wallet Seed"
},
"restore": {
"message": "Restore"
},
"revealSeedWords": {
"message": "Reveal Seed Words"
},
@ -774,6 +783,9 @@
"sendTokens": {
"message": "Send Tokens"
},
"separateEachWord": {
"message": "Separate each word with a single space"
},
"onlySendToEtherAddress": {
"message": "Only send ETH to an Ethereum address."
},

79
app/error.html Normal file
View File

@ -0,0 +1,79 @@
<html>
<head>
<title>MetaMask Error</title>
<link href="https://fonts.googleapis.com/css?family=Rokkitt" rel="stylesheet">
<style>
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
img{
display: block;
}
html, body{
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
@keyframes logoAmin{
from {transform: scale(1);}
50%{transform: scale(1.1);}
to {transform: scale(1);}
}
.errorBox{
width: 70%;
height: auto;
overflow: hidden;
background-image: url("./images/deadface.png");
background-repeat: no-repeat;
background-position: 100% 50%;
background-size: auto 90%;
padding: 5px;
}
.errorBox > img{
width: 100px;
height: auto;
margin-bottom: 25px;
animation: logoAmin 1s infinite linear;
}
.errorBox > h1, .errorBox > h2{
letter-spacing: 2px;
}
.errorBox > h1{
color: #9b9b9b;
font-size: 40px;
}
.errorBox > h2{
color: #1b243d;
font-size: 20px;
padding-top: 5px;
}
.errorBox > h2 >a{
color: #1b243d;
}
.errorBox > h2 >a:hover{
color: #44588e;
}
.errorBox > h1 > span{
color: #33559f;
}
</style>
</head>
<body>
<div class="errorBox">
<img src="./images/logo.png" alt="">
<h1><span id="name"></span> not found</h1>
<h2>Powered by <a href="https://www.portal.network/">Portal Network</a></h2>
</div>
<script>
let index = location.href.lastIndexOf("?name=")
let name = location.href.slice(index + 6)
document.getElementById("name").innerHTML = name
</script>
</body>
</html>

BIN
app/images/404.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
app/images/cancel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
app/images/deadface.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

53
app/images/loginglogo.svg Normal file
View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="128px" height="128px" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 49.3 (51167) - http://www.bohemiancoding.com/sketch -->
<title>logo2</title>
<desc>Created with Sketch.</desc>
<defs>
<polygon id="path-1" points="0 82.118 126.527 82.118 126.527 0 0 0"></polygon>
</defs>
<g id="logo2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Page-1" transform="translate(1.000000, 23.000000)">
<path d="M6.8811,74.2729 C6.6901,74.0489 6.4661,73.8719 6.2111,73.7389 C5.9551,73.6069 5.6861,73.5409 5.4031,73.5409 L0.0001,73.5409 L0.0001,82.0769 L0.9581,82.0769 L0.9581,74.4029 L5.2261,74.4029 C5.4261,74.4029 5.6071,74.4549 5.7661,74.5599 C5.9251,74.6649 6.0601,74.7969 6.1701,74.9569 C6.2791,75.1159 6.3631,75.2939 6.4231,75.4899 C6.4821,75.6859 6.5111,75.8759 6.5111,76.0579 C6.5111,76.2219 6.4891,76.3949 6.4431,76.5779 C6.3981,76.7599 6.3221,76.9289 6.2171,77.0839 C6.1121,77.2389 5.9831,77.3669 5.8281,77.4669 C5.6731,77.5669 5.4851,77.6179 5.2671,77.6179 L3.9941,77.6179 L3.9941,78.4789 L5.4311,78.4789 C5.7141,78.4789 5.9801,78.4129 6.2311,78.2809 C6.4821,78.1489 6.7031,77.9709 6.8951,77.7479 C7.0861,77.5239 7.2361,77.2679 7.3461,76.9809 C7.4561,76.6939 7.5101,76.3909 7.5101,76.0719 C7.5101,75.7149 7.4531,75.3829 7.3391,75.0729 C7.2251,74.7629 7.0721,74.4959 6.8811,74.2729" id="Fill-1" fill="#1B243D"></path>
<path d="M16.43,79.1157 C16.247,79.5207 15.999,79.8797 15.684,80.1887 C15.369,80.4997 15.005,80.7457 14.59,80.9277 C14.175,81.1107 13.735,81.2017 13.27,81.2017 C12.805,81.2017 12.365,81.1107 11.95,80.9277 C11.534,80.7457 11.172,80.4997 10.862,80.1887 C10.552,79.8797 10.305,79.5207 10.123,79.1157 C9.941,78.7097 9.85,78.2787 9.85,77.8227 C9.85,77.3757 9.941,76.9447 10.123,76.5297 C10.305,76.1147 10.552,75.7527 10.862,75.4417 C11.172,75.1327 11.537,74.8837 11.956,74.6967 C12.376,74.5097 12.818,74.4167 13.284,74.4167 C13.748,74.4167 14.188,74.5097 14.603,74.6967 C15.018,74.8837 15.381,75.1327 15.691,75.4417 C16.001,75.7527 16.247,76.1147 16.43,76.5297 C16.612,76.9447 16.703,77.3757 16.703,77.8227 C16.703,78.2787 16.612,78.7097 16.43,79.1157 M16.341,74.7647 C15.953,74.3777 15.495,74.0697 14.966,73.8417 C14.437,73.6137 13.872,73.4997 13.27,73.4997 C12.668,73.4997 12.102,73.6137 11.574,73.8417 C11.044,74.0697 10.586,74.3777 10.199,74.7647 C9.811,75.1527 9.503,75.6087 9.275,76.1337 C9.047,76.6577 8.933,77.2167 8.933,77.8087 C8.933,78.4017 9.047,78.9607 9.275,79.4847 C9.503,80.0097 9.811,80.4657 10.199,80.8527 C10.586,81.2407 11.044,81.5487 11.574,81.7757 C12.102,82.0047 12.668,82.1177 13.27,82.1177 C13.872,82.1177 14.437,82.0047 14.966,81.7757 C15.495,81.5487 15.953,81.2407 16.341,80.8527 C16.728,80.4657 17.036,80.0097 17.264,79.4847 C17.492,78.9607 17.606,78.4017 17.606,77.8087 C17.606,77.2167 17.492,76.6577 17.264,76.1337 C17.036,75.6087 16.728,75.1527 16.341,74.7647" id="Fill-3" fill="#1B243D"></path>
<path d="M26.2249,74.2729 C26.0329,74.0489 25.8089,73.8719 25.5549,73.7389 C25.2989,73.6069 25.0299,73.5409 24.7469,73.5409 L19.3439,73.5409 L19.3439,82.0769 L20.3009,82.0769 L20.3009,74.4029 L24.5699,74.4029 C24.7699,74.4029 24.9499,74.4549 25.1099,74.5599 C25.2689,74.6649 25.4039,74.7969 25.5139,74.9569 C25.6229,75.1159 25.7069,75.2939 25.7669,75.4899 C25.8259,75.6859 25.8549,75.8759 25.8549,76.0579 C25.8549,76.2219 25.8319,76.3949 25.7869,76.5779 C25.7409,76.7599 25.6659,76.9289 25.5609,77.0839 C25.4559,77.2389 25.3269,77.3669 25.1709,77.4669 C25.0169,77.5669 24.8289,77.6179 24.6109,77.6179 L23.2969,77.6179 L25.5819,82.0769 L26.6079,82.0769 L24.7879,78.4789 C25.0709,78.4789 25.3379,78.4129 25.5889,78.2809 C25.8389,78.1489 26.0579,77.9709 26.2459,77.7479 C26.4319,77.5239 26.5799,77.2679 26.6899,76.9809 C26.7989,76.6939 26.8539,76.3909 26.8539,76.0719 C26.8539,75.7149 26.7969,75.3829 26.6829,75.0729 C26.5689,74.7629 26.4159,74.4959 26.2249,74.2729" id="Fill-5" fill="#1B243D"></path>
<polygon id="Fill-7" fill="#1B243D" points="35.8694 73.5405 28.4134 73.5405 28.4134 74.4025 31.6554 74.4025 31.6554 82.0765 32.6134 82.0765 32.6134 74.4025 35.8694 74.4025"></polygon>
<polygon id="Fill-9" fill="#1B243D" points="35.3084 82.0766 41.4234 82.0766 40.8344 81.2156 36.8134 81.2156 39.7814 75.1406 43.2294 82.0766 44.2964 82.0766 39.7814 73.0896"></polygon>
<polygon id="Fill-11" fill="#1B243D" points="46.7859 73.5405 45.8279 73.5405 45.8279 82.0765 52.3269 82.0765 52.3269 81.2155 46.7859 81.2155"></polygon>
<polygon id="Fill-13" fill="#1B243D" points="66.0471 81.27 60.6441 73.541 59.0431 73.541 59.0431 82.077 60.0011 82.077 60.0011 74.334 65.5001 82.077 67.0051 82.077 67.0051 73.541 66.0471 73.541"></polygon>
<polygon id="Fill-15" fill="#1B243D" points="68.9202 82.0766 75.4182 82.0766 75.4182 81.2156 69.8782 81.2156 69.8782 74.4026 75.4182 74.4026 75.4182 73.5406 68.9202 73.5406"></polygon>
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="Clip-18"></g>
<polygon id="Fill-17" fill="#1B243D" mask="url(#mask-2)" points="71.218 78.479 75.309 78.479 75.309 77.618 71.218 77.618"></polygon>
<polygon id="Fill-19" fill="#1B243D" mask="url(#mask-2)" points="77.2923 74.4028 80.5343 74.4028 80.5343 82.0768 81.4923 82.0768 81.4923 74.4028 84.7483 74.4028 84.7483 73.5408 77.2923 73.5408"></polygon>
<polygon id="Fill-20" fill="#1B243D" mask="url(#mask-2)" points="95.8284 81.3657 91.6694 73.0897 87.5794 81.2977 87.5794 73.5407 86.6214 73.5407 86.6214 82.0767 88.2634 82.0767 91.6694 75.0997 95.1174 82.0767 96.7864 82.0767 96.7864 73.5407 95.8284 73.5407"></polygon>
<path d="M106.0203,79.1157 C105.8373,79.5207 105.5893,79.8797 105.2743,80.1887 C104.9603,80.4997 104.5953,80.7457 104.1803,80.9277 C103.7653,81.1107 103.3253,81.2017 102.8603,81.2017 C102.3953,81.2017 101.9553,81.1107 101.5403,80.9277 C101.1243,80.7457 100.7623,80.4997 100.4523,80.1887 C100.1423,79.8797 99.8953,79.5207 99.7133,79.1157 C99.5313,78.7097 99.4403,78.2787 99.4403,77.8227 C99.4403,77.3757 99.5313,76.9447 99.7133,76.5297 C99.8953,76.1147 100.1423,75.7527 100.4523,75.4417 C100.7623,75.1327 101.1273,74.8837 101.5463,74.6967 C101.9663,74.5097 102.4093,74.4167 102.8743,74.4167 C103.3393,74.4167 103.7793,74.5097 104.1943,74.6967 C104.6083,74.8837 104.9713,75.1327 105.2813,75.4417 C105.5913,75.7527 105.8373,76.1147 106.0203,76.5297 C106.2023,76.9447 106.2933,77.3757 106.2933,77.8227 C106.2933,78.2787 106.2023,78.7097 106.0203,79.1157 M105.9313,74.7647 C105.5433,74.3777 105.0853,74.0697 104.5563,73.8417 C104.0273,73.6137 103.4623,73.4997 102.8603,73.4997 C102.2583,73.4997 101.6923,73.6137 101.1643,73.8417 C100.6343,74.0697 100.1763,74.3777 99.7893,74.7647 C99.4013,75.1527 99.0933,75.6087 98.8653,76.1337 C98.6373,76.6577 98.5233,77.2167 98.5233,77.8087 C98.5233,78.4017 98.6373,78.9607 98.8653,79.4847 C99.0933,80.0097 99.4013,80.4657 99.7893,80.8527 C100.1763,81.2407 100.6343,81.5487 101.1643,81.7757 C101.6923,82.0047 102.2583,82.1177 102.8603,82.1177 C103.4623,82.1177 104.0273,82.0047 104.5563,81.7757 C105.0853,81.5487 105.5433,81.2407 105.9313,80.8527 C106.3193,80.4657 106.6263,80.0097 106.8543,79.4847 C107.0823,78.9607 107.1963,78.4017 107.1963,77.8087 C107.1963,77.2167 107.0823,76.6577 106.8543,76.1337 C106.6263,75.6087 106.3193,75.1527 105.9313,74.7647" id="Fill-21" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M115.8152,74.2729 C115.6232,74.0489 115.4002,73.8719 115.1452,73.7389 C114.8892,73.6069 114.6202,73.5409 114.3372,73.5409 L108.9342,73.5409 L108.9342,82.0769 L109.8912,82.0769 L109.8912,74.4029 L114.1602,74.4029 C114.3602,74.4029 114.5402,74.4549 114.7002,74.5599 C114.8592,74.6649 114.9942,74.7969 115.1042,74.9569 C115.2132,75.1159 115.2972,75.2939 115.3572,75.4899 C115.4162,75.6859 115.4452,75.8759 115.4452,76.0579 C115.4452,76.2219 115.4222,76.3949 115.3772,76.5779 C115.3312,76.7599 115.2562,76.9289 115.1512,77.0839 C115.0462,77.2389 114.9172,77.3669 114.7612,77.4669 C114.6072,77.5669 114.4192,77.6179 114.2012,77.6179 L112.8872,77.6179 L115.1722,82.0769 L116.1982,82.0769 L114.3782,78.4789 C114.6612,78.4789 114.9282,78.4129 115.1792,78.2809 C115.4292,78.1489 115.6482,77.9709 115.8362,77.7479 C116.0222,77.5239 116.1702,77.2679 116.2802,76.9809 C116.3892,76.6939 116.4442,76.3909 116.4442,76.0719 C116.4442,75.7149 116.3872,75.3829 116.2732,75.0729 C116.1592,74.7629 116.0062,74.4959 115.8152,74.2729" id="Fill-22" fill="#1B243D" mask="url(#mask-2)"></path>
<polygon id="Fill-23" fill="#1B243D" mask="url(#mask-2)" points="126.5266 73.5405 125.4866 73.5405 123.3666 77.8505 125.4866 82.0765 126.5266 82.0765 124.4336 77.8505"></polygon>
<polygon id="Fill-24" fill="#1B243D" mask="url(#mask-2)" points="119.2078 73.5405 118.2498 73.5405 118.2498 82.0765 119.2078 82.0765 119.2078 78.2735 122.1078 78.2735 122.1078 77.4115 119.2078 77.4115"></polygon>
<path d="M72.4627,48.06 C67.3487,48.06 61.5897,46.102 56.2467,42.545 C55.7657,42.225 55.2427,42.234 55.0787,42.564 C54.9137,42.894 55.1697,43.421 55.6507,43.741 C61.4477,47.6 67.6967,49.725 73.2447,49.725 C77.8417,49.725 81.5387,48.281 83.9357,45.548 C86.2857,42.87 87.1877,39.202 86.5457,34.942 C86.4797,34.504 86.0177,34.036 85.5137,33.896 C85.0107,33.756 84.6557,33.998 84.7217,34.436 C85.3137,38.362 84.4817,41.743 82.3157,44.211 C80.1077,46.73 76.6997,48.06 72.4627,48.06" id="Fill-25" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M84.5081,28.4746 C84.2921,28.0146 83.7441,27.6416 83.2851,27.6416 C82.8251,27.6416 82.6281,28.0146 82.8431,28.4746 C83.2451,29.3286 83.5941,30.1886 83.8801,31.0306 C84.0341,31.4866 84.5521,31.9036 85.0361,31.9626 C85.0741,31.9676 85.1121,31.9706 85.1481,31.9706 C85.5591,31.9706 85.7741,31.6646 85.6311,31.2456 C85.3211,30.3326 84.9441,29.4006 84.5081,28.4746" id="Fill-26" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M71.5769,13.6919 C65.5769,9.5209 59.0759,7.2239 53.2699,7.2239 C48.6269,7.2239 44.9069,8.6949 42.5129,11.4779 C40.1969,14.1689 39.3079,17.9979 40.0099,22.2589 C40.0819,22.6979 40.5479,23.1639 41.0509,23.2979 C41.1429,23.3219 41.2309,23.3339 41.3109,23.3339 C41.6679,23.3339 41.8889,23.1039 41.8299,22.7449 C41.1839,18.8179 42.0039,15.2889 44.1379,12.8079 C46.3439,10.2439 49.7719,8.8879 54.0529,8.8879 C59.4039,8.8879 65.3959,11.0049 70.9259,14.8499 C71.4009,15.1799 71.9309,15.1889 72.1109,14.8689 C72.2909,14.5489 72.0519,14.0219 71.5769,13.6919" id="Fill-27" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M42.6355,25.9184 C42.4805,25.4624 41.9635,25.0444 41.4795,24.9854 C40.9955,24.9264 40.7285,25.2474 40.8845,25.7034 C41.1935,26.6164 41.5715,27.5484 42.0075,28.4744 C42.2225,28.9344 42.7705,29.3064 43.2305,29.3064 C43.6905,29.3064 43.8875,28.9344 43.6715,28.4744 C43.2695,27.6194 42.9215,26.7594 42.6355,25.9184" id="Fill-28" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M48.9544,5.5986 C48.9954,5.5986 49.0354,5.5956 49.0734,5.5896 C50.1214,5.4216 51.2354,5.3376 52.3844,5.3376 C52.8434,5.3376 53.0404,4.9646 52.8254,4.5046 C52.6094,4.0456 52.0614,3.6726 51.6014,3.6726 C50.3714,3.6726 49.1784,3.7636 48.0554,3.9426 C47.6324,4.0106 47.5174,4.4336 47.7984,4.8886 C48.0544,5.3016 48.5494,5.5986 48.9544,5.5986" id="Fill-29" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M38.4558,28.4746 C41.5898,35.1436 47.1408,41.4016 54.0858,46.0956 C54.3238,46.2566 54.5728,46.3366 54.7848,46.3366 C54.9988,46.3366 55.1738,46.2546 55.2598,46.0896 C55.4298,45.7636 55.1798,45.2356 54.7008,44.9126 C48.2228,40.5336 43.0448,34.6966 40.1208,28.4746 C37.7008,23.3246 37.0648,18.4506 38.2838,14.3796 C39.4638,10.4356 42.3918,7.5286 46.5268,6.1936 C46.9118,6.0696 46.9538,5.6106 46.6218,5.1676 C46.2888,4.7246 45.7088,4.4676 45.3248,4.5906 C40.8908,6.0226 37.7518,9.1386 36.4868,13.3646 C35.1808,17.7296 35.8618,22.9536 38.4558,28.4746" id="Fill-30" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M77.4417,51.3588 C76.3937,51.5268 75.2797,51.6118 74.1307,51.6118 C73.6717,51.6118 73.4737,51.9838 73.6907,52.4438 C73.9057,52.9028 74.4537,53.2758 74.9137,53.2758 C76.1437,53.2758 77.3367,53.1848 78.4607,53.0048 C78.8827,52.9378 78.9977,52.5148 78.7167,52.0598 C78.4357,51.6058 77.8647,51.2918 77.4417,51.3588" id="Fill-31" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M88.0589,28.4741 C84.9249,21.8061 79.3749,15.5481 72.4319,10.8551 C71.9539,10.5311 71.4279,10.5341 71.2579,10.8601 C71.0879,11.1871 71.3379,11.7141 71.8159,12.0371 C78.2939,16.4161 83.4709,22.2531 86.3949,28.4741 C88.7639,33.5141 89.4229,38.3051 88.3009,42.3281 C87.2169,46.2181 84.4469,49.1491 80.5019,50.5781 C80.1259,50.7151 80.0999,51.1811 80.4419,51.6201 C80.7209,51.9771 81.1569,52.2061 81.5129,52.2061 C81.5939,52.2061 81.6709,52.1951 81.7419,52.1691 C85.9709,50.6351 88.9399,47.4951 90.1029,43.3251 C91.3049,39.0121 90.5989,33.8771 88.0589,28.4741" id="Fill-32" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M36.5716,28.4746 C36.3556,28.0146 35.8076,27.6416 35.3476,27.6416 C34.8886,27.6416 34.6906,28.0146 34.9066,28.4746 C37.7026,34.4226 42.1996,40.1156 47.9136,44.9396 C48.1826,45.1666 48.4956,45.2876 48.7556,45.2876 C48.9226,45.2876 49.0686,45.2376 49.1656,45.1336 C49.4136,44.8656 49.2566,44.3466 48.8136,43.9726 C43.4356,39.4326 39.2026,34.0736 36.5716,28.4746" id="Fill-33" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M56.8172,49.5649 C55.1282,48.6039 53.4612,47.5269 51.8632,46.3639 C51.3942,46.0229 50.8562,45.9969 50.6592,46.3039 C50.4632,46.6129 50.6842,47.1389 51.1522,47.4799 C52.8492,48.7149 54.6202,49.8589 56.4142,50.8789 C56.6212,50.9979 56.8282,51.0549 57.0062,51.0549 C57.2542,51.0549 57.4482,50.9439 57.5132,50.7329 C57.6242,50.3699 57.3132,49.8469 56.8172,49.5649" id="Fill-34" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M75.7991,55.1606 C70.9321,55.1606 65.5491,53.8386 60.2301,51.3366 C59.7241,51.0986 59.2721,51.2246 59.2191,51.6186 C59.1671,52.0126 59.5341,52.5236 60.0391,52.7616 C65.6911,55.4206 71.4111,56.8246 76.5821,56.8246 C77.0411,56.8246 77.2381,56.4526 77.0231,55.9926 C76.8061,55.5326 76.2591,55.1606 75.7991,55.1606" id="Fill-35" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M71.843,8.6733 C75.749,11.1523 79.3,14.1083 82.396,17.4603 C85.599,20.9283 88.139,24.6343 89.944,28.4743 C90.16,28.9343 90.707,29.3063 91.167,29.3063 C91.627,29.3063 91.824,28.9343 91.608,28.4743 C89.691,24.3953 86.993,20.4583 83.588,16.7723 C80.3,13.2113 76.528,10.0713 72.379,7.4383 C71.893,7.1303 71.379,7.1563 71.231,7.4983 C71.083,7.8393 71.357,8.3653 71.843,8.6733" id="Fill-36" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M64.1145,4.6572 C65.5935,5.2632 67.0835,5.9662 68.5425,6.7462 C68.7385,6.8512 68.9315,6.9012 69.0985,6.9012 C69.3585,6.9012 69.5575,6.7802 69.6135,6.5532 C69.7045,6.1782 69.3735,5.6592 68.8735,5.3912 C67.3235,4.5622 65.7405,3.8162 64.1695,3.1722 C63.6625,2.9652 63.2385,3.1282 63.2225,3.5382 C63.2075,3.9492 63.6075,4.4492 64.1145,4.6572" id="Fill-37" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M50.7161,1.788 C53.6641,1.788 56.7851,2.266 59.9921,3.207 C60.0951,3.237 60.1921,3.252 60.2811,3.252 C60.6281,3.252 60.8491,3.034 60.8041,2.687 C60.7471,2.252 60.2931,1.78 59.7881,1.631 C56.3801,0.631 53.0651,0.123 49.9331,0.123 C49.4741,0.123 49.2761,0.496 49.4921,0.956 C49.7081,1.415 50.2561,1.788 50.7161,1.788" id="Fill-38" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M36.7913,1.5722 C37.1013,1.3622 37.0253,0.8602 36.6233,0.4512 C36.2213,0.0432 35.6443,-0.1178 35.3333,0.0932 C32.3243,2.1362 30.1993,4.9382 29.0183,8.4202 C28.8973,8.7782 29.1993,9.3012 29.6923,9.5912 C29.9053,9.7152 30.1183,9.7762 30.3023,9.7762 C30.5443,9.7762 30.7353,9.6702 30.8043,9.4672 C31.9243,6.1662 33.9383,3.5102 36.7913,1.5722" id="Fill-39" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M29.3557,10.9082 C28.8527,10.6582 28.3887,10.7682 28.3197,11.1542 C28.1767,11.9612 28.0807,12.8002 28.0327,13.6492 C28.0107,14.0562 28.4037,14.5592 28.9107,14.7732 C29.0647,14.8382 29.2117,14.8692 29.3417,14.8692 C29.6417,14.8692 29.8547,14.7072 29.8707,14.4242 C29.9157,13.6192 30.0067,12.8242 30.1427,12.0592 C30.2107,11.6732 29.8587,11.1582 29.3557,10.9082" id="Fill-40" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M96.823,47.3579 C96.33,47.0689 95.832,47.1249 95.711,47.4819 C94.591,50.7829 92.576,53.4389 89.723,55.3769 C89.414,55.5869 89.489,56.0889 89.891,56.4979 C90.174,56.7849 90.542,56.9499 90.844,56.9499 C90.972,56.9499 91.089,56.9199 91.181,56.8569 C94.191,54.8119 96.316,52.0099 97.497,48.5289 C97.617,48.1709 97.316,47.6469 96.823,47.3579" id="Fill-41" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M97.6082,41.9389 C97.1012,41.7279 96.6742,41.8889 96.6562,42.2969 C96.6162,43.1809 96.5212,44.0529 96.3722,44.8889 C96.3042,45.2749 96.6562,45.7909 97.1592,46.0409 C97.3412,46.1299 97.5192,46.1739 97.6742,46.1739 C97.9462,46.1739 98.1512,46.0409 98.1942,45.7939 C98.3512,44.9129 98.4522,43.9929 98.4942,43.0589 C98.5122,42.6509 98.1162,42.1489 97.6082,41.9389" id="Fill-42" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M70.7937,44.5092 C61.9517,44.5092 51.3777,37.3162 47.2227,28.4742 C43.0667,19.6332 46.8797,12.4392 55.7217,12.4392 C64.5637,12.4392 75.1377,19.6332 79.2927,28.4742 C83.4477,37.3162 79.6357,44.5092 70.7937,44.5092 M54.9397,10.7752 C45.1797,10.7752 40.9717,18.7152 45.5577,28.4742 C50.1447,38.2342 61.8157,46.1742 71.5757,46.1742 C81.3357,46.1742 85.5437,38.2342 80.9577,28.4742 C76.3707,18.7152 64.6987,10.7752 54.9397,10.7752" id="Fill-43" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M36.9939,5.7876 C36.5479,5.4176 35.9899,5.3376 35.7469,5.6096 C34.2189,7.3236 33.1309,9.3756 32.5139,11.7096 C32.4159,12.0796 32.7409,12.6006 33.2389,12.8726 C33.4379,12.9816 33.6359,13.0346 33.8059,13.0346 C34.0619,13.0346 34.2599,12.9166 34.3179,12.6946 C34.8999,10.4966 35.9239,8.5646 37.3629,6.9516 C37.6049,6.6786 37.4399,6.1586 36.9939,5.7876" id="Fill-44" fill="#1B243D" mask="url(#mask-2)"></path>
<path d="M90.5696,51.5581 C92.2026,49.8011 93.3576,47.6751 94.0016,45.2401 C94.0996,44.8691 93.7756,44.3481 93.2766,44.0761 C92.7776,43.8041 92.2946,43.8831 92.1966,44.2541 C91.5906,46.5471 90.5026,48.5491 88.9656,50.2041 C88.7166,50.4701 88.8746,50.9911 89.3176,51.3641 C89.5866,51.5911 89.8996,51.7121 90.1596,51.7121 C90.3266,51.7121 90.4716,51.6621 90.5696,51.5581" id="Fill-45" fill="#1B243D" mask="url(#mask-2)"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

BIN
app/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
app/images/pw-128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
app/images/pw-48x48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
app/images/pw128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

35
app/loading.html Normal file
View File

@ -0,0 +1,35 @@
<html>
<head>
<title>MetaMask Loading</title>
<style>
#div-logo {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 256px;
}
#logo {
width: 100%;
animation: pulse 1s ease-in-out infinite;
}
@keyframes pulse {
0% {
opacity: 1;
}
50% {
opacity: 0.5;
transform: scale(0.95, 0.95);
}
100% {
opacity: 1;
}
}
</style>
</head>
<body>
<div id="div-logo">
<img id="logo" src="./images/loginglogo.svg">
</div>
</body>
</html>

View File

@ -59,7 +59,10 @@
"unlimitedStorage",
"clipboardWrite",
"http://localhost:8545/",
"https://*.infura.io/"
"https://*.infura.io/",
"activeTab",
"webRequest",
"*://*.eth/"
],
"web_accessible_resources": [
"inpage.js"
@ -72,4 +75,4 @@
"*"
]
}
}
}

View File

@ -26,6 +26,8 @@ const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics')
const EdgeEncryptor = require('./edge-encryptor')
const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code')
const getObjStructure = require('./lib/getObjStructure')
const ipfsContent = require('./lib/ipfsContent.js')
const {
ENVIRONMENT_TYPE_POPUP,
ENVIRONMENT_TYPE_NOTIFICATION,
@ -66,6 +68,7 @@ initialize().catch(log.error)
// setup metamask mesh testing container
setupMetamaskMeshMetrics()
/**
* An object representing a transaction, in whatever state it is in.
* @typedef TransactionMeta
@ -155,6 +158,7 @@ async function initialize () {
const initLangCode = await getFirstPreferredLangCode()
await setupController(initState, initLangCode)
log.debug('MetaMask initialization complete.')
ipfsContent(initState.NetworkController.provider)
}
//
@ -258,6 +262,7 @@ function setupController (initState, initLangCode) {
})
global.metamaskController = controller
// report failed transactions to Sentry
controller.txController.on(`tx:status-update`, (txId, status) => {
if (status !== 'failed') return
@ -378,7 +383,7 @@ function setupController (initState, initLangCode) {
}
// communication with page or other extension
function connectExternal(remotePort) {
function connectExternal (remotePort) {
const originDomain = urlUtil.parse(remotePort.sender.url).hostname
const portStream = new PortStream(remotePort)
controller.setupUntrustedCommunication(portStream, originDomain)

View File

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

View File

@ -60,7 +60,7 @@ class BalanceController {
* Sets up listeners and subscriptions which should trigger an update of ethBalance. These updates include:
* - when a transaction changes state to 'submitted', 'confirmed' or 'failed'
* - when the current account changes (i.e. a new account is selected)
* - when there is a block update
* - when there is a block update
*
* @private
*
@ -100,7 +100,7 @@ class BalanceController {
/**
* Gets the pending transactions (i.e. those with a 'submitted' status). These are accessed from the
* TransactionController passed to this BalanceController during construction.
* TransactionController passed to this BalanceController during construction.
*
* @private
* @returns {Promise<array>} Promises an array of transaction objects.

View File

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

View File

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

View File

@ -16,9 +16,9 @@ class CurrencyController {
* currentCurrency, conversionRate and conversionDate properties
* @property {string} currentCurrency A 2-4 character shorthand that describes a specific currency, currently
* selected by the user
* @property {number} conversionRate The conversion rate from ETH to the selected currency.
* @property {number} conversionRate The conversion rate from ETH to the selected currency.
* @property {string} conversionDate The date at which the conversion rate was set. Expressed in in milliseconds
* since midnight of January 1, 1970
* since midnight of January 1, 1970
* @property {number} conversionInterval The id of the interval created by the scheduleConversionInterval method.
* Used to clear an existing interval on subsequent calls of that method.
*
@ -59,7 +59,7 @@ class CurrencyController {
/**
* A getter for the conversionRate property
*
* @returns {string} The conversion rate from ETH to the selected currency.
* @returns {string} The conversion rate from ETH to the selected currency.
*
*/
getConversionRate () {
@ -80,7 +80,7 @@ class CurrencyController {
* A getter for the conversionDate property
*
* @returns {string} The date at which the conversion rate was set. Expressed in milliseconds since midnight of
* January 1, 1970
* January 1, 1970
*
*/
getConversionDate () {

View File

@ -132,7 +132,7 @@ module.exports = class NetworkController extends EventEmitter {
} else if (type === LOCALHOST) {
this._configureStandardProvider({ rpcUrl: LOCALHOST_RPC_URL })
// url-based rpc endpoints
} else if (type === 'rpc'){
} else if (type === 'rpc') {
this._configureStandardProvider({ rpcUrl: rpcTarget })
} else {
throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`)

View File

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

View File

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

View File

@ -126,4 +126,4 @@ class TxGasUtil {
}
}
module.exports = TxGasUtil
module.exports = TxGasUtil

View File

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

View File

@ -0,0 +1 @@
module.exports = [{'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'resolver', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'owner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'label', 'type': 'bytes32'}, {'name': 'owner', 'type': 'address'}], 'name': 'setSubnodeOwner', 'outputs': [], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'ttl', 'type': 'uint64'}], 'name': 'setTTL', 'outputs': [], 'payable': false, 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'ttl', 'outputs': [{'name': '', 'type': 'uint64'}], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'resolver', 'type': 'address'}], 'name': 'setResolver', 'outputs': [], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'owner', 'type': 'address'}], 'name': 'setOwner', 'outputs': [], 'payable': false, 'type': 'function'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'owner', 'type': 'address'}], 'name': 'Transfer', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': true, 'name': 'label', 'type': 'bytes32'}, {'indexed': false, 'name': 'owner', 'type': 'address'}], 'name': 'NewOwner', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'resolver', 'type': 'address'}], 'name': 'NewResolver', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'ttl', 'type': 'uint64'}], 'name': 'NewTTL', 'type': 'event'}]

View File

@ -0,0 +1,2 @@
module.exports =
[{'constant': true, 'inputs': [{'name': 'interfaceID', 'type': 'bytes4'}], 'name': 'supportsInterface', 'outputs': [{'name': '', 'type': 'bool'}], 'payable': false, 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'contentTypes', 'type': 'uint256'}], 'name': 'ABI', 'outputs': [{'name': 'contentType', 'type': 'uint256'}, {'name': 'data', 'type': 'bytes'}], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'x', 'type': 'bytes32'}, {'name': 'y', 'type': 'bytes32'}], 'name': 'setPubkey', 'outputs': [], 'payable': false, 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'content', 'outputs': [{'name': 'ret', 'type': 'bytes32'}], 'payable': false, 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'addr', 'outputs': [{'name': 'ret', 'type': 'address'}], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'contentType', 'type': 'uint256'}, {'name': 'data', 'type': 'bytes'}], 'name': 'setABI', 'outputs': [], 'payable': false, 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'name', 'outputs': [{'name': 'ret', 'type': 'string'}], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'name', 'type': 'string'}], 'name': 'setName', 'outputs': [], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'hash', 'type': 'bytes32'}], 'name': 'setContent', 'outputs': [], 'payable': false, 'type': 'function'}, {'constant': true, 'inputs': [{'name': 'node', 'type': 'bytes32'}], 'name': 'pubkey', 'outputs': [{'name': 'x', 'type': 'bytes32'}, {'name': 'y', 'type': 'bytes32'}], 'payable': false, 'type': 'function'}, {'constant': false, 'inputs': [{'name': 'node', 'type': 'bytes32'}, {'name': 'addr', 'type': 'address'}], 'name': 'setAddr', 'outputs': [], 'payable': false, 'type': 'function'}, {'inputs': [{'name': 'ensAddr', 'type': 'address'}], 'payable': false, 'type': 'constructor'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'a', 'type': 'address'}], 'name': 'AddrChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'hash', 'type': 'bytes32'}], 'name': 'ContentChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'name', 'type': 'string'}], 'name': 'NameChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': true, 'name': 'contentType', 'type': 'uint256'}], 'name': 'ABIChanged', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': 'node', 'type': 'bytes32'}, {'indexed': false, 'name': 'x', 'type': 'bytes32'}, {'indexed': false, 'name': 'y', 'type': 'bytes32'}], 'name': 'PubkeyChanged', 'type': 'event'}]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,40 @@
const extension = require('extensionizer')
const resolver = require('./resolver.js')
module.exports = function (provider) {
extension.webRequest.onBeforeRequest.addListener(details => {
const urlhttpreplace = details.url.replace(/\w+?:\/\//, '')
const url = urlhttpreplace.replace(/[\\/].*/g, '') // eslint-disable-line no-useless-escape
let domainhtml = urlhttpreplace.match(/[\\/].*/g) // eslint-disable-line no-useless-escape
let clearTime = null
const name = url.replace(/\/$/g, '')
if (domainhtml === null) domainhtml = ['']
extension.tabs.getSelected(null, tab => {
extension.tabs.update(tab.id, { url: 'loading.html' })
clearTime = setTimeout(() => {
return extension.tabs.update(tab.id, { url: '404.html' })
}, 60000)
resolver.resolve(name, provider).then(ipfsHash => {
clearTimeout(clearTime)
let url = 'https://ipfs.infura.io/ipfs/' + ipfsHash + domainhtml[0]
return fetch(url, { method: 'HEAD' }).then(response => response.status).then(statusCode => {
if (statusCode !== 200) return extension.tabs.update(tab.id, { url: '404.html' })
extension.tabs.update(tab.id, { url: url })
})
.catch(err => {
url = 'https://ipfs.infura.io/ipfs/' + ipfsHash + domainhtml[0]
extension.tabs.update(tab.id, {url: url})
return err
})
})
.catch(err => {
clearTimeout(clearTime)
const url = err === 'unsupport' ? 'unsupport' : 'error'
extension.tabs.update(tab.id, {url: `${url}.html?name=${name}`})
})
})
return { cancel: true }
}, {urls: ['*://*.eth/', '*://*.eth/*']})
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,71 @@
const namehash = require('eth-ens-namehash')
const multihash = require('multihashes')
const HttpProvider = require('ethjs-provider-http')
const Eth = require('ethjs-query')
const EthContract = require('ethjs-contract')
const registrarAbi = require('./contracts/registrar')
const resolverAbi = require('./contracts/resolver')
function ens (name, provider) {
const eth = new Eth(new HttpProvider(getProvider(provider.type)))
const hash = namehash.hash(name)
const contract = new EthContract(eth)
const Registrar = contract(registrarAbi).at(getRegistrar(provider.type))
return new Promise((resolve, reject) => {
if (provider.type === 'mainnet' || provider.type === 'ropsten') {
Registrar.resolver(hash).then((address) => {
if (address === '0x0000000000000000000000000000000000000000') {
reject(null)
} else {
const Resolver = contract(resolverAbi).at(address['0'])
return Resolver.content(hash)
}
}).then((contentHash) => {
if (contentHash['0'] === '0x0000000000000000000000000000000000000000000000000000000000000000') reject(null)
if (contentHash.ret !== '0x') {
const hex = contentHash['0'].substring(2)
const buf = multihash.fromHexString(hex)
resolve(multihash.toB58String(multihash.encode(buf, 'sha2-256')))
} else {
reject(null)
}
})
} else {
return reject('unsupport')
}
})
}
function getProvider (type) {
switch (type) {
case 'mainnet':
return 'https://mainnet.infura.io/'
case 'ropsten':
return 'https://ropsten.infura.io/'
default:
return 'http://localhost:8545/'
}
}
function getRegistrar (type) {
switch (type) {
case 'mainnet':
return '0x314159265dd8dbb310642f98f50c066173c1259b'
case 'ropsten':
return '0x112234455c3a32fd11230c42e7bccd4a84e02010'
default:
return '0x0000000000000000000000000000000000000000'
}
}
module.exports.resolve = function (name, provider) {
const path = name.split('.')
const tld = path[path.length - 1]
if (tld === 'eth') {
return ens(name, provider)
} else {
return new Promise((resolve, reject) => {
reject(null)
})
}
}

View File

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

View File

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

View File

@ -338,6 +338,7 @@ module.exports = class MetamaskController extends EventEmitter {
markAccountsFound: this.markAccountsFound.bind(this),
markPasswordForgotten: this.markPasswordForgotten.bind(this),
unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this),
getGasPrice: (cb) => cb(null, this.getGasPrice()),
// coinbase
buyEth: this.buyEth.bind(this),
@ -405,7 +406,6 @@ module.exports = class MetamaskController extends EventEmitter {
}
//=============================================================================
// VAULT / KEYRING RELATED METHODS
//=============================================================================
@ -962,7 +962,7 @@ module.exports = class MetamaskController extends EventEmitter {
* Allows a user to begin the seed phrase recovery process.
* @param {Function} cb - A callback function called when complete.
*/
markPasswordForgotten(cb) {
markPasswordForgotten (cb) {
this.configManager.setPasswordForgotten(true)
this.sendUpdate()
cb()
@ -972,7 +972,7 @@ module.exports = class MetamaskController extends EventEmitter {
* Allows a user to end the seed phrase recovery process.
* @param {Function} cb - A callback function called when complete.
*/
unMarkPasswordForgotten(cb) {
unMarkPasswordForgotten (cb) {
this.configManager.setPasswordForgotten(false)
this.sendUpdate()
cb()

View File

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

View File

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

View File

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

View File

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

59
app/unsupport.html Normal file
View File

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MetaMask</title>
</head>
<style>
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
img{
display: block;
}
html, body{
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
@keyframes logoAmin{
from {transform: scale(1);}
50%{transform: scale(1.1);}
to {transform: scale(1);}
}
.unsupport{
width: 80%;
height: auto;
overflow: hidden;
padding: 10px;
}
.unsupport > img{
margin: 0 auto 31px auto;
width: 136px;
height: auto;
animation: logoAmin 1s infinite linear;
}
.unsupport > h1{
text-align: center;
font-family: Gotham;
font-size: 18px;
font-weight: 500;
font-style: normal;
font-stretch: normal;
line-height: normal;
letter-spacing: 1.3px;
color: #33559f;
}
</style>
<body>
<div class="unsupport">
<img src="./images/cancel.png" alt="">
<h1>ENS resolver only support on Ethereum mainnet</h1>
</div>
</body>
</html>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -183,6 +183,7 @@ App.prototype.renderAppBar = function () {
this.setState({ isNetworkMenuOpen: !isNetworkMenuOpen })
},
}),
]),
props.isUnlocked && h('div', {

View File

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

View File

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

View File

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

View File

@ -34,9 +34,13 @@ TypedMessageRenderer.prototype.render = function () {
function renderTypedData (values) {
return values.map(function (value) {
let v = value.value
if (typeof v === 'boolean') {
v = v.toString()
}
return h('div', {}, [
h('strong', {style: {display: 'block', fontWeight: 'bold'}}, String(value.name) + ':'),
h('div', {}, value.value),
h('div', {}, v),
])
})
}

View File

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

View File

@ -42,9 +42,6 @@ RestoreVaultScreen.prototype.render = function () {
// wallet seed entry
h('h3', 'Wallet Seed'),
h('textarea.twelve-word-phrase.letter-spacey', {
dataset: {
persistentFormId: 'wallet-seed',
},
placeholder: 'Enter your secret twelve word phrase here to restore your vault.',
}),

66477
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -38,8 +38,8 @@
"test:mascara:build:tests": "browserify test/integration/lib/first-time.js -o dist/mascara/tests.js",
"ganache:start": "ganache-cli -m 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'",
"sentry:publish": "node ./development/sentry-publish.js",
"lint": "gulp lint",
"lint:fix": "gulp lint:fix",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"ui": "npm run test:flat:build:states && beefy development/ui-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
"mock": "beefy development/mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./",
"watch": "mocha watch --recursive \"test/unit/**/*.js\"",
@ -93,7 +93,7 @@
"ensnare": "^1.0.0",
"eslint-plugin-react": "^7.4.0",
"eth-bin-to-ops": "^1.0.1",
"eth-contract-metadata": "^1.1.5",
"eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master",
"eth-hd-keyring": "^1.2.1",
"eth-json-rpc-filters": "^1.2.6",
"eth-json-rpc-infura": "^3.0.0",
@ -107,7 +107,7 @@
"ethereumjs-wallet": "^0.6.0",
"etherscan-link": "^1.0.2",
"ethjs": "^0.4.0",
"ethjs-contract": "^0.2.0",
"ethjs-contract": "^0.2.3",
"ethjs-ens": "^2.0.0",
"ethjs-query": "^0.3.4",
"express": "^4.15.5",
@ -183,6 +183,7 @@
"semaphore": "^1.0.5",
"semver": "^5.4.1",
"shallow-copy": "0.0.1",
"superstatic": "^5.0.2",
"sw-controller": "^1.0.3",
"sw-stream": "^2.0.2",
"textarea-caret": "^3.0.1",
@ -191,7 +192,9 @@
"web3": "^0.20.1",
"web3-provider-engine": "^14.0.5",
"web3-stream-provider": "^3.0.1",
"xtend": "^4.0.1"
"xtend": "^4.0.1",
"multihashes": "^0.4.12",
"eth-ens-namehash": "^2.0.8"
},
"devDependencies": {
"@sentry/cli": "^1.30.3",
@ -208,7 +211,7 @@
"babel-register": "^6.7.2",
"babelify": "^8.0.0",
"beefy": "^2.1.5",
"brfs": "^1.4.3",
"brfs": "^1.6.1",
"browserify": "^16.1.1",
"chai": "^4.1.0",
"chromedriver": "2.36.0",
@ -232,13 +235,12 @@
"file-loader": "^1.1.11",
"fs-promise": "^2.0.3",
"ganache-cli": "^6.1.0",
"ganache-core": "^2.1.0",
"ganache-core": "^2.1.3",
"geckodriver": "^1.11.0",
"gh-pages": "^1.1.0",
"gh-pages": "^1.2.0",
"gifencoder": "^1.1.0",
"gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed",
"gulp-babel": "^7.0.0",
"gulp-eslint": "^4.0.0",
"gulp-json-editor": "^2.2.1",
"gulp-livereload": "^3.8.1",
"gulp-multi-process": "^1.3.1",
@ -251,13 +253,14 @@
"gulp-util": "^3.0.7",
"gulp-watch": "^5.0.0",
"gulp-zip": "^4.0.0",
"http-server": "^0.11.1",
"image-size": "^0.6.2",
"isomorphic-fetch": "^2.2.1",
"jsdoc": "^3.5.5",
"jsdom": "^11.2.0",
"jsdom-global": "^3.0.2",
"jshint-stylish": "~2.2.1",
"karma": "^2.0.0",
"karma": "^2.0.4",
"karma-chrome-launcher": "^2.2.0",
"karma-cli": "^1.0.1",
"karma-firefox-launcher": "^1.0.1",
@ -268,9 +271,9 @@
"mocha-jsdom": "^1.1.0",
"mocha-sinon": "^2.0.0",
"nock": "^9.0.14",
"node-sass": "^4.7.2",
"node-sass": "^4.9.0",
"nsp": "^3.2.1",
"nyc": "^11.0.3",
"nyc": "^13.0.0",
"open": "0.0.5",
"path": "^0.12.7",
"png-file-stream": "^1.0.0",
@ -293,11 +296,11 @@
"style-loader": "^0.21.0",
"stylelint-config-standard": "^18.2.0",
"tape": "^4.5.1",
"testem": "^2.0.0",
"testem": "^2.8.0",
"through2": "^2.0.3",
"vinyl-buffer": "^1.0.1",
"vinyl-source-stream": "^2.0.0",
"watchify": "^3.9.0"
"watchify": "^3.11.0"
},
"engines": {
"node": ">=8.0.0"

View File

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

View File

@ -0,0 +1,66 @@
/*
The `piggybankContract` is compiled from:
pragma solidity ^0.4.0;
contract PiggyBank {
uint private balance;
address public owner;
function PiggyBank() public {
owner = msg.sender;
balance = 0;
}
function deposit() public payable returns (uint) {
balance += msg.value;
return balance;
}
function withdraw(uint withdrawAmount) public returns (uint remainingBal) {
require(msg.sender == owner);
balance -= withdrawAmount;
msg.sender.transfer(withdrawAmount);
return balance;
}
}
*/
var piggybankContract = web3.eth.contract([{'constant': false, 'inputs': [{'name': 'withdrawAmount', 'type': 'uint256'}], 'name': 'withdraw', 'outputs': [{'name': 'remainingBal', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'owner', 'outputs': [{'name': '', 'type': 'address'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [], 'name': 'deposit', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': true, 'stateMutability': 'payable', 'type': 'function'}, {'inputs': [], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}])
const deployButton = document.getElementById('deployButton')
const depositButton = document.getElementById('depositButton')
const withdrawButton = document.getElementById('withdrawButton')
deployButton.addEventListener('click', async function (event) {
var piggybank = await piggybankContract.new(
{
from: web3.eth.accounts[0],
data: '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029',
gas: '4700000',
}, function (e, contract) {
console.log(e, contract)
if (typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash)
console.log(`contract`, contract)
depositButton.addEventListener('click', function (event) {
contract.deposit({ from: web3.eth.accounts[0], value: '0x29a2241af62c0000' }, function (result) {
console.log(result)
})
})
withdrawButton.addEventListener('click', function (event) {
contract.withdraw('0xde0b6b3a7640000', { from: web3.eth.accounts[0] }, function (result) {
console.log(result)
})
})
}
})
console.log(piggybank)
})

View File

@ -0,0 +1,8 @@
<html>
<body>
<button id="deployButton">Deploy Contract</button>
<button id="depositButton">Deposit</button>
<button id="withdrawButton">Withdraw</button>
</body>
<script src="contract.js"></script>
</html>

View File

@ -12,7 +12,6 @@ const {
} = require('../func')
const {
checkBrowserForConsoleErrors,
loadExtension,
verboseReportOnFailure,
findElement,
findElements,
@ -22,13 +21,12 @@ const {
describe('Using MetaMask with an existing account', function () {
let extensionId
let driver
let tokenAddress
const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'
const testAddress = '0xE18035BF8712672935FDB4e5e431b1a0183d2DFC'
const testPrivateKey2 = '14abe6f4aab7f9f626fe981c864d0adeb5685f289ac9270c27b8fd790b4235d6'
const regularDelayMs = 1000
const largeDelayMs = regularDelayMs * 2
const waitingNewPageDelayMs = regularDelayMs * 10
this.timeout(0)
this.bail(true)
@ -97,15 +95,16 @@ describe('Using MetaMask with an existing account', function () {
await delay(regularDelayMs)
// Close all other tabs
let [oldUi, infoPage, newUi] = await driver.getAllWindowHandles()
newUi = newUi || infoPage
const [oldUi, infoPage, newUi] = await driver.getAllWindowHandles()
const newUiOrInfoPage = newUi || infoPage
await driver.switchTo().window(oldUi)
await driver.close()
if (infoPage !== newUi) {
if (infoPage !== newUiOrInfoPage) {
await driver.switchTo().window(infoPage)
await driver.close()
}
await driver.switchTo().window(newUi)
await driver.switchTo().window(newUiOrInfoPage)
await delay(regularDelayMs)
const continueBtn = await findElement(driver, By.css('.welcome-screen__button'))
@ -166,8 +165,7 @@ describe('Using MetaMask with an existing account', function () {
describe('Show account information', () => {
it('shows the correct account address', async () => {
const detailsButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Details')]`))
detailsButton.click()
await driver.findElement(By.css('.wallet-view__details-button')).click()
await driver.findElement(By.css('.qr-wrapper')).isDisplayed()
await delay(regularDelayMs)
@ -263,8 +261,10 @@ describe('Using MetaMask with an existing account', function () {
await configureGas.click()
await delay(regularDelayMs)
const gasModal = await driver.findElement(By.css('span .modal'))
const save = await findElement(driver, By.xpath(`//button[contains(text(), 'Save')]`))
await save.click()
await driver.wait(until.stalenessOf(gasModal))
await delay(regularDelayMs)
// Continue to next screen
@ -289,143 +289,36 @@ describe('Using MetaMask with an existing account', function () {
})
})
describe('Send ETH from Faucet', () => {
it('starts a send transaction inside Faucet', async () => {
await driver.executeScript('window.open("https://faucet.metamask.io")')
await delay(waitingNewPageDelayMs)
const [extension, faucet] = await driver.getAllWindowHandles()
await driver.switchTo().window(faucet)
describe('Imports an account with private key', () => {
it('choose Create Account from the account menu', async () => {
await driver.findElement(By.css('.account-menu__icon')).click()
await delay(regularDelayMs)
const send1eth = await findElement(driver, By.xpath(`//button[contains(text(), '10 ether')]`), 14000)
await send1eth.click()
const [importAccount] = await findElements(driver, By.xpath(`//div[contains(text(), 'Import Account')]`))
await importAccount.click()
await delay(regularDelayMs)
})
await driver.switchTo().window(extension)
await loadExtension(driver, extensionId)
it('enter private key', async () => {
const privateKeyInput = await findElement(driver, By.css('#private-key-box'))
await privateKeyInput.sendKeys(testPrivateKey2)
await delay(regularDelayMs)
const importButtons = await findElements(driver, By.xpath(`//button[contains(text(), 'Import')]`))
await importButtons[0].click()
await delay(regularDelayMs)
})
const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`), 14000)
await confirmButton.click()
it('should show the correct account name', async () => {
const [accountName] = await findElements(driver, By.css('.account-name'))
assert.equal(await accountName.getText(), 'Account 3')
await delay(regularDelayMs)
})
await driver.switchTo().window(faucet)
await delay(regularDelayMs)
await driver.close()
await delay(regularDelayMs)
await driver.switchTo().window(extension)
await delay(regularDelayMs)
await loadExtension(driver, extensionId)
it('should show the imported label', async () => {
const [importedLabel] = await findElements(driver, By.css('.wallet-view__keyring-label'))
assert.equal(await importedLabel.getText(), 'IMPORTED')
await delay(regularDelayMs)
})
})
describe('Add existing token using search', () => {
it('clicks on the Add Token button', async () => {
const addToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Token')]`))
await addToken.click()
await delay(regularDelayMs)
})
it('picks an existing token', async () => {
const tokenSearch = await findElement(driver, By.css('#search-tokens'))
await tokenSearch.sendKeys('BAT')
await delay(regularDelayMs)
const token = await findElement(driver, By.xpath("//span[contains(text(), 'BAT')]"))
await token.click()
await delay(regularDelayMs)
const nextScreen = await findElement(driver, By.xpath(`//button[contains(text(), 'Next')]`))
await nextScreen.click()
await delay(regularDelayMs)
const addTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Tokens')]`))
await addTokens.click()
await delay(largeDelayMs)
})
it('renders the balance for the new token', async () => {
const balance = await findElement(driver, By.css('.tx-view .balance-display .token-amount'))
await driver.wait(until.elementTextMatches(balance, /^0\s*BAT\s*$/), 10000)
const tokenAmount = await balance.getText()
assert.ok(/^0\s*BAT\s*$/.test(tokenAmount))
await delay(regularDelayMs)
})
})
describe('Add a custom token from TokenFactory', () => {
it('creates a new token', async () => {
await driver.executeScript('window.open("https://tokenfactory.surge.sh/#/factory")')
await delay(waitingNewPageDelayMs)
const [extension, tokenFactory] = await driver.getAllWindowHandles()
await driver.switchTo().window(tokenFactory)
const [
totalSupply,
tokenName,
tokenDecimal,
tokenSymbol,
] = await findElements(driver, By.css('.form-control'))
await totalSupply.sendKeys('100')
await tokenName.sendKeys('Test')
await tokenDecimal.sendKeys('0')
await tokenSymbol.sendKeys('TST')
const createToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Create Token')]`))
await createToken.click()
await delay(regularDelayMs)
await driver.switchTo().window(extension)
await loadExtension(driver, extensionId)
await delay(regularDelayMs)
const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
await confirmButton.click()
await delay(regularDelayMs)
await driver.switchTo().window(tokenFactory)
await delay(regularDelayMs)
const tokenContactAddress = await driver.findElement(By.css('div > div > div:nth-child(2) > span:nth-child(3)'))
tokenAddress = await tokenContactAddress.getText()
await driver.close()
await driver.switchTo().window(extension)
await loadExtension(driver, extensionId)
await delay(regularDelayMs)
})
it('clicks on the Add Token button', async () => {
const addToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Token')]`))
await addToken.click()
await delay(regularDelayMs)
})
it('picks the new Test token', async () => {
const addCustomToken = await findElement(driver, By.xpath("//div[contains(text(), 'Custom Token')]"))
await addCustomToken.click()
await delay(regularDelayMs)
const newTokenAddress = await findElement(driver, By.css('#custom-address'))
await newTokenAddress.sendKeys(tokenAddress)
await delay(regularDelayMs)
const nextScreen = await findElement(driver, By.xpath(`//button[contains(text(), 'Next')]`))
await nextScreen.click()
await delay(regularDelayMs)
const addTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Tokens')]`))
await addTokens.click()
await delay(regularDelayMs)
})
it('renders the balance for the new token', async () => {
const balance = await findElement(driver, By.css('.tx-view .balance-display .token-amount'))
await driver.wait(until.elementTextMatches(balance, /^100\s*TST\s*$/), 10000)
const tokenAmount = await balance.getText()
assert.ok(/^100\s*TST\s*$/.test(tokenAmount))
await delay(regularDelayMs)
})
})
})

View File

@ -2,6 +2,7 @@ const fs = require('fs')
const mkdirp = require('mkdirp')
const pify = require('pify')
const {until} = require('selenium-webdriver')
const { delay } = require('../func')
module.exports = {
checkBrowserForConsoleErrors,
@ -9,6 +10,7 @@ module.exports = {
verboseReportOnFailure,
findElement,
findElements,
openNewPage,
}
async function loadExtension (driver, extensionId) {
@ -64,3 +66,15 @@ async function findElement (driver, by, timeout = 10000) {
async function findElements (driver, by, timeout = 10000) {
return driver.wait(until.elementsLocated(by), timeout)
}
async function openNewPage (driver, url) {
await driver.executeScript('window.open()')
await delay(1000)
const handles = await driver.getAllWindowHandles()
const secondHandle = handles[1]
await driver.switchTo().window(secondHandle)
await driver.get(url)
await delay(1000)
}

View File

@ -16,6 +16,7 @@ const {
checkBrowserForConsoleErrors,
loadExtension,
verboseReportOnFailure,
openNewPage,
} = require('./helpers')
describe('MetaMask', function () {
@ -27,7 +28,6 @@ describe('MetaMask', function () {
const tinyDelayMs = 1000
const regularDelayMs = tinyDelayMs * 2
const largeDelayMs = regularDelayMs * 2
const waitingNewPageDelayMs = regularDelayMs * 30
this.timeout(0)
this.bail(true)
@ -62,7 +62,7 @@ describe('MetaMask', function () {
}
}
if (this.currentTest.state === 'failed') {
await verboseReportOnFailure(this.currentTest)
await verboseReportOnFailure(driver, this.currentTest)
}
})
@ -71,14 +71,20 @@ describe('MetaMask', function () {
})
describe('New UI setup', async function () {
let networkSelector
it('switches to first tab', async function () {
const [firstTab] = await driver.getAllWindowHandles()
await driver.switchTo().window(firstTab)
await delay(regularDelayMs)
try {
networkSelector = await findElement(driver, By.css('#network_component'))
} catch (e) {
await loadExtension(driver, extensionId)
}
await delay(regularDelayMs)
})
it('use the local network', async function () {
const networkSelector = await findElement(driver, By.css('#network_component'))
await networkSelector.click()
await delay(regularDelayMs)
@ -93,15 +99,21 @@ describe('MetaMask', function () {
await delay(regularDelayMs)
// Close all other tabs
let [oldUi, infoPage, newUi] = await driver.getAllWindowHandles()
newUi = newUi || infoPage
const [oldUi, tab1, tab2] = await driver.getAllWindowHandles()
await driver.switchTo().window(oldUi)
await driver.close()
if (infoPage !== newUi) {
await driver.switchTo().window(infoPage)
await driver.switchTo().window(tab1)
const tab1Url = await driver.getCurrentUrl()
if (tab1Url.match(/metamask.io/)) {
await driver.switchTo().window(tab1)
await driver.close()
await driver.switchTo().window(tab2)
} else if (tab2) {
await driver.switchTo().window(tab2)
await driver.close()
await driver.switchTo().window(tab1)
}
await driver.switchTo().window(newUi)
await delay(regularDelayMs)
const continueBtn = await findElement(driver, By.css('.welcome-screen__button'))
@ -136,6 +148,7 @@ describe('MetaMask', function () {
await driver.executeScript('arguments[0].scrollIntoView(true)', bottomOfTos)
await delay(regularDelayMs)
const acceptTos = await findElement(driver, By.css('.tou button'))
driver.wait(until.elementIsEnabled(acceptTos))
await acceptTos.click()
await delay(regularDelayMs)
})
@ -160,8 +173,10 @@ describe('MetaMask', function () {
let seedPhrase
it('reveals the seed phrase', async () => {
const revealSeedPhrase = await findElement(driver, By.css('.backup-phrase__secret-blocker'))
await revealSeedPhrase.click()
const byRevealButton = By.css('.backup-phrase__secret-blocker .backup-phrase__reveal-button')
await driver.wait(until.elementLocated(byRevealButton, 10000))
const revealSeedPhraseButton = await findElement(driver, byRevealButton, 10000)
await revealSeedPhraseButton.click()
await delay(regularDelayMs)
seedPhrase = await driver.findElement(By.css('.backup-phrase__secret-words')).getText()
@ -173,56 +188,76 @@ describe('MetaMask', function () {
await delay(regularDelayMs)
})
async function retypeSeedPhrase (words) {
try {
const word0 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[0]}')]`), 10000)
await word0.click()
await delay(tinyDelayMs)
const word1 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[1]}')]`), 10000)
await word1.click()
await delay(tinyDelayMs)
const word2 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[2]}')]`), 10000)
await word2.click()
await delay(tinyDelayMs)
const word3 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[3]}')]`), 10000)
await word3.click()
await delay(tinyDelayMs)
const word4 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[4]}')]`), 10000)
await word4.click()
await delay(tinyDelayMs)
const word5 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[5]}')]`), 10000)
await word5.click()
await delay(tinyDelayMs)
const word6 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[6]}')]`), 10000)
await word6.click()
await delay(tinyDelayMs)
const word7 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[7]}')]`), 10000)
await word7.click()
await delay(tinyDelayMs)
const word8 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[8]}')]`), 10000)
await word8.click()
await delay(tinyDelayMs)
const word9 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[9]}')]`), 10000)
await word9.click()
await delay(tinyDelayMs)
const word10 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[10]}')]`), 10000)
await word10.click()
await delay(tinyDelayMs)
const word11 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[11]}')]`), 10000)
await word11.click()
await delay(tinyDelayMs)
} catch (e) {
await loadExtension(driver, extensionId)
await retypeSeedPhrase(words)
}
}
it('can retype the seed phrase', async () => {
const words = seedPhrase.split(' ')
const word0 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[0]}')]`))
await word0.click()
await delay(tinyDelayMs)
const word1 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[1]}')]`))
await word1.click()
await delay(tinyDelayMs)
const word2 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[2]}')]`))
await word2.click()
await delay(tinyDelayMs)
const word3 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[3]}')]`))
await word3.click()
await delay(tinyDelayMs)
const word4 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[4]}')]`))
await word4.click()
await delay(tinyDelayMs)
const word5 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[5]}')]`))
await word5.click()
await delay(tinyDelayMs)
const word6 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[6]}')]`))
await word6.click()
await delay(tinyDelayMs)
const word7 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[7]}')]`))
await word7.click()
await delay(tinyDelayMs)
const word8 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[8]}')]`))
await word8.click()
await delay(tinyDelayMs)
const word9 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[9]}')]`))
await word9.click()
await delay(tinyDelayMs)
const word10 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[10]}')]`))
await word10.click()
await delay(tinyDelayMs)
const word11 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[11]}')]`))
await word11.click()
await delay(tinyDelayMs)
await retypeSeedPhrase(words)
const confirm = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
await confirm.click()
@ -230,7 +265,8 @@ describe('MetaMask', function () {
})
it('clicks through the deposit modal', async () => {
const buyModal = await driver.findElement(By.css('span .modal'))
const byBuyModal = By.css('span .modal')
const buyModal = await driver.wait(until.elementLocated(byBuyModal))
const closeModal = await findElement(driver, By.css('.page-container__header-close'))
await closeModal.click()
await driver.wait(until.stalenessOf(buyModal))
@ -244,8 +280,12 @@ describe('MetaMask', function () {
await driver.findElement(By.css('.qr-wrapper')).isDisplayed()
await delay(regularDelayMs)
const accountModal = await driver.findElement(By.css('span .modal'))
await driver.executeScript("document.querySelector('.account-modal-close').click()")
await delay(regularDelayMs * 4)
await driver.wait(until.stalenessOf(accountModal))
await delay(regularDelayMs)
})
})
@ -315,9 +355,12 @@ describe('MetaMask', function () {
await seedTextArea.sendKeys(testSeedPhrase)
await delay(regularDelayMs)
await driver.findElement(By.id('password-box')).sendKeys('correct horse battery staple')
await driver.findElement(By.id('password-box-confirm')).sendKeys('correct horse battery staple')
await driver.findElement(By.css('button:nth-child(2)')).click()
const passwordInputs = await driver.findElements(By.css('input'))
await delay(regularDelayMs)
passwordInputs[0].sendKeys('correct horse battery staple')
passwordInputs[1].sendKeys('correct horse battery staple')
await driver.findElement(By.css('.first-time-flow__button')).click()
await delay(regularDelayMs)
})
@ -345,8 +388,11 @@ describe('MetaMask', function () {
await configureGas.click()
await delay(regularDelayMs)
const gasModal = await driver.findElement(By.css('span .modal'))
const save = await findElement(driver, By.xpath(`//button[contains(text(), 'Save')]`))
await save.click()
await driver.wait(until.stalenessOf(gasModal))
await delay(regularDelayMs)
// Continue to next screen
@ -365,19 +411,20 @@ describe('MetaMask', function () {
const transactions = await findElements(driver, By.css('.tx-list-item'))
assert.equal(transactions.length, 1)
const txValues = await findElements(driver, By.css('.tx-list-value'))
assert.equal(txValues.length, 1)
assert.equal(await txValues[0].getText(), '1 ETH')
const txValues = await findElement(driver, By.css('.tx-list-value'))
await driver.wait(until.elementTextMatches(txValues, /1\sETH/), 10000)
})
})
describe('Send ETH from Faucet', () => {
it('starts a send transaction inside Faucet', async () => {
await driver.executeScript('window.open("https://faucet.metamask.io")')
await delay(waitingNewPageDelayMs)
await openNewPage(driver, 'https://faucet.metamask.io')
const [extension, faucet] = await driver.getAllWindowHandles()
await driver.switchTo().window(faucet)
const faucetPageTitle = await findElement(driver, By.css('.container-fluid'))
await driver.wait(until.elementTextMatches(faucetPageTitle, /MetaMask/))
await delay(regularDelayMs)
const send1eth = await findElement(driver, By.xpath(`//button[contains(text(), '10 ether')]`), 14000)
@ -403,47 +450,133 @@ describe('MetaMask', function () {
})
})
describe('Add existing token using search', () => {
it('clicks on the Add Token button', async () => {
const addToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Token')]`))
await addToken.click()
describe('Deploy contract and call contract methods', () => {
let extension
let contractTestPage
it('confirms a deploy contract transaction', async () => {
await openNewPage(driver, 'http://127.0.0.1:8080/');
[extension, contractTestPage] = await driver.getAllWindowHandles()
await delay(regularDelayMs)
const deployContractButton = await findElement(driver, By.css('#deployButton'))
await deployContractButton.click()
await delay(regularDelayMs)
await driver.switchTo().window(extension)
await delay(regularDelayMs)
const txListItem = await findElement(driver, By.css('.tx-list-item'))
await txListItem.click()
await delay(regularDelayMs)
const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
await confirmButton.click()
await delay(regularDelayMs)
const txStatuses = await findElements(driver, By.css('.tx-list-status'))
await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed/))
const txAccounts = await findElements(driver, By.css('.tx-list-account'))
assert.equal(await txAccounts[0].getText(), 'Contract Deployment')
})
it('can pick a token from the existing options', async () => {
const tokenSearch = await findElement(driver, By.css('#search-tokens'))
await tokenSearch.sendKeys('BAT')
it('calls and confirms a contract method where ETH is sent', async () => {
await driver.switchTo().window(contractTestPage)
await delay(regularDelayMs)
const token = await findElement(driver, By.xpath("//span[contains(text(), 'BAT')]"))
await token.click()
const depositButton = await findElement(driver, By.css('#depositButton'))
await depositButton.click()
await delay(regularDelayMs)
const nextScreen = await findElement(driver, By.xpath(`//button[contains(text(), 'Next')]`))
await nextScreen.click()
await driver.switchTo().window(extension)
await delay(regularDelayMs)
const addTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Tokens')]`))
await addTokens.click()
await delay(largeDelayMs)
const txListItem = await findElement(driver, By.css('.tx-list-item'))
await txListItem.click()
await delay(regularDelayMs)
// Set the gas limit
const configureGas = await findElement(driver, By.css('.sliders-icon-container'))
await configureGas.click()
await delay(regularDelayMs)
const gasModal = await driver.findElement(By.css('span .modal'))
await driver.wait(until.elementLocated(By.css('.send-v2__customize-gas__title')))
const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.customize-gas-input'))
await gasPriceInput.clear()
await gasPriceInput.sendKeys('10')
await gasLimitInput.clear()
await gasLimitInput.sendKeys('60001')
const save = await findElement(driver, By.xpath(`//button[contains(text(), 'Save')]`))
await save.click()
await delay(regularDelayMs)
await driver.wait(until.stalenessOf(gasModal))
const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
await confirmButton.click()
await delay(regularDelayMs)
const txStatuses = await findElements(driver, By.css('.tx-list-status'))
await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed/))
const txValues = await findElement(driver, By.css('.tx-list-value'))
await driver.wait(until.elementTextMatches(txValues, /3\sETH/), 10000)
const txAccounts = await findElements(driver, By.css('.tx-list-account'))
const firstTxAddress = await txAccounts[0].getText()
assert(firstTxAddress.match(/^0x\w{8}\.{3}\w{4}$/))
})
it('renders the balance for the chosen token', async () => {
it('calls and confirms a contract method where ETH is received', async () => {
await driver.switchTo().window(contractTestPage)
await delay(regularDelayMs)
const withdrawButton = await findElement(driver, By.css('#withdrawButton'))
await withdrawButton.click()
await delay(regularDelayMs)
await driver.switchTo().window(extension)
await delay(regularDelayMs)
const txListItem = await findElement(driver, By.css('.tx-list-item'))
await txListItem.click()
await delay(regularDelayMs)
const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
await confirmButton.click()
await delay(regularDelayMs)
const txStatuses = await findElements(driver, By.css('.tx-list-status'))
await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed/))
const txValues = await findElement(driver, By.css('.tx-list-value'))
await driver.wait(until.elementTextMatches(txValues, /0\sETH/), 10000)
await driver.switchTo().window(contractTestPage)
await driver.close()
await driver.switchTo().window(extension)
})
it('renders the correct ETH balance', async () => {
const balance = await findElement(driver, By.css('.tx-view .balance-display .token-amount'))
await driver.wait(until.elementTextMatches(balance, /^0\s*BAT\s*$/), 10000)
await driver.wait(until.elementTextMatches(balance, /^86.*ETH.*$/), 10000)
const tokenAmount = await balance.getText()
assert.ok(/^0\s*BAT\s*$/.test(tokenAmount))
assert.ok(/^86.*ETH.*$/.test(tokenAmount))
await delay(regularDelayMs)
})
})
describe('Add a custom token from TokenFactory', () => {
it('creates a new token', async () => {
await driver.executeScript('window.open("https://tokenfactory.surge.sh/#/factory")')
await delay(waitingNewPageDelayMs)
openNewPage(driver, 'https://tokenfactory.surge.sh/#/factory')
await delay(regularDelayMs * 10)
const [extension, tokenFactory] = await driver.getAllWindowHandles()
await driver.switchTo().window(tokenFactory)
const [
totalSupply,
tokenName,
@ -470,12 +603,16 @@ describe('MetaMask', function () {
await driver.switchTo().window(tokenFactory)
await delay(regularDelayMs)
const tokenContactAddress = await driver.findElement(By.css('div > div > div:nth-child(2) > span:nth-child(3)'))
tokenAddress = await tokenContactAddress.getText()
await driver.close()
await driver.switchTo().window(extension)
await loadExtension(driver, extensionId)
await driver.switchTo().window(extension)
await delay(regularDelayMs)
})
it('clicks on the Add Token button', async () => {
@ -510,4 +647,212 @@ describe('MetaMask', function () {
await delay(regularDelayMs)
})
})
describe('Send token from inside MetaMask', () => {
let gasModal
it('starts to send a transaction', async function () {
const sendButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Send')]`))
await sendButton.click()
await delay(regularDelayMs)
const inputAddress = await findElement(driver, By.css('input[placeholder="Recipient Address"]'))
const inputAmount = await findElement(driver, By.css('.currency-display__input'))
await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970')
await inputAmount.sendKeys('50')
// Set the gas limit
const configureGas = await findElement(driver, By.css('.send-v2__gas-fee-display button'))
await configureGas.click()
await delay(regularDelayMs)
gasModal = await driver.findElement(By.css('span .modal'))
})
it('customizes gas', async () => {
await driver.wait(until.elementLocated(By.css('.send-v2__customize-gas__title')))
const save = await findElement(driver, By.xpath(`//button[contains(text(), 'Save')]`))
await save.click()
await delay(regularDelayMs)
})
it('transitions to the confirm screen', async () => {
await driver.wait(until.stalenessOf(gasModal))
// Continue to next screen
const nextScreen = await findElement(driver, By.xpath(`//button[contains(text(), 'Next')]`))
await nextScreen.click()
await delay(regularDelayMs)
})
it('submits the transaction', async function () {
const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
await confirmButton.click()
await delay(regularDelayMs)
})
it('finds the transaction in the transactions list', async function () {
const transactions = await findElements(driver, By.css('.tx-list-item'))
assert.equal(transactions.length, 1)
const txValues = await findElements(driver, By.css('.tx-list-value'))
assert.equal(txValues.length, 1)
// test cancelled on firefox until https://github.com/mozilla/geckodriver/issues/906 is resolved,
// or possibly until we use latest version of firefox in the tests
if (process.env.SELENIUM_BROWSER !== 'firefox') {
await driver.wait(until.elementTextMatches(txValues[0], /50\sTST/), 10000)
}
const txStatuses = await findElements(driver, By.css('.tx-list-status'))
const tx = await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed|Failed/), 10000)
assert.equal(await tx.getText(), 'Confirmed')
})
})
describe('Send a custom token from TokenFactory', () => {
let gasModal
it('sends an already created token', async () => {
openNewPage(driver, `https://tokenfactory.surge.sh/#/token/${tokenAddress}`)
const [extension] = await driver.getAllWindowHandles()
const [
transferToAddress,
transferToAmount,
] = await findElements(driver, By.css('.form-control'))
await transferToAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970')
await transferToAmount.sendKeys('26')
const transferAmountButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Transfer Amount')]`))
await transferAmountButton.click()
await delay(regularDelayMs)
const [,, popup] = await driver.getAllWindowHandles()
await driver.switchTo().window(popup)
await driver.close()
await driver.switchTo().window(extension)
await delay(regularDelayMs)
const [txListItem] = await findElements(driver, By.css('.tx-list-item'))
await txListItem.click()
await delay(regularDelayMs)
// Set the gas limit
const configureGas = await driver.wait(until.elementLocated(By.css('.send-v2__gas-fee-display button')))
await configureGas.click()
await delay(regularDelayMs)
gasModal = await driver.findElement(By.css('span .modal'))
})
it('customizes gas', async () => {
await driver.wait(until.elementLocated(By.css('.send-v2__customize-gas__title')))
const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.customize-gas-input'))
await gasPriceInput.clear()
await delay(tinyDelayMs)
await gasPriceInput.sendKeys('10')
await delay(tinyDelayMs)
await gasLimitInput.clear()
await delay(tinyDelayMs)
await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'a'))
await gasLimitInput.sendKeys('60000')
await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'e'))
// Needed for different behaviour of input in different versions of firefox
const gasLimitInputValue = await gasLimitInput.getAttribute('value')
if (gasLimitInputValue === '600001') {
await gasLimitInput.sendKeys(Key.BACK_SPACE)
}
const save = await findElement(driver, By.css('.send-v2__customize-gas__save'))
await save.click()
await driver.wait(until.stalenessOf(gasModal))
const gasFeeInput = await findElement(driver, By.css('.currency-display__input'))
assert.equal(await gasFeeInput.getAttribute('value'), 0.0006)
})
it('submits the transaction', async function () {
const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`))
await confirmButton.click()
await delay(regularDelayMs)
})
it('finds the transaction in the transactions list', async function () {
const transactions = await findElements(driver, By.css('.tx-list-item'))
assert.equal(transactions.length, 2)
const txValues = await findElements(driver, By.css('.tx-list-value'))
await driver.wait(until.elementTextMatches(txValues[0], /26\sTST/))
const txStatuses = await findElements(driver, By.css('.tx-list-status'))
await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed/))
const walletBalance = await findElement(driver, By.css('.wallet-balance'))
await walletBalance.click()
const tokenListItems = await findElements(driver, By.css('.token-list-item'))
await tokenListItems[0].click()
// test cancelled on firefox until https://github.com/mozilla/geckodriver/issues/906 is resolved,
// or possibly until we use latest version of firefox in the tests
if (process.env.SELENIUM_BROWSER !== 'firefox') {
const tokenBalanceAmount = await findElement(driver, By.css('.token-balance__amount'))
assert.equal(await tokenBalanceAmount.getText(), '24')
}
})
})
describe('Hide token', () => {
it('hides the token when clicked', async () => {
const [hideTokenEllipsis] = await findElements(driver, By.css('.token-list-item__ellipsis'))
await hideTokenEllipsis.click()
const byTokenMenuDropdownOption = By.css('.menu__item--clickable')
const tokenMenuDropdownOption = await driver.wait(until.elementLocated(byTokenMenuDropdownOption))
await tokenMenuDropdownOption.click()
const confirmHideModal = await findElement(driver, By.css('span .modal'))
const byHideTokenConfirmationButton = By.css('.hide-token-confirmation__button')
const hideTokenConfirmationButton = await driver.wait(until.elementLocated(byHideTokenConfirmationButton))
await hideTokenConfirmationButton.click()
await driver.wait(until.stalenessOf(confirmHideModal))
})
})
describe('Add existing token using search', () => {
it('clicks on the Add Token button', async () => {
const addToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Token')]`))
await addToken.click()
await delay(regularDelayMs)
})
it('can pick a token from the existing options', async () => {
const tokenSearch = await findElement(driver, By.css('#search-tokens'))
await tokenSearch.sendKeys('BAT')
await delay(regularDelayMs)
const token = await findElement(driver, By.xpath("//span[contains(text(), 'BAT')]"))
await token.click()
await delay(regularDelayMs)
const nextScreen = await findElement(driver, By.xpath(`//button[contains(text(), 'Next')]`))
await nextScreen.click()
await delay(regularDelayMs)
const addTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Add Tokens')]`))
await addTokens.click()
await delay(largeDelayMs)
})
it('renders the balance for the chosen token', async () => {
const balance = await findElement(driver, By.css('.tx-view .balance-display .token-amount'))
await driver.wait(until.elementTextMatches(balance, /0\sBAT/))
await delay(regularDelayMs)
})
})
})

View File

@ -6,5 +6,5 @@ set -o pipefail
export PATH="$PATH:./node_modules/.bin"
shell-parallel -s 'npm run ganache:start' -x 'sleep 5 && mocha test/e2e/beta/metamask-beta-ui.spec'
shell-parallel -s 'npm run ganache:start' -x 'sleep 5 && mocha test/e2e/beta/from-import-beta-ui.spec'
shell-parallel -s 'npm run ganache:start' -x 'sleep 5 && superstatic test/e2e/beta/contract-test/ --port 8080 --host 127.0.0.1' -x 'sleep 5 && mocha test/e2e/beta/metamask-beta-ui.spec'
shell-parallel -s 'npm run ganache:start -- -d' -x 'sleep 5 && superstatic test/e2e/beta/contract-test/ --port 8080 --host 127.0.0.1' -x 'sleep 5 && mocha test/e2e/beta/from-import-beta-ui.spec'

View File

@ -4,7 +4,7 @@ const path = require('path')
const assert = require('assert')
const pify = require('pify')
const webdriver = require('selenium-webdriver')
const { By, Key } = webdriver
const { By, Key, until } = webdriver
const { delay, buildChromeWebDriver, buildFirefoxWebdriver, installWebExt, getExtensionIdChrome, getExtensionIdFirefox } = require('./func')
describe('Metamask popup page', function () {
@ -229,7 +229,11 @@ describe('Metamask popup page', function () {
it('confirms transaction', async function () {
await delay(300)
await driver.findElement(By.css('#pending-tx-form > div.flex-row.flex-space-around.conf-buttons > input')).click()
const bySubmitButton = By.css('#pending-tx-form > div.flex-row.flex-space-around.conf-buttons > input')
const submitButton = await driver.wait(until.elementLocated(bySubmitButton))
submitButton.click()
await delay(500)
})
@ -269,7 +273,8 @@ describe('Metamask popup page', function () {
it('confirms transaction in MetaMask popup', async function () {
const windowHandles = await driver.getAllWindowHandles()
await driver.switchTo().window(windowHandles[windowHandles.length - 1])
const metamaskSubmit = await driver.findElement(By.css('#pending-tx-form > div.flex-row.flex-space-around.conf-buttons > input'))
const byMetamaskSubmit = By.css('#pending-tx-form > div.flex-row.flex-space-around.conf-buttons > input')
const metamaskSubmit = await driver.wait(until.elementLocated(byMetamaskSubmit))
await metamaskSubmit.click()
await delay(1000)
})
@ -330,7 +335,7 @@ describe('Metamask popup page', function () {
await driver.executeScript('window.metamask.setProviderType(arguments[0])', type)
}
async function checkBrowserForConsoleErrors() {
async function checkBrowserForConsoleErrors () {
const ignoredLogTypes = ['WARNING']
const ignoredErrorMessages = [
// React throws error warnings on "dataset", but still sets the data-* properties correctly

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