From 7d3da0ae96a761461ee12bf20d8386a5ba7aade2 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Mon, 25 Jun 2018 11:45:00 -0700 Subject: migration 27 - remove rejected transactions from state --- test/unit/migrations/027-test.js | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 test/unit/migrations/027-test.js (limited to 'test') diff --git a/test/unit/migrations/027-test.js b/test/unit/migrations/027-test.js new file mode 100644 index 000000000..77c0bbee6 --- /dev/null +++ b/test/unit/migrations/027-test.js @@ -0,0 +1,50 @@ +const assert = require('assert') +const migration27 = require('../../../app/scripts/migrations/027') + +const oldStorage = { + "meta": {}, + "data": { + "TransactionController": { + "transactions": [ + ] + }, + }, +} + +const transactions = [] + + +while (transactions.length < 9) { + transactions.push({status: 'rejected'}) + transactions.push({status: 'unapproved'}) + transactions.push({status: 'approved'}) +} + + +oldStorage.data.TransactionController.transactions = transactions + +describe('migration #27', () => { + it('should remove rejected transactions', (done) => { + migration27.migrate(oldStorage) + .then((newStorage) => { + const newTransactions = newStorage.data.TransactionController.transactions + assert.equal(newTransactions.length, 6, 'transactions is expected to have the length of 6') + newTransactions.forEach((txMeta) => { + if (txMeta.status === 'rejected') done(new Error('transaction was found with a status of rejected')) + }) + done() + }) + .catch(done) + }) + + it('should successfully migrate first time state', (done) => { + migration27.migrate({ + meta: {}, + data: require('../../../app/scripts/first-time-state'), + }) + .then((migratedData) => { + assert.equal(migratedData.meta.version, migration27.version) + done() + }).catch(done) + }) +}) -- cgit v1.2.3 From 9b92ba4c47d5489c5c0f822045360be708110cac Mon Sep 17 00:00:00 2001 From: frankiebee Date: Mon, 25 Jun 2018 15:07:54 -0700 Subject: trandsactions - remove rejected transactions from history --- .../app/controllers/transactions/tx-state-manager-test.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'test') diff --git a/test/unit/app/controllers/transactions/tx-state-manager-test.js b/test/unit/app/controllers/transactions/tx-state-manager-test.js index 20bc08b94..f2d0175cb 100644 --- a/test/unit/app/controllers/transactions/tx-state-manager-test.js +++ b/test/unit/app/controllers/transactions/tx-state-manager-test.js @@ -288,4 +288,18 @@ describe('TransactionStateManager', function () { }) }) + + describe.only('#_removeTx', function () { + it('should remove the transaction from the storage', () => { + txStateManager._saveTxList([ {id: 1} ]) + txStateManager._removeTx(1) + assert(!txStateManager.getFullTxList().length, 'txList should be empty') + }) + + it('should only remove the transaction with ID 1 from the storage', () => { + txStateManager._saveTxList([ {id: 1}, {id: 2} ]) + txStateManager._removeTx(1) + assert.equal(txStateManager.getFullTxList()[0].id, 2, 'txList should have a id of 2') + }) + }) }) -- cgit v1.2.3 From 7b1f57e05d7a186be085ffcc8807516499218cba Mon Sep 17 00:00:00 2001 From: frankiebee Date: Mon, 25 Jun 2018 15:16:27 -0700 Subject: woops - remove .only Co-authored-by: @jennypollack --- test/unit/app/controllers/transactions/tx-state-manager-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/unit/app/controllers/transactions/tx-state-manager-test.js b/test/unit/app/controllers/transactions/tx-state-manager-test.js index f2d0175cb..8b7dc78aa 100644 --- a/test/unit/app/controllers/transactions/tx-state-manager-test.js +++ b/test/unit/app/controllers/transactions/tx-state-manager-test.js @@ -289,7 +289,7 @@ describe('TransactionStateManager', function () { }) }) - describe.only('#_removeTx', function () { + describe('#_removeTx', function () { it('should remove the transaction from the storage', () => { txStateManager._saveTxList([ {id: 1} ]) txStateManager._removeTx(1) -- cgit v1.2.3 From 94a4f99115cf549a3014d29d828e7a432bf36a62 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Mon, 25 Jun 2018 16:16:51 -0700 Subject: tests - fix cancle transaction test to better fit new behavior --- .../unit/app/controllers/transactions/tx-controller-test.js | 13 ++++++++++--- .../app/controllers/transactions/tx-state-manager-test.js | 10 ---------- 2 files changed, 10 insertions(+), 13 deletions(-) (limited to 'test') diff --git a/test/unit/app/controllers/transactions/tx-controller-test.js b/test/unit/app/controllers/transactions/tx-controller-test.js index 9bdfe7c1a..4328f38e5 100644 --- a/test/unit/app/controllers/transactions/tx-controller-test.js +++ b/test/unit/app/controllers/transactions/tx-controller-test.js @@ -357,9 +357,16 @@ describe('Transaction Controller', function () { ]) }) - it('should set the transaction to rejected from unapproved', async function () { - await txController.cancelTransaction(0) - assert.equal(txController.txStateManager.getTx(0).status, 'rejected') + it('should emit a status change to rejected', function (done) { + txController.once('tx:status-update', (txId, status) => { + try { + assert.equal(status, 'rejected', 'status should e rejected') + assert.equal(txId, 0, 'id should e 0') + done() + } catch (e) { done(e) } + }) + + txController.cancelTransaction(0) }) }) diff --git a/test/unit/app/controllers/transactions/tx-state-manager-test.js b/test/unit/app/controllers/transactions/tx-state-manager-test.js index 8b7dc78aa..39c2d6337 100644 --- a/test/unit/app/controllers/transactions/tx-state-manager-test.js +++ b/test/unit/app/controllers/transactions/tx-state-manager-test.js @@ -45,16 +45,6 @@ describe('TransactionStateManager', function () { }) describe('#setTxStatusRejected', function () { - it('sets the tx status to rejected', function () { - let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } - txStateManager.addTx(tx) - txStateManager.setTxStatusRejected(1) - let result = txStateManager.getTxList() - assert.ok(Array.isArray(result)) - assert.equal(result.length, 1) - assert.equal(result[0].status, 'rejected') - }) - it('should emit a rejected event to signal the exciton of callback', (done) => { let tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } txStateManager.addTx(tx) -- cgit v1.2.3 From 6284e664810fe0dcdcb35e55cc57bc11b9298dbb Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Wed, 27 Jun 2018 22:18:06 -0400 Subject: tests for spec --- test/unit/app/controllers/detect-tokens-test.js | 101 ++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 test/unit/app/controllers/detect-tokens-test.js (limited to 'test') diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js new file mode 100644 index 000000000..f9f5c902d --- /dev/null +++ b/test/unit/app/controllers/detect-tokens-test.js @@ -0,0 +1,101 @@ +const assert = require('assert') +const sinon = require('sinon') +const DetectTokensController = require('../../../../app/scripts/controllers/detect-tokens') +const PreferencesController = require('../../../../app/scripts/controllers/preferences') +const ObservableStore = require('obs-store') + +describe('DetectTokensController', () => { + it('should poll on correct interval', async () => { + const stub = sinon.stub(global, 'setInterval') + new DetectTokensController({ interval: 1337 }) // eslint-disable-line no-new + assert.strictEqual(stub.getCall(0).args[1], 1337) + stub.restore() + }) + + it('should not check tokens while in test network', async () => { + var network = new ObservableStore({provider: {type:'rinkeby'}}) + const preferences = new PreferencesController() + const controller = new DetectTokensController({preferences: preferences, network: network}) + controller.isActive = true + controller.contracts = { + "0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4": { + "name": "JET8 Token", + "logo": "J8T.svg", + "erc20": true, + "symbol": "J8T", + "decimals": 8 + }, + "0xBC86727E770de68B1060C91f6BB6945c73e10388": { + "name": "Ink Protocol", + "logo": "ink_protocol.svg", + "erc20": true, + "symbol": "XNK", + "decimals": 18 + } + } + controller.fetchContractAccountBalance = address => address + + await controller.exploreNewTokens() + assert.deepEqual(preferences.store.getState().tokens, []) + + }) + + it('should only check and add tokens while in main network', async () => { + const network = new ObservableStore({provider: {type:'mainnet'}}) + const preferences = new PreferencesController() + const controller = new DetectTokensController({preferences: preferences, network: network}) + controller.isActive = true + controller.contracts = { + "0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4": { + "name": "JET8 Token", + "logo": "J8T.svg", + "erc20": true, + "symbol": "J8T", + "decimals": 8 + }, + "0xBC86727E770de68B1060C91f6BB6945c73e10388": { + "name": "Ink Protocol", + "logo": "ink_protocol.svg", + "erc20": true, + "symbol": "XNK", + "decimals": 18 + } + } + controller.fetchContractAccountBalance = address => address + + await controller.exploreNewTokens() + assert.deepEqual(preferences.store.getState().tokens, + [{address: "0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4", decimals: 8, symbol: "J8T"}, + {address: "0xbc86727e770de68b1060c91f6bb6945c73e10388", decimals: 18, symbol: "XNK"}]) + }) + + it('should not detect same token while in main network', async () => { + const network = new ObservableStore({provider: {type:'mainnet'}}) + const preferences = new PreferencesController() + preferences.addToken("0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4", 8, "J8T") + const controller = new DetectTokensController({preferences: preferences, network: network}) + controller.isActive = true + controller.contracts = { + "0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4": { + "name": "JET8 Token", + "logo": "J8T.svg", + "erc20": true, + "symbol": "J8T", + "decimals": 8 + }, + "0xBC86727E770de68B1060C91f6BB6945c73e10388": { + "name": "Ink Protocol", + "logo": "ink_protocol.svg", + "erc20": true, + "symbol": "XNK", + "decimals": 18 + } + } + controller.fetchContractAccountBalance = address => address + + await controller.exploreNewTokens() + assert.deepEqual(preferences.store.getState().tokens, + [{address: "0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4", decimals: 8, symbol: "J8T"}, + {address: "0xbc86727e770de68b1060c91f6bb6945c73e10388", decimals: 18, symbol: "XNK"}]) + }) +}) -- cgit v1.2.3 From 63b9c8796bf744f05a3b7d88319460eed772efa9 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Tue, 3 Jul 2018 15:24:23 -0400 Subject: fix lint --- test/unit/app/controllers/detect-tokens-test.js | 100 +++++++++++------------- 1 file changed, 46 insertions(+), 54 deletions(-) (limited to 'test') diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js index f9f5c902d..82e86bfcc 100644 --- a/test/unit/app/controllers/detect-tokens-test.js +++ b/test/unit/app/controllers/detect-tokens-test.js @@ -13,89 +13,81 @@ describe('DetectTokensController', () => { }) it('should not check tokens while in test network', async () => { - var network = new ObservableStore({provider: {type:'rinkeby'}}) + var network = new ObservableStore({provider: {type: 'rinkeby'}}) const preferences = new PreferencesController() const controller = new DetectTokensController({preferences: preferences, network: network}) controller.isActive = true controller.contracts = { - "0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4": { - "name": "JET8 Token", - "logo": "J8T.svg", - "erc20": true, - "symbol": "J8T", - "decimals": 8 + '0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4': { + 'name': 'JET8 Token', + 'logo': 'J8T.svg', + 'erc20': true, + 'symbol': 'J8T', + 'decimals': 8, + }, + '0xBC86727E770de68B1060C91f6BB6945c73e10388': { + 'name': 'Ink Protocol', + 'logo': 'ink_protocol.svg', + 'erc20': true, + 'symbol': 'XNK', + 'decimals': 18, }, - "0xBC86727E770de68B1060C91f6BB6945c73e10388": { - "name": "Ink Protocol", - "logo": "ink_protocol.svg", - "erc20": true, - "symbol": "XNK", - "decimals": 18 - } } controller.fetchContractAccountBalance = address => address - await controller.exploreNewTokens() assert.deepEqual(preferences.store.getState().tokens, []) - - }) +}) it('should only check and add tokens while in main network', async () => { - const network = new ObservableStore({provider: {type:'mainnet'}}) + const network = new ObservableStore({provider: {type: 'mainnet'}}) const preferences = new PreferencesController() const controller = new DetectTokensController({preferences: preferences, network: network}) controller.isActive = true controller.contracts = { - "0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4": { - "name": "JET8 Token", - "logo": "J8T.svg", - "erc20": true, - "symbol": "J8T", - "decimals": 8 + '0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4': { + 'name': 'JET8 Token', + 'logo': 'J8T.svg', + 'erc20': true, + 'symbol': 'J8T', + 'decimals': 8, + }, + '0xBC86727E770de68B1060C91f6BB6945c73e10388': { + 'name': 'Ink Protocol', + 'logo': 'ink_protocol.svg', + 'erc20': true, + 'symbol': 'XNK', + 'decimals': 18, }, - "0xBC86727E770de68B1060C91f6BB6945c73e10388": { - "name": "Ink Protocol", - "logo": "ink_protocol.svg", - "erc20": true, - "symbol": "XNK", - "decimals": 18 - } } controller.fetchContractAccountBalance = address => address - await controller.exploreNewTokens() - assert.deepEqual(preferences.store.getState().tokens, - [{address: "0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4", decimals: 8, symbol: "J8T"}, - {address: "0xbc86727e770de68b1060c91f6bb6945c73e10388", decimals: 18, symbol: "XNK"}]) + assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}]) }) it('should not detect same token while in main network', async () => { - const network = new ObservableStore({provider: {type:'mainnet'}}) + const network = new ObservableStore({provider: {type: 'mainnet'}}) const preferences = new PreferencesController() - preferences.addToken("0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4", 8, "J8T") + preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 8, 'J8T') const controller = new DetectTokensController({preferences: preferences, network: network}) controller.isActive = true controller.contracts = { - "0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4": { - "name": "JET8 Token", - "logo": "J8T.svg", - "erc20": true, - "symbol": "J8T", - "decimals": 8 + '0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4': { + 'name': 'JET8 Token', + 'logo': 'J8T.svg', + 'erc20': true, + 'symbol': 'J8T', + 'decimals': 8, + }, + '0xBC86727E770de68B1060C91f6BB6945c73e10388': { + 'name': 'Ink Protocol', + 'logo': 'ink_protocol.svg', + 'erc20': true, + 'symbol': 'XNK', + 'decimals': 18, }, - "0xBC86727E770de68B1060C91f6BB6945c73e10388": { - "name": "Ink Protocol", - "logo": "ink_protocol.svg", - "erc20": true, - "symbol": "XNK", - "decimals": 18 - } } controller.fetchContractAccountBalance = address => address - await controller.exploreNewTokens() - assert.deepEqual(preferences.store.getState().tokens, - [{address: "0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4", decimals: 8, symbol: "J8T"}, - {address: "0xbc86727e770de68b1060c91f6bb6945c73e10388", decimals: 18, symbol: "XNK"}]) + assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}]) }) }) -- cgit v1.2.3 From c47a4ce2c93d50425f580c2a166c1698cf1c508f Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 4 Jul 2018 16:44:56 -0230 Subject: Update new-ui-send integration tests to always explicitly set gas price. (e2e tests handle auto-setting and defaults) --- test/integration/lib/send-new-ui.js | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'test') diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js index 72e4a8cb1..85885f118 100644 --- a/test/integration/lib/send-new-ui.js +++ b/test/integration/lib/send-new-ui.js @@ -114,19 +114,8 @@ async function runSendFlowTest(assert, done) { errorMessage = $('.send-v2__error') assert.equal(errorMessage.length, 0, 'send should stop rendering amount error message after amount is corrected') - const sendGasField = await queryAsync($, '.send-v2__gas-fee-display') - assert.equal( - sendGasField.find('.currency-display__input-wrapper > input').val(), - '0.000021', - 'send gas field should show estimated gas total' - ) - assert.equal( - sendGasField.find('.currency-display__converted-value')[0].textContent, - '$0.03 USD', - 'send gas field should show estimated gas total converted to USD' - ) - await customizeGas(assert, 0, 21000, '0', '$0.00 USD') + await customizeGas(assert, 1, 21000, '0.000021', '$0.03 USD') await customizeGas(assert, 500, 60000, '0.03', '$36.03 USD') const sendButton = await queryAsync($, 'button.btn-primary.btn--large.page-container__footer-button') -- cgit v1.2.3 From f262f0ea64e1e803d8dcd9a31f92cffe81d27b3d Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 22 Jun 2018 14:41:18 -0230 Subject: Update import from seed screen on new ui. --- test/e2e/beta/metamask-beta-ui.spec.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index 5f270b52b..b07b1ecd7 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -355,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) }) -- cgit v1.2.3 From 7d691c7398bef524334791f894427aa3ca53297c Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Sat, 7 Jul 2018 18:53:00 -0700 Subject: Fix existing unit tests --- test/unit/actions/tx_test.js | 102 +++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 61 deletions(-) (limited to 'test') diff --git a/test/unit/actions/tx_test.js b/test/unit/actions/tx_test.js index c110f71fc..160cd4552 100644 --- a/test/unit/actions/tx_test.js +++ b/test/unit/actions/tx_test.js @@ -1,74 +1,54 @@ -// var jsdom = require('mocha-jsdom') var assert = require('assert') -var freeze = require('deep-freeze-strict') var path = require('path') -var sinon = require('sinon') -var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'actions.js')) -var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'reducers.js')) +import configureMockStore from 'redux-mock-store' +import thunk from 'redux-thunk' -describe('tx confirmation screen', function () { - beforeEach(function () { - this.sinon = sinon.createSandbox() - }) - - afterEach(function () { - this.sinon.restore() - }) +const actions = require(path.join(__dirname, '../../../ui/app/actions.js')) - var initialState, result +const middlewares = [thunk] +const mockStore = configureMockStore(middlewares) - describe('when there is only one tx', function () { - var firstTxId = 1457634084250832 - - beforeEach(function () { - initialState = { - appState: { - currentView: { - name: 'confTx', - }, - }, - metamask: { - unapprovedTxs: { - '1457634084250832': { - id: 1457634084250832, - status: 'unconfirmed', - time: 1457634084250, - }, - }, +describe('tx confirmation screen', function () { + const txId = 1457634084250832 + const initialState = { + appState: { + currentView: { + name: 'confTx', + }, + }, + metamask: { + unapprovedTxs: { + [txId]: { + id: txId, + status: 'unconfirmed', + time: 1457634084250, }, - } - freeze(initialState) + }, + }, + } + + const store = mockStore(initialState) + + describe('cancelTx', function () { + before(function (done) { + actions._setBackgroundConnection({ + approveTransaction (txId, cb) { cb('An error!') }, + cancelTransaction (txId, cb) { cb() }, + clearSeedWordCache (cb) { cb() }, + getState (cb) { cb() }, + }) + done() }) - describe('cancelTx', function () { - before(function (done) { - actions._setBackgroundConnection({ - approveTransaction (txId, cb) { cb('An error!') }, - cancelTransaction (txId, cb) { cb() }, - clearSeedWordCache (cb) { cb() }, + it('creates COMPLETED_TX with the cancelled transaction ID', function (done) { + store.dispatch(actions.cancelTx({ id: txId })) + .then(() => { + const storeActions = store.getActions() + const completedTxAction = storeActions.find(({ type }) => type === actions.COMPLETED_TX) + assert.equal(completedTxAction.value, txId) + done() }) - - actions.cancelTx({value: firstTxId})((action) => { - result = reducers(initialState, action) - }) - done() - }) - - it('should transition to the account detail view', function () { - assert.equal(result.appState.currentView.name, 'accountDetail') - }) - - it('should have no unconfirmed txs remaining', function () { - var count = getUnconfirmedTxCount(result) - assert.equal(count, 0) - }) }) }) }) - -function getUnconfirmedTxCount (state) { - var txs = state.metamask.unapprovedTxs - var count = Object.keys(txs).length - return count -} -- cgit v1.2.3 From 8a678001a959b5cb3d6b1d50920882c8f9b58043 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 10 Jul 2018 11:43:00 -0700 Subject: test - fix for lint --- test/unit/migrations/027-test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/unit/migrations/027-test.js b/test/unit/migrations/027-test.js index 77c0bbee6..3ec9f0c0e 100644 --- a/test/unit/migrations/027-test.js +++ b/test/unit/migrations/027-test.js @@ -2,11 +2,11 @@ const assert = require('assert') const migration27 = require('../../../app/scripts/migrations/027') const oldStorage = { - "meta": {}, - "data": { - "TransactionController": { - "transactions": [ - ] + 'meta': {}, + 'data': { + 'TransactionController': { + 'transactions': [ + ], }, }, } -- cgit v1.2.3 From 1a0a701de0fe97386a5acb666c4a4e123f27af94 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 6 Jul 2018 20:25:30 -0230 Subject: Handles window indeterminancy issues for external dapps in e2e beta tests. --- test/e2e/beta/contract-test/contract.js | 114 ++++++++++++++++----- test/e2e/beta/contract-test/index.html | 33 +++++- test/e2e/beta/helpers.js | 48 ++++++++- test/e2e/beta/metamask-beta-ui.spec.js | 174 +++++++++++++++++--------------- 4 files changed, 255 insertions(+), 114 deletions(-) (limited to 'test') diff --git a/test/e2e/beta/contract-test/contract.js b/test/e2e/beta/contract-test/contract.js index 18c866f21..8af008dce 100644 --- a/test/e2e/beta/contract-test/contract.js +++ b/test/e2e/beta/contract-test/contract.js @@ -32,35 +32,103 @@ var piggybankContract = web3.eth.contract([{'constant': false, 'inputs': [{'name const deployButton = document.getElementById('deployButton') const depositButton = document.getElementById('depositButton') const withdrawButton = document.getElementById('withdrawButton') +const sendButton = document.getElementById('sendButton') +const createToken = document.getElementById('createToken') +const transferTokens = document.getElementById('transferTokens') +const approveTokens = document.getElementById('approveTokens') 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) - 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) - }) + console.log(`contract`, contract) + + depositButton.addEventListener('click', function (event) { + contract.deposit({ from: web3.eth.accounts[0], value: '0x3782dace9d900000' }, 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) +}) + +sendButton.addEventListener('click', function (event) { + web3.eth.sendTransaction({ + from: web3.eth.accounts[0], + to: '0x2f318C334780961FB129D2a6c30D0763d9a5C970', + value: '0x29a2241af62c0000', + gas: 21000, + gasPrice: 20000000000, + }, (result) => { + console.log(result) + }) +}) + + +createToken.addEventListener('click', async function (event) { + var _initialAmount = 100 + var _tokenName = 'TST' + var _decimalUnits = 0 + var _tokenSymbol = 'TST' + var humanstandardtokenContract = web3.eth.contract([{'constant': true, 'inputs': [], 'name': 'name', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_spender', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'approve', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'totalSupply', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_from', 'type': 'address'}, {'name': '_to', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'transferFrom', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'decimals', 'outputs': [{'name': '', 'type': 'uint8'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'version', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [{'name': '_owner', 'type': 'address'}], 'name': 'balanceOf', 'outputs': [{'name': 'balance', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': true, 'inputs': [], 'name': 'symbol', 'outputs': [{'name': '', 'type': 'string'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_to', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}], 'name': 'transfer', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': false, 'inputs': [{'name': '_spender', 'type': 'address'}, {'name': '_value', 'type': 'uint256'}, {'name': '_extraData', 'type': 'bytes'}], 'name': 'approveAndCall', 'outputs': [{'name': 'success', 'type': 'bool'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'function'}, {'constant': true, 'inputs': [{'name': '_owner', 'type': 'address'}, {'name': '_spender', 'type': 'address'}], 'name': 'allowance', 'outputs': [{'name': 'remaining', 'type': 'uint256'}], 'payable': false, 'stateMutability': 'view', 'type': 'function'}, {'inputs': [{'name': '_initialAmount', 'type': 'uint256'}, {'name': '_tokenName', 'type': 'string'}, {'name': '_decimalUnits', 'type': 'uint8'}, {'name': '_tokenSymbol', 'type': 'string'}], 'payable': false, 'stateMutability': 'nonpayable', 'type': 'constructor'}, {'payable': false, 'stateMutability': 'nonpayable', 'type': 'fallback'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': '_from', 'type': 'address'}, {'indexed': true, 'name': '_to', 'type': 'address'}, {'indexed': false, 'name': '_value', 'type': 'uint256'}], 'name': 'Transfer', 'type': 'event'}, {'anonymous': false, 'inputs': [{'indexed': true, 'name': '_owner', 'type': 'address'}, {'indexed': true, 'name': '_spender', 'type': 'address'}, {'indexed': false, 'name': '_value', 'type': 'uint256'}], 'name': 'Approval', 'type': 'event'}]) + return humanstandardtokenContract.new( + _initialAmount, + _tokenName, + _decimalUnits, + _tokenSymbol, + { + from: web3.eth.accounts[0], + data: '0x60806040526040805190810160405280600481526020017f48302e3100000000000000000000000000000000000000000000000000000000815250600690805190602001906200005192919062000143565b503480156200005f57600080fd5b50604051620011f3380380620011f383398101806040528101908080519060200190929190805182019291906020018051906020019092919080518201929190505050836000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508360028190555082600390805190602001906200010492919062000143565b5081600460006101000a81548160ff021916908360ff16021790555080600590805190602001906200013892919062000143565b5050505050620001f2565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200018657805160ff1916838001178555620001b7565b82800160010185558215620001b7579182015b82811115620001b657825182559160200191906001019062000199565b5b509050620001c69190620001ca565b5090565b620001ef91905b80821115620001eb576000816000905550600101620001d1565b5090565b90565b610ff180620002026000396000f3006080604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100c1578063095ea7b31461015157806318160ddd146101b657806323b872dd146101e1578063313ce5671461026657806354fd4d501461029757806370a082311461032757806395d89b411461037e578063a9059cbb1461040e578063cae9ca5114610473578063dd62ed3e1461051e575b3480156100bb57600080fd5b50600080fd5b3480156100cd57600080fd5b506100d6610595565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101165780820151818401526020810190506100fb565b50505050905090810190601f1680156101435780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015d57600080fd5b5061019c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610633565b604051808215151515815260200191505060405180910390f35b3480156101c257600080fd5b506101cb610725565b6040518082815260200191505060405180910390f35b3480156101ed57600080fd5b5061024c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061072b565b604051808215151515815260200191505060405180910390f35b34801561027257600080fd5b5061027b6109a4565b604051808260ff1660ff16815260200191505060405180910390f35b3480156102a357600080fd5b506102ac6109b7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102ec5780820151818401526020810190506102d1565b50505050905090810190601f1680156103195780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561033357600080fd5b50610368600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610a55565b6040518082815260200191505060405180910390f35b34801561038a57600080fd5b50610393610a9d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103d35780820151818401526020810190506103b8565b50505050905090810190601f1680156104005780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561041a57600080fd5b50610459600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b3b565b604051808215151515815260200191505060405180910390f35b34801561047f57600080fd5b50610504600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610ca1565b604051808215151515815260200191505060405180910390f35b34801561052a57600080fd5b5061057f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610f3e565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561062b5780601f106106005761010080835404028352916020019161062b565b820191906000526020600020905b81548152906001019060200180831161060e57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60025481565b6000816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101580156107f7575081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b80156108035750600082115b1561099857816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905061099d565b600090505b9392505050565b600460009054906101000a900460ff1681565b60068054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a4d5780601f10610a2257610100808354040283529160200191610a4d565b820191906000526020600020905b815481529060010190602001808311610a3057829003601f168201915b505050505081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b335780601f10610b0857610100808354040283529160200191610b33565b820191906000526020600020905b815481529060010190602001808311610b1657829003601f168201915b505050505081565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610b8b5750600082115b15610c9657816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610c9b565b600090505b92915050565b600082600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040518082815260200191505060405180910390a38373ffffffffffffffffffffffffffffffffffffffff1660405180807f72656365697665417070726f76616c28616464726573732c75696e743235362c81526020017f616464726573732c627974657329000000000000000000000000000000000000815250602e01905060405180910390207c01000000000000000000000000000000000000000000000000000000009004338530866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828051906020019080838360005b83811015610ee2578082015181840152602081019050610ec7565b50505050905090810190601f168015610f0f5780820380516001836020036101000a031916815260200191505b509450505050506000604051808303816000875af1925050501515610f3357600080fd5b600190509392505050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050929150505600a165627a7a723058200052919e0bc22b5adcd3d320be977df3a1dcc35d1a0160287383ba371900a1c50029', + gas: '4700000', + gasPrice: '20000000000', + }, function (e, contract) { + console.log(e, contract) + if (typeof contract.address !== 'undefined') { + console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash) + + document.getElementById('tokenAddress').innerHTML = contract.address - withdrawButton.addEventListener('click', function (event) { - contract.withdraw('0xde0b6b3a7640000', { from: web3.eth.accounts[0] }, function (result) { - console.log(result) - }) + transferTokens.addEventListener('click', function (event) { + console.log(`event`, event) + contract.transfer('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '7', { + from: web3.eth.accounts[0], + to: contract.address, + data: '0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a', + gas: 60000, + gasPrice: '20000000000', + }, function (result) { + console.log('result', result) }) - } - }) + }) - console.log(piggybank) + approveTokens.addEventListener('click', function (event) { + contract.approve('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '7', { + from: web3.eth.accounts[0], + to: contract.address, + data: '0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005', + gas: 60000, + gasPrice: '20000000000', + }, function (result) { + console.log(result) + }) + }) + } + }) }) + diff --git a/test/e2e/beta/contract-test/index.html b/test/e2e/beta/contract-test/index.html index 0868633f7..0d63fd940 100644 --- a/test/e2e/beta/contract-test/index.html +++ b/test/e2e/beta/contract-test/index.html @@ -1,8 +1,33 @@ + + E2E Test Dapp + - - - - +
+
Contract
+
+ + + +
+
+
+
Send eth
+
+ +
+
+
+
Send tokens
+
+
+ + + +
+
+ + + \ No newline at end of file diff --git a/test/e2e/beta/helpers.js b/test/e2e/beta/helpers.js index fcc3e96d6..e7299184e 100644 --- a/test/e2e/beta/helpers.js +++ b/test/e2e/beta/helpers.js @@ -6,11 +6,14 @@ const { delay } = require('../func') module.exports = { checkBrowserForConsoleErrors, - loadExtension, - verboseReportOnFailure, + closeAllWindowHandlesExcept, findElement, findElements, + loadExtension, openNewPage, + switchToWindowWithTitle, + verboseReportOnFailure, + waitUntilXWindowHandles, } async function loadExtension (driver, extensionId) { @@ -72,9 +75,46 @@ async function openNewPage (driver, url) { await delay(1000) const handles = await driver.getAllWindowHandles() - const secondHandle = handles[1] - await driver.switchTo().window(secondHandle) + const lastHandle = handles[handles.length - 1] + await driver.switchTo().window(lastHandle) await driver.get(url) await delay(1000) } + +async function waitUntilXWindowHandles (driver, x) { + const windowHandles = await driver.getAllWindowHandles() + if (windowHandles.length === x) return + await delay(1000) + return await waitUntilXWindowHandles(driver, x) +} + +async function switchToWindowWithTitle (driver, title, windowHandles) { + if (!windowHandles) { + windowHandles = await driver.getAllWindowHandles() + } else if (windowHandles.length === 0) { + throw new Error('No window with title: ' + title) + } + const firstHandle = windowHandles[0] + await driver.switchTo().window(firstHandle) + const handleTitle = await driver.getTitle() + + if (handleTitle === title) { + return firstHandle + } else { + return await switchToWindowWithTitle(driver, title, windowHandles.slice(1)) + } +} + +async function closeAllWindowHandlesExcept (driver, exceptions, windowHandles) { + exceptions = typeof exceptions === 'string' ? [ exceptions ] : exceptions + windowHandles = windowHandles || await driver.getAllWindowHandles() + const lastWindowHandle = windowHandles.pop() + if (!exceptions.includes(lastWindowHandle)) { + await driver.switchTo().window(lastWindowHandle) + await delay(1000) + await driver.close() + await delay(1000) + } + return windowHandles.length && await closeAllWindowHandlesExcept(driver, exceptions, windowHandles) +} diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index b07b1ecd7..69bcf8901 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -11,12 +11,15 @@ const { getExtensionIdFirefox, } = require('../func') const { + checkBrowserForConsoleErrors, + closeAllWindowHandlesExcept, findElement, findElements, - checkBrowserForConsoleErrors, loadExtension, - verboseReportOnFailure, openNewPage, + switchToWindowWithTitle, + verboseReportOnFailure, + waitUntilXWindowHandles, } = require('./helpers') describe('MetaMask', function () { @@ -25,7 +28,7 @@ describe('MetaMask', function () { let tokenAddress const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent' - const tinyDelayMs = 1000 + const tinyDelayMs = 200 const regularDelayMs = tinyDelayMs * 2 const largeDelayMs = regularDelayMs * 2 @@ -94,6 +97,11 @@ describe('MetaMask', function () { }) it('selects the new UI option', async () => { + try { + const overlay = await findElement(driver, By.css('.full-flex-height')) + await driver.wait(until.stalenessOf(overlay)) + } catch (e) {} + const button = await findElement(driver, By.xpath("//p[contains(text(), 'Try Beta Version')]")) await button.click() await delay(regularDelayMs) @@ -324,10 +332,10 @@ describe('MetaMask', function () { const create = await findElement(driver, By.xpath(`//button[contains(text(), 'Create')]`)) await create.click() - await delay(regularDelayMs) + await delay(largeDelayMs) }) - it('should correct account name', async () => { + it('should display correct account name', async () => { const accountName = await findElement(driver, By.css('.account-name')) assert.equal(await accountName.getText(), '2nd account') await delay(regularDelayMs) @@ -366,8 +374,7 @@ describe('MetaMask', function () { it('balance renders', async () => { const balance = await findElement(driver, By.css('.balance-display .token-amount')) - const tokenAmount = await balance.getText() - assert.equal(tokenAmount, '100.000 ETH') + await driver.wait(until.elementTextMatches(balance, /100.+ETH/)) await delay(regularDelayMs) }) }) @@ -404,59 +411,69 @@ describe('MetaMask', function () { it('confirms the transaction', async function () { const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`)) await confirmButton.click() - await delay(regularDelayMs) + await delay(largeDelayMs) }) 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 findElement(driver, By.css('.tx-list-value')) - await driver.wait(until.elementTextMatches(txValues, /1\sETH/), 10000) + if (process.env.SELENIUM_BROWSER !== 'firefox') { + 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 openNewPage(driver, 'https://faucet.metamask.io') + describe('Send ETH from dapp', () => { + it('starts a send transaction inside the dapp', async () => { + await openNewPage(driver, 'http://127.0.0.1:8080/') + await delay(regularDelayMs) - const [extension, faucet] = await driver.getAllWindowHandles() - await driver.switchTo().window(faucet) + await waitUntilXWindowHandles(driver, 2) + let windowHandles = await driver.getAllWindowHandles() + const extension = windowHandles[0] + const dapp = windowHandles[1] - const faucetPageTitle = await findElement(driver, By.css('.container-fluid')) - await driver.wait(until.elementTextMatches(faucetPageTitle, /MetaMask/)) + await driver.switchTo().window(dapp) await delay(regularDelayMs) - const send1eth = await findElement(driver, By.xpath(`//button[contains(text(), '10 ether')]`), 14000) - await send1eth.click() + const send3eth = await findElement(driver, By.xpath(`//button[contains(text(), 'Send')]`), 10000) + await send3eth.click() await delay(regularDelayMs) - await driver.switchTo().window(extension) - await loadExtension(driver, extensionId) + windowHandles = await driver.getAllWindowHandles() + await driver.switchTo().window(windowHandles[2]) await delay(regularDelayMs) - const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`), 14000) + const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`), 10000) await confirmButton.click() await delay(regularDelayMs) - await driver.switchTo().window(faucet) - await delay(regularDelayMs) - await driver.close() - await delay(regularDelayMs) + await closeAllWindowHandlesExcept(driver, [extension, dapp]) await driver.switchTo().window(extension) await delay(regularDelayMs) - await loadExtension(driver, extensionId) - 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 findElement(driver, By.css('.tx-list-value')) + await driver.wait(until.elementTextMatches(txValues, /3\sETH/), 10000) }) }) describe('Deploy contract and call contract methods', () => { let extension - let contractTestPage + let dapp it('confirms a deploy contract transaction', async () => { - await openNewPage(driver, 'http://127.0.0.1:8080/'); + const windowHandles = await driver.getAllWindowHandles() + extension = windowHandles[0] + dapp = windowHandles[1] + await delay(tinyDelayMs) - [extension, contractTestPage] = await driver.getAllWindowHandles() + await driver.switchTo().window(dapp) await delay(regularDelayMs) const deployContractButton = await findElement(driver, By.css('#deployButton')) @@ -466,7 +483,7 @@ describe('MetaMask', function () { await driver.switchTo().window(extension) await delay(regularDelayMs) - const txListItem = await findElement(driver, By.css('.tx-list-item')) + const txListItem = await findElement(driver, By.xpath(`//span[contains(text(), 'Contract Deployment')]`)) await txListItem.click() await delay(regularDelayMs) @@ -479,10 +496,11 @@ describe('MetaMask', function () { const txAccounts = await findElements(driver, By.css('.tx-list-account')) assert.equal(await txAccounts[0].getText(), 'Contract Deployment') + await delay(regularDelayMs) }) it('calls and confirms a contract method where ETH is sent', async () => { - await driver.switchTo().window(contractTestPage) + await driver.switchTo().window(dapp) await delay(regularDelayMs) const depositButton = await findElement(driver, By.css('#depositButton')) @@ -492,7 +510,7 @@ describe('MetaMask', function () { await driver.switchTo().window(extension) await delay(regularDelayMs) - const txListItem = await findElement(driver, By.css('.tx-list-item')) + const txListItem = await findElement(driver, By.xpath(`//span[contains(text(), '4 ETH')]`)) await txListItem.click() await delay(regularDelayMs) @@ -524,7 +542,7 @@ describe('MetaMask', function () { 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) + await driver.wait(until.elementTextMatches(txValues, /4\sETH/), 10000) const txAccounts = await findElements(driver, By.css('.tx-list-account')) const firstTxAddress = await txAccounts[0].getText() @@ -532,7 +550,7 @@ describe('MetaMask', function () { }) it('calls and confirms a contract method where ETH is received', async () => { - await driver.switchTo().window(contractTestPage) + await driver.switchTo().window(dapp) await delay(regularDelayMs) const withdrawButton = await findElement(driver, By.css('#withdrawButton')) @@ -556,38 +574,31 @@ describe('MetaMask', function () { 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 closeAllWindowHandlesExcept(driver, [extension, dapp]) 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, /^86.*ETH.*$/), 10000) - const tokenAmount = await balance.getText() - assert.ok(/^86.*ETH.*$/.test(tokenAmount)) await delay(regularDelayMs) + if (process.env.SELENIUM_BROWSER !== 'firefox') { + await driver.wait(until.elementTextMatches(balance, /^92.*ETH.*$/), 10000) + const tokenAmount = await balance.getText() + assert.ok(/^92.*ETH.*$/.test(tokenAmount)) + await delay(regularDelayMs) + } }) }) - describe('Add a custom token from TokenFactory', () => { + describe('Add a custom token from a dapp', () => { it('creates a new token', async () => { - openNewPage(driver, 'https://tokenfactory.surge.sh/#/factory') + const windowHandles = await driver.getAllWindowHandles() + const extension = windowHandles[0] + const dapp = windowHandles[1] + await delay(regularDelayMs * 2) - await delay(regularDelayMs * 10) - const [extension, tokenFactory] = await driver.getAllWindowHandles() - - 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') + await driver.switchTo().window(dapp) + await delay(regularDelayMs) const createToken = await findElement(driver, By.xpath(`//button[contains(text(), 'Create Token')]`)) await createToken.click() @@ -601,15 +612,16 @@ describe('MetaMask', function () { await confirmButton.click() await delay(regularDelayMs) - await driver.switchTo().window(tokenFactory) - await delay(regularDelayMs) + await driver.switchTo().window(dapp) + await delay(tinyDelayMs) - const tokenContactAddress = await driver.findElement(By.css('div > div > div:nth-child(2) > span:nth-child(3)')) - tokenAddress = await tokenContactAddress.getText() + const tokenContractAddress = await driver.findElement(By.css('#tokenAddress')) + await driver.wait(until.elementTextMatches(tokenContractAddress, /0x/)) + tokenAddress = await tokenContractAddress.getText() - await driver.close() - await driver.switchTo().window(extension) - await loadExtension(driver, extensionId) + await delay(regularDelayMs) + await closeAllWindowHandlesExcept(driver, [extension, dapp]) + await delay(regularDelayMs) await driver.switchTo().window(extension) await delay(regularDelayMs) @@ -709,32 +721,28 @@ describe('MetaMask', function () { }) }) - describe('Send a custom token from TokenFactory', () => { + describe('Send a custom token from dapp', () => { 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')) + const windowHandles = await driver.getAllWindowHandles() + const extension = windowHandles[0] + const dapp = await switchToWindowWithTitle(driver, 'E2E Test Dapp', windowHandles) + await closeAllWindowHandlesExcept(driver, [extension, dapp]) + await delay(regularDelayMs) - await transferToAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970') - await transferToAmount.sendKeys('26') + await driver.switchTo().window(dapp) + await delay(tinyDelayMs) - const transferAmountButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Transfer Amount')]`)) - await transferAmountButton.click() - await delay(regularDelayMs) + const transferTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Transfer Tokens')]`)) + await transferTokens.click() - const [,, popup] = await driver.getAllWindowHandles() - await driver.switchTo().window(popup) - await driver.close() + await closeAllWindowHandlesExcept(driver, extension) await driver.switchTo().window(extension) await delay(regularDelayMs) const [txListItem] = await findElements(driver, By.css('.tx-list-item')) + const [txListValue] = await findElements(driver, By.css('.tx-list-value')) + await driver.wait(until.elementTextMatches(txListValue, /7\sTST/)) await txListItem.click() await delay(regularDelayMs) @@ -785,7 +793,7 @@ describe('MetaMask', function () { assert.equal(transactions.length, 2) const txValues = await findElements(driver, By.css('.tx-list-value')) - await driver.wait(until.elementTextMatches(txValues[0], /26\sTST/)) + await driver.wait(until.elementTextMatches(txValues[0], /7\sTST/)) const txStatuses = await findElements(driver, By.css('.tx-list-status')) await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed/)) @@ -799,7 +807,7 @@ describe('MetaMask', function () { // 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') + assert.equal(await tokenBalanceAmount.getText(), '43') } }) }) -- cgit v1.2.3 From 228b8072218a27fe45867018152392ffb2012251 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 9 Jul 2018 13:38:05 -0230 Subject: Fix existing e2e tests --- test/e2e/beta/metamask-beta-ui.spec.js | 37 ++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'test') diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index 69bcf8901..61738af00 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -196,8 +196,20 @@ describe('MetaMask', function () { await delay(regularDelayMs) }) - async function retypeSeedPhrase (words) { + async function retypeSeedPhrase (words, wasReloaded) { try { + if (wasReloaded) { + 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) + + const nextScreen = await findElement(driver, By.css('.backup-phrase button')) + await nextScreen.click() + await delay(regularDelayMs) + } + const word0 = await findElement(driver, By.xpath(`//button[contains(text(), '${words[0]}')]`), 10000) await word0.click() @@ -258,7 +270,7 @@ describe('MetaMask', function () { await delay(tinyDelayMs) } catch (e) { await loadExtension(driver, extensionId) - await retypeSeedPhrase(words) + await retypeSeedPhrase(words, true) } } @@ -311,7 +323,7 @@ describe('MetaMask', function () { it('accepts the account password after lock', async () => { await driver.findElement(By.id('password')).sendKeys('correct horse battery staple') await driver.findElement(By.id('password')).sendKeys(Key.ENTER) - await delay(regularDelayMs * 4) + await delay(largeDelayMs * 4) }) }) @@ -390,6 +402,9 @@ describe('MetaMask', function () { await inputAddress.sendKeys('0x2f318C334780961FB129D2a6c30D0763d9a5C970') await inputAmount.sendKeys('1') + const inputValue = await inputAmount.getAttribute('value') + assert.equal(inputValue, '1') + // Set the gas limit const configureGas = await findElement(driver, By.css('.send-v2__gas-fee-display button')) await configureGas.click() @@ -515,12 +530,12 @@ describe('MetaMask', function () { await delay(regularDelayMs) // Set the gas limit - const configureGas = await findElement(driver, By.css('.sliders-icon-container')) + const configureGas = await findElement(driver, By.css('.confirm-detail-row__header-text--edit')) 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'))) + await driver.wait(until.elementLocated(By.css('.customize-gas__title'))) const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.customize-gas-input')) await gasPriceInput.clear() @@ -680,7 +695,7 @@ describe('MetaMask', function () { gasModal = await driver.findElement(By.css('span .modal')) }) - it('customizes gas', async () => { + it('opens customizes gas modal', 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() @@ -747,7 +762,7 @@ describe('MetaMask', function () { await delay(regularDelayMs) // Set the gas limit - const configureGas = await driver.wait(until.elementLocated(By.css('.send-v2__gas-fee-display button'))) + const configureGas = await driver.wait(until.elementLocated(By.css('.confirm-detail-row__header-text--edit'))) await configureGas.click() await delay(regularDelayMs) @@ -755,7 +770,7 @@ describe('MetaMask', function () { }) it('customizes gas', async () => { - await driver.wait(until.elementLocated(By.css('.send-v2__customize-gas__title'))) + await driver.wait(until.elementLocated(By.css('.customize-gas__title'))) const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.customize-gas-input')) await gasPriceInput.clear() @@ -774,12 +789,12 @@ describe('MetaMask', function () { await gasLimitInput.sendKeys(Key.BACK_SPACE) } - const save = await findElement(driver, By.css('.send-v2__customize-gas__save')) + const save = await findElement(driver, By.css('.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) + const gasFeeInputs = await findElements(driver, By.css('.confirm-detail-row__eth')) + assert.equal(await gasFeeInputs[0].getText(), '♦ 0.0006') }) it('submits the transaction', async function () { -- cgit v1.2.3 From b30499886f5f738aeb93df2571cf07e2b9897ae1 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 10 Jul 2018 15:35:27 -0700 Subject: test - check that #setTxStatusRejected removes transaction from history --- test/unit/app/controllers/transactions/tx-state-manager-test.js | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test') diff --git a/test/unit/app/controllers/transactions/tx-state-manager-test.js b/test/unit/app/controllers/transactions/tx-state-manager-test.js index 089b7a8a6..88bdaa60e 100644 --- a/test/unit/app/controllers/transactions/tx-state-manager-test.js +++ b/test/unit/app/controllers/transactions/tx-state-manager-test.js @@ -43,6 +43,15 @@ describe('TransactionStateManager', function () { }) describe('#setTxStatusRejected', function () { + it('sets the tx status to rejected and removes it from history', function () { + const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } + txStateManager.addTx(tx) + txStateManager.setTxStatusRejected(1) + const result = txStateManager.getTxList() + assert.ok(Array.isArray(result)) + assert.equal(result.length, 0) + }) + it('should emit a rejected event to signal the exciton of callback', (done) => { const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } txStateManager.addTx(tx) -- cgit v1.2.3 From f81676fda141c4ea37b76c7adb545d4a7c0588e2 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 10 Jul 2018 13:13:17 -0230 Subject: Update e2e beta tests to cover confirm refactor changes. --- test/e2e/beta/helpers.js | 13 +++ test/e2e/beta/metamask-beta-ui.spec.js | 144 ++++++++++++++++++++++++++++++++- test/e2e/metamask.spec.js | 2 +- 3 files changed, 155 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/e2e/beta/helpers.js b/test/e2e/beta/helpers.js index e7299184e..828f87db7 100644 --- a/test/e2e/beta/helpers.js +++ b/test/e2e/beta/helpers.js @@ -1,10 +1,12 @@ const fs = require('fs') const mkdirp = require('mkdirp') const pify = require('pify') +const assert = require('assert') const {until} = require('selenium-webdriver') const { delay } = require('../func') module.exports = { + assertElementNotPresent, checkBrowserForConsoleErrors, closeAllWindowHandlesExcept, findElement, @@ -118,3 +120,14 @@ async function closeAllWindowHandlesExcept (driver, exceptions, windowHandles) { } return windowHandles.length && await closeAllWindowHandlesExcept(driver, exceptions, windowHandles) } + +async function assertElementNotPresent (webdriver, driver, by) { + try { + const dataTab = await findElement(driver, by, 4000) + if (dataTab) { + assert(false, 'Data tab should not be present') + } + } catch (err) { + assert(err instanceof webdriver.error.NoSuchElementError) + } +} diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index 61738af00..c4db925c4 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -11,6 +11,7 @@ const { getExtensionIdFirefox, } = require('../func') const { + assertElementNotPresent, checkBrowserForConsoleErrors, closeAllWindowHandlesExcept, findElement, @@ -461,6 +462,8 @@ describe('MetaMask', function () { await driver.switchTo().window(windowHandles[2]) await delay(regularDelayMs) + assertElementNotPresent(webdriver, driver, By.xpath(`//li[contains(text(), 'Data')]`)) + const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`), 10000) await confirmButton.click() await delay(regularDelayMs) @@ -482,7 +485,7 @@ describe('MetaMask', function () { describe('Deploy contract and call contract methods', () => { let extension let dapp - it('confirms a deploy contract transaction', async () => { + it('creates a deploy contract transaction', async () => { const windowHandles = await driver.getAllWindowHandles() extension = windowHandles[0] dapp = windowHandles[1] @@ -501,7 +504,25 @@ describe('MetaMask', function () { const txListItem = await findElement(driver, By.xpath(`//span[contains(text(), 'Contract Deployment')]`)) await txListItem.click() await delay(regularDelayMs) + }) + + it('displays the contract creation data', async () => { + const dataTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Data')]`)) + dataTab.click() + await (regularDelayMs) + + await findElement(driver, By.xpath(`//div[contains(text(), '127.0.0.1')]`)) + + const confirmDataDiv = await findElement(driver, By.css('.confirm-page-container-content__data-box')) + const confirmDataText = await confirmDataDiv.getText() + assert.equal(confirmDataText.match(/0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff/)) + const detailsTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Details')]`)) + detailsTab.click() + await (regularDelayMs) + }) + + it('confirms a deploy contract transaction', async () => { const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`)) await confirmButton.click() await delay(regularDelayMs) @@ -711,6 +732,24 @@ describe('MetaMask', function () { await delay(regularDelayMs) }) + it('displays the token transfer data', async () => { + const dataTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Data')]`)) + dataTab.click() + await (regularDelayMs) + + const functionType = await findElement(driver, By.css('.confirm-page-container-content__function-type')) + const functionTypeText = await functionType.getText() + assert.equal(functionTypeText, 'Transfer') + + const confirmDataDiv = await findElement(driver, By.css('.confirm-page-container-content__data-box')) + const confirmDataText = await confirmDataDiv.getText() + assert.equal(confirmDataText.match(/0xa9059cbb0000000000000000000000002f318c334780961fb129d2a6c30d0763d9a5c97/)) + + const detailsTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Details')]`)) + detailsTab.click() + await (regularDelayMs) + }) + it('submits the transaction', async function () { const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`)) await confirmButton.click() @@ -751,9 +790,9 @@ describe('MetaMask', function () { const transferTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Transfer Tokens')]`)) await transferTokens.click() - await closeAllWindowHandlesExcept(driver, extension) + await closeAllWindowHandlesExcept(driver, [extension, dapp]) await driver.switchTo().window(extension) - await delay(regularDelayMs) + await delay(largeDelayMs) const [txListItem] = await findElements(driver, By.css('.tx-list-item')) const [txListValue] = await findElements(driver, By.css('.tx-list-value')) @@ -827,6 +866,105 @@ describe('MetaMask', function () { }) }) + describe('Approves a custom token from dapp', () => { + let gasModal + it('approves an already created token', async () => { + const windowHandles = await driver.getAllWindowHandles() + const extension = windowHandles[0] + const dapp = await switchToWindowWithTitle(driver, 'E2E Test Dapp', windowHandles) + await closeAllWindowHandlesExcept(driver, [extension, dapp]) + await delay(regularDelayMs) + + await driver.switchTo().window(dapp) + await delay(tinyDelayMs) + + const transferTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Approve Tokens')]`)) + await transferTokens.click() + + await closeAllWindowHandlesExcept(driver, extension) + await driver.switchTo().window(extension) + await delay(regularDelayMs) + + const [txListItem] = await findElements(driver, By.css('.tx-list-item')) + const [txListValue] = await findElements(driver, By.css('.tx-list-value')) + await driver.wait(until.elementTextMatches(txListValue, /0\sETH/)) + await txListItem.click() + await delay(regularDelayMs) + }) + + it('displays the token approval data', async () => { + const dataTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Data')]`)) + dataTab.click() + await (regularDelayMs) + + const functionType = await findElement(driver, By.css('.confirm-page-container-content__function-type')) + const functionTypeText = await functionType.getText() + assert.equal(functionTypeText, 'Approve') + + const confirmDataDiv = await findElement(driver, By.css('.confirm-page-container-content__data-box')) + const confirmDataText = await confirmDataDiv.getText() + assert.equal(confirmDataText.match(/0x095ea7b30000000000000000000000002f318c334780961fb129d2a6c30d0763d9a5c97/)) + + const detailsTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Details')]`)) + detailsTab.click() + await (regularDelayMs) + + const approvalWarning = await findElement(driver, By.css('.confirm-page-container-warning__warning')) + const approvalWarningText = await approvalWarning.getText() + assert(approvalWarningText.match(/By approving this/)) + await (regularDelayMs) + }) + + it('opens the gas edit modal', async () => { + const configureGas = await driver.wait(until.elementLocated(By.css('.confirm-detail-row__header-text--edit'))) + 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('.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('.customize-gas__save')) + await save.click() + await driver.wait(until.stalenessOf(gasModal)) + + const gasFeeInputs = await findElements(driver, By.css('.confirm-detail-row__eth')) + assert.equal(await gasFeeInputs[0].getText(), '♦ 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 txValues = await findElements(driver, By.css('.tx-list-value')) + await driver.wait(until.elementTextMatches(txValues[0], /0\sETH/)) + const txStatuses = await findElements(driver, By.css('.tx-list-status')) + await driver.wait(until.elementTextMatches(txStatuses[0], /Confirmed/)) + }) + }) + describe('Hide token', () => { it('hides the token when clicked', async () => { const [hideTokenEllipsis] = await findElements(driver, By.css('.token-list-item__ellipsis')) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index a32b924b8..b6efae5b3 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -234,7 +234,7 @@ describe('Metamask popup page', function () { submitButton.click() - await delay(500) + await delay(1500) }) it('finds the transaction in the transactions list', async function () { -- cgit v1.2.3 From a7a66171c235a2c4f318d329b0d57ff5b87c83b8 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 10 Jul 2018 21:39:22 -0230 Subject: Fix signature request tests for compatability with confirm refactor. --- test/integration/lib/confirm-sig-requests.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/test/integration/lib/confirm-sig-requests.js b/test/integration/lib/confirm-sig-requests.js index 5613c0dcb..017f059b8 100644 --- a/test/integration/lib/confirm-sig-requests.js +++ b/test/integration/lib/confirm-sig-requests.js @@ -1,5 +1,6 @@ const reactTriggerChange = require('react-trigger-change') const { + timeout, queryAsync, } = require('../../lib/util') @@ -18,14 +19,14 @@ async function runConfirmSigRequestsTest (assert, done) { selectState.val('confirm sig requests') reactTriggerChange(selectState[0]) - // await timeout(1000000) - const pendingRequestItem = $.find('.tx-list-item.tx-list-pending-item-container.tx-list-clickable') if (pendingRequestItem[0]) { pendingRequestItem[0].click() } + await timeout(1000) + let confirmSigHeadline = await queryAsync($, '.request-signature__headline') assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested') @@ -37,7 +38,7 @@ async function runConfirmSigRequestsTest (assert, done) { let confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large') confirmSigSignButton[0].click() - + await timeout(1000) confirmSigHeadline = await queryAsync($, '.request-signature__headline') assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested') @@ -46,7 +47,7 @@ async function runConfirmSigRequestsTest (assert, done) { confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large') confirmSigSignButton[0].click() - + await timeout(1000) confirmSigHeadline = await queryAsync($, '.request-signature__headline') assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested') @@ -56,7 +57,4 @@ async function runConfirmSigRequestsTest (assert, done) { confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large') confirmSigSignButton[0].click() - - const txView = await queryAsync($, '.tx-view') - assert.ok(txView[0], 'Should return to the account details screen after confirming') } -- cgit v1.2.3 From 91eca558f0f82e096251bebdc34136c864e224fe Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 11 Jul 2018 08:25:52 -0230 Subject: Fix send integration tests for compatability with confirm refactor. --- test/integration/lib/send-new-ui.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'test') diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js index d5e80151c..406863ca6 100644 --- a/test/integration/lib/send-new-ui.js +++ b/test/integration/lib/send-new-ui.js @@ -125,18 +125,18 @@ async function runSendFlowTest (assert, done) { reactTriggerChange(selectState[0]) const confirmFromName = (await queryAsync($, '.sender-to-recipient__sender-name')).first() - assert.equal(confirmFromName[0].textContent, 'Send Account 2', 'confirm screen should show correct from name') + assert.equal(confirmFromName[0].textContent, 'Send Account 4', 'confirm screen should show correct from name') const confirmToName = (await queryAsync($, '.sender-to-recipient__recipient-name')).last() assert.equal(confirmToName[0].textContent, 'Send Account 3', 'confirm screen should show correct to name') - const confirmScreenRows = await queryAsync($, '.confirm-screen-rows') - const confirmScreenGas = confirmScreenRows.find('.currency-display__converted-value')[0] - assert.equal(confirmScreenGas.textContent, '$3.60 USD', 'confirm screen should show correct gas') - const confirmScreenTotal = confirmScreenRows.find('.confirm-screen-row-info')[2] - assert.equal(confirmScreenTotal.textContent, '$2,405.36 USD', 'confirm screen should show correct total') + const confirmScreenRowFiats = await queryAsync($, '.confirm-detail-row__fiat') + const confirmScreenGas = confirmScreenRowFiats[0] + assert.equal(confirmScreenGas.textContent, '$3.60', 'confirm screen should show correct gas') + const confirmScreenTotal = confirmScreenRowFiats[1] + assert.equal(confirmScreenTotal.textContent, '$2,405.36', 'confirm screen should show correct total') - const confirmScreenBackButton = await queryAsync($, '.page-container__back-button') + const confirmScreenBackButton = await queryAsync($, '.confirm-page-container-header__back-button') confirmScreenBackButton[0].click() const sendFromFieldItemInEdit = await queryAsync($, '.account-list-item') -- cgit v1.2.3 From e91d87efd91bce3d893a20832a2d2361cbd256ee Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 11 Jul 2018 13:37:26 -0230 Subject: Fix bug in test mock signature request methods. --- test/integration/lib/confirm-sig-requests.js | 2 ++ test/integration/lib/currency-localization.js | 1 + 2 files changed, 3 insertions(+) (limited to 'test') diff --git a/test/integration/lib/confirm-sig-requests.js b/test/integration/lib/confirm-sig-requests.js index 017f059b8..dcc25c493 100644 --- a/test/integration/lib/confirm-sig-requests.js +++ b/test/integration/lib/confirm-sig-requests.js @@ -57,4 +57,6 @@ async function runConfirmSigRequestsTest (assert, done) { confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large') confirmSigSignButton[0].click() + + await timeout(2000) } diff --git a/test/integration/lib/currency-localization.js b/test/integration/lib/currency-localization.js index 3ad1a23e5..d42b7495d 100644 --- a/test/integration/lib/currency-localization.js +++ b/test/integration/lib/currency-localization.js @@ -19,6 +19,7 @@ async function runCurrencyLocalizationTest (assert, done) { console.log('*** start runCurrencyLocalizationTest') const selectState = await queryAsync($, 'select') selectState.val('currency localization') + await timeout(1000) reactTriggerChange(selectState[0]) await timeout(1000) const txView = await queryAsync($, '.tx-view') -- cgit v1.2.3 From 8912955765e41c7d57ac6252e003ab10f5db6b7e Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 11 Jul 2018 14:51:58 -0230 Subject: Wait for submitted tx list item amounts to match the expected before clicking through. (e2e beta tests) --- test/e2e/beta/metamask-beta-ui.spec.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index c4db925c4..fd75bd2f6 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -546,8 +546,9 @@ describe('MetaMask', function () { await driver.switchTo().window(extension) await delay(regularDelayMs) - const txListItem = await findElement(driver, By.xpath(`//span[contains(text(), '4 ETH')]`)) - await txListItem.click() + const [txListValue] = await findElements(driver, By.css('.tx-list-value')) + await driver.wait(until.elementTextMatches(txListValue, /4\sETH/), 10000) + await txListValue.click() await delay(regularDelayMs) // Set the gas limit @@ -796,12 +797,12 @@ describe('MetaMask', function () { const [txListItem] = await findElements(driver, By.css('.tx-list-item')) const [txListValue] = await findElements(driver, By.css('.tx-list-value')) - await driver.wait(until.elementTextMatches(txListValue, /7\sTST/)) - await txListItem.click() + await driver.wait(until.elementTextMatches(txListValue, /7\sTST/), 10000) + await txListValue.click() await delay(regularDelayMs) // Set the gas limit - const configureGas = await driver.wait(until.elementLocated(By.css('.confirm-detail-row__header-text--edit'))) + const configureGas = await driver.wait(until.elementLocated(By.css('.confirm-detail-row__header-text--edit')), 10000) await configureGas.click() await delay(regularDelayMs) -- cgit v1.2.3 From 05ee2b7401cbbcf120eb627d0ad54122c05f85b0 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 11 Jul 2018 15:13:32 -0230 Subject: Reattempt to find network selector; wait for network selector dropdown to contain localhost before attempting to click. (e2e beta tests) --- test/e2e/beta/metamask-beta-ui.spec.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index fd75bd2f6..39199c1e1 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -84,15 +84,19 @@ describe('MetaMask', function () { networkSelector = await findElement(driver, By.css('#network_component')) } catch (e) { await loadExtension(driver, extensionId) + await delay(largeDelayMs * 2) + networkSelector = await findElement(driver, By.css('#network_component')) } await delay(regularDelayMs) }) - it('use the local network', async function () { + it('uses the local network', async function () { await networkSelector.click() await delay(regularDelayMs) - const localhost = await findElement(driver, By.xpath(`//li[contains(text(), 'Localhost')]`)) + const networks = await findElements(driver, By.css('.dropdown-menu-item')) + const localhost = networks[4] + await driver.wait(until.elementTextMatches(localhost, /Localhost/)) await localhost.click() await delay(regularDelayMs) }) @@ -795,7 +799,6 @@ describe('MetaMask', function () { await driver.switchTo().window(extension) await delay(largeDelayMs) - const [txListItem] = await findElements(driver, By.css('.tx-list-item')) const [txListValue] = await findElements(driver, By.css('.tx-list-value')) await driver.wait(until.elementTextMatches(txListValue, /7\sTST/), 10000) await txListValue.click() -- cgit v1.2.3 From 07322bc404692625ceac06722df12ff179f26c6f Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 11 Jul 2018 15:47:17 -0230 Subject: Wait for an element with a .tx-list-pending-item-container to be rendered before attempting to select the tx-list-item. (e2e beta tests) --- test/e2e/beta/metamask-beta-ui.spec.js | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test') diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index 39199c1e1..caa49d450 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -550,6 +550,7 @@ describe('MetaMask', function () { await driver.switchTo().window(extension) await delay(regularDelayMs) + await findElements(driver, By.css('.tx-list-pending-item-container')) const [txListValue] = await findElements(driver, By.css('.tx-list-value')) await driver.wait(until.elementTextMatches(txListValue, /4\sETH/), 10000) await txListValue.click() @@ -799,6 +800,7 @@ describe('MetaMask', function () { await driver.switchTo().window(extension) await delay(largeDelayMs) + await findElements(driver, By.css('.tx-list-pending-item-container')) const [txListValue] = await findElements(driver, By.css('.tx-list-value')) await driver.wait(until.elementTextMatches(txListValue, /7\sTST/), 10000) await txListValue.click() -- cgit v1.2.3 From 910713c6b3c5b8f865fdcb989bfe3ee0b14eb364 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Wed, 11 Jul 2018 15:59:05 -0400 Subject: improve tests --- test/unit/app/controllers/detect-tokens-test.js | 105 +++++++++++------------- 1 file changed, 49 insertions(+), 56 deletions(-) (limited to 'test') diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js index 82e86bfcc..dca48c6bb 100644 --- a/test/unit/app/controllers/detect-tokens-test.js +++ b/test/unit/app/controllers/detect-tokens-test.js @@ -5,6 +5,14 @@ const PreferencesController = require('../../../../app/scripts/controllers/prefe const ObservableStore = require('obs-store') describe('DetectTokensController', () => { + const sandbox = sinon.createSandbox() + let clock + before(async () => { + }) + after(() => { + sandbox.restore() + }) + it('should poll on correct interval', async () => { const stub = sinon.stub(global, 'setInterval') new DetectTokensController({ interval: 1337 }) // eslint-disable-line no-new @@ -12,82 +20,67 @@ describe('DetectTokensController', () => { stub.restore() }) + it('should be called on every polling period', async () => { + clock = sandbox.useFakeTimers() + const network = new ObservableStore({provider: {type: 'mainnet'}}) + const preferences = new PreferencesController() + const controller = new DetectTokensController({preferences: preferences, network: network}) + controller.isActive = true + + var stub = sandbox.stub(controller, 'exploreNewTokens') + + clock.tick(1) + sandbox.assert.notCalled(stub) + clock.tick(180000) + sandbox.assert.called(stub) + clock.tick(180000) + sandbox.assert.calledTwice(stub) + clock.tick(180000) + sandbox.assert.calledThrice(stub) + }) + it('should not check tokens while in test network', async () => { var network = new ObservableStore({provider: {type: 'rinkeby'}}) const preferences = new PreferencesController() const controller = new DetectTokensController({preferences: preferences, network: network}) controller.isActive = true - controller.contracts = { - '0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4': { - 'name': 'JET8 Token', - 'logo': 'J8T.svg', - 'erc20': true, - 'symbol': 'J8T', - 'decimals': 8, - }, - '0xBC86727E770de68B1060C91f6BB6945c73e10388': { - 'name': 'Ink Protocol', - 'logo': 'ink_protocol.svg', - 'erc20': true, - 'symbol': 'XNK', - 'decimals': 18, - }, - } - controller.fetchContractAccountBalance = address => address + + var stub = sandbox.stub(controller, 'detectTokenBalance') + .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4').returns(true) + .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388').returns(true) + await controller.exploreNewTokens() - assert.deepEqual(preferences.store.getState().tokens, []) -}) + sandbox.assert.notCalled(stub) + }) it('should only check and add tokens while in main network', async () => { const network = new ObservableStore({provider: {type: 'mainnet'}}) const preferences = new PreferencesController() const controller = new DetectTokensController({preferences: preferences, network: network}) controller.isActive = true - controller.contracts = { - '0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4': { - 'name': 'JET8 Token', - 'logo': 'J8T.svg', - 'erc20': true, - 'symbol': 'J8T', - 'decimals': 8, - }, - '0xBC86727E770de68B1060C91f6BB6945c73e10388': { - 'name': 'Ink Protocol', - 'logo': 'ink_protocol.svg', - 'erc20': true, - 'symbol': 'XNK', - 'decimals': 18, - }, - } - controller.fetchContractAccountBalance = address => address + + sandbox.stub(controller, 'detectTokenBalance') + .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4').returns(true) + .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388').returns(true) + await controller.exploreNewTokens() - assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}]) + assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, + {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}]) }) it('should not detect same token while in main network', async () => { const network = new ObservableStore({provider: {type: 'mainnet'}}) const preferences = new PreferencesController() - preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 8, 'J8T') + preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8) const controller = new DetectTokensController({preferences: preferences, network: network}) controller.isActive = true - controller.contracts = { - '0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4': { - 'name': 'JET8 Token', - 'logo': 'J8T.svg', - 'erc20': true, - 'symbol': 'J8T', - 'decimals': 8, - }, - '0xBC86727E770de68B1060C91f6BB6945c73e10388': { - 'name': 'Ink Protocol', - 'logo': 'ink_protocol.svg', - 'erc20': true, - 'symbol': 'XNK', - 'decimals': 18, - }, - } - controller.fetchContractAccountBalance = address => address + + sandbox.stub(controller, 'detectTokenBalance') + .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4').returns(true) + .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388').returns(true) + await controller.exploreNewTokens() - assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}]) + assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, + {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}]) }) }) -- cgit v1.2.3 From eb2b36b3cb9a74851767a67bb38ba88b9ad74ab5 Mon Sep 17 00:00:00 2001 From: Bobby Dresser Date: Thu, 21 Jun 2018 14:17:00 -0700 Subject: fix tos link; --- test/lib/migrations/002.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/lib/migrations/002.json b/test/lib/migrations/002.json index 9ad3d4cfe..15820ded5 100644 --- a/test/lib/migrations/002.json +++ b/test/lib/migrations/002.json @@ -1 +1 @@ -{"meta":{"version":20},"data":{"config":{},"NetworkController":{"provider":{"type":"mainnet","rpcTarget":"https://mainnet.infura.io/metamask"},"network":"1"},"firstTimeInfo":{"version":"3.12.1","date":1517351427287},"NoticeController":{"noticesList":[{"read":false,"date":"Thu Feb 09 2017","title":"Terms of Use","body":"# Terms of Use #\n\n**THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.**\n\n_Our Terms of Use have been updated as of September 5, 2016_\n\n## 1. Acceptance of Terms ##\n\nMetaMask provides a platform for managing Ethereum (or \"ETH\") accounts, and allowing ordinary websites to interact with the Ethereum blockchain, while keeping the user in control over what transactions they approve, through our website located at[ ](http://metamask.io)[https://metamask.io/](https://metamask.io/) and browser plugin (the \"Site\") — which includes text, images, audio, code and other materials (collectively, the “Content”) and all of the features, and services provided. The Site, and any other features, tools, materials, or other services offered from time to time by MetaMask are referred to here as the “Service.” Please read these Terms of Use (the “Terms” or “Terms of Use”) carefully before using the Service. By using or otherwise accessing the Services, or clicking to accept or agree to these Terms where that option is made available, you (1) accept and agree to these Terms (2) consent to the collection, use, disclosure and other handling of information as described in our Privacy Policy and (3) any additional terms, rules and conditions of participation issued by MetaMask from time to time. If you do not agree to the Terms, then you may not access or use the Content or Services.\n\n## 2. Modification of Terms of Use ##\n\nExcept for Section 13, providing for binding arbitration and waiver of class action rights, MetaMask reserves the right, at its sole discretion, to modify or replace the Terms of Use at any time. The most current version of these Terms will be posted on our Site. You shall be responsible for reviewing and becoming familiar with any such modifications. Use of the Services by you after any modification to the Terms constitutes your acceptance of the Terms of Use as modified.\n\n\n\n## 3. Eligibility ##\n\nYou hereby represent and warrant that you are fully able and competent to enter into the terms, conditions, obligations, affirmations, representations and warranties set forth in these Terms and to abide by and comply with these Terms.\n\nMetaMask is a global platform and by accessing the Content or Services, you are representing and warranting that, you are of the legal age of majority in your jurisdiction as is required to access such Services and Content and enter into arrangements as provided by the Service. You further represent that you are otherwise legally permitted to use the service in your jurisdiction including owning cryptographic tokens of value, and interacting with the Services or Content in any way. You further represent you are responsible for ensuring compliance with the laws of your jurisdiction and acknowledge that MetaMask is not liable for your compliance with such laws.\n\n## 4 Account Password and Security ##\n\nWhen setting up an account within MetaMask, you will be responsible for keeping your own account secrets, which may be a twelve-word seed phrase, an account file, or other locally stored secret information. MetaMask encrypts this information locally with a password you provide, that we never send to our servers. You agree to (a) never use the same password for MetaMask that you have ever used outside of this service; (b) keep your secret information and password confidential and do not share them with anyone else; (c) immediately notify MetaMask of any unauthorized use of your account or breach of security. MetaMask cannot and will not be liable for any loss or damage arising from your failure to comply with this section.\n\n## 5. Representations, Warranties, and Risks ##\n\n### 5.1. Warranty Disclaimer ###\n\nYou expressly understand and agree that your use of the Service is at your sole risk. The Service (including the Service and the Content) are provided on an \"AS IS\" and \"as available\" basis, without warranties of any kind, either express or implied, including, without limitation, implied warranties of merchantability, fitness for a particular purpose or non-infringement. You acknowledge that MetaMask has no control over, and no duty to take any action regarding: which users gain access to or use the Service; what effects the Content may have on you; how you may interpret or use the Content; or what actions you may take as a result of having been exposed to the Content. You release MetaMask from all liability for you having acquired or not acquired Content through the Service. MetaMask makes no representations concerning any Content contained in or accessed through the Service, and MetaMask will not be responsible or liable for the accuracy, copyright compliance, legality or decency of material contained in or accessed through the Service.\n\n### 5.2 Sophistication and Risk of Cryptographic Systems ###\n\nBy utilizing the Service or interacting with the Content or platform in any way, you represent that you understand the inherent risks associated with cryptographic systems; and warrant that you have an understanding of the usage and intricacies of native cryptographic tokens, like Ether (ETH) and Bitcoin (BTC), smart contract based tokens such as those that follow the Ethereum Token Standard (https://github.com/ethereum/EIPs/issues/20), and blockchain-based software systems.\n\n### 5.3 Risk of Regulatory Actions in One or More Jurisdictions ###\n\nMetaMask and ETH could be impacted by one or more regulatory inquiries or regulatory action, which could impede or limit the ability of MetaMask to continue to develop, or which could impede or limit your ability to access or use the Service or Ethereum blockchain.\n\n### 5.4 Risk of Weaknesses or Exploits in the Field of Cryptography ###\n\nYou acknowledge and understand that Cryptography is a progressing field. Advances in code cracking or technical advances such as the development of quantum computers may present risks to cryptocurrencies and Services of Content, which could result in the theft or loss of your cryptographic tokens or property. To the extent possible, MetaMask intends to update the protocol underlying Services to account for any advances in cryptography and to incorporate additional security measures, but does not guarantee or otherwise represent full security of the system. By using the Service or accessing Content, you acknowledge these inherent risks.\n\n### 5.5 Volatility of Crypto Currencies ###\n\nYou understand that Ethereum and other blockchain technologies and associated currencies or tokens are highly volatile due to many factors including but not limited to adoption, speculation, technology and security risks. You also acknowledge that the cost of transacting on such technologies is variable and may increase at any time causing impact to any activities taking place on the Ethereum blockchain. You acknowledge these risks and represent that MetaMask cannot be held liable for such fluctuations or increased costs.\n\n### 5.6 Application Security ###\n\nYou acknowledge that Ethereum applications are code subject to flaws and acknowledge that you are solely responsible for evaluating any code provided by the Services or Content and the trustworthiness of any third-party websites, products, smart-contracts, or Content you access or use through the Service. You further expressly acknowledge and represent that Ethereum applications can be written maliciously or negligently, that MetaMask cannot be held liable for your interaction with such applications and that such applications may cause the loss of property or even identity. This warning and others later provided by MetaMask in no way evidence or represent an on-going duty to alert you to all of the potential risks of utilizing the Service or Content.\n\n## 6. Indemnity ##\n\nYou agree to release and to indemnify, defend and hold harmless MetaMask and its parents, subsidiaries, affiliates and agencies, as well as the officers, directors, employees, shareholders and representatives of any of the foregoing entities, from and against any and all losses, liabilities, expenses, damages, costs (including attorneys’ fees and court costs) claims or actions of any kind whatsoever arising or resulting from your use of the Service, your violation of these Terms of Use, and any of your acts or omissions that implicate publicity rights, defamation or invasion of privacy. MetaMask reserves the right, at its own expense, to assume exclusive defense and control of any matter otherwise subject to indemnification by you and, in such case, you agree to cooperate with MetaMask in the defense of such matter.\n\n## 7. Limitation on liability ##\n\nYOU ACKNOWLEDGE AND AGREE THAT YOU ASSUME FULL RESPONSIBILITY FOR YOUR USE OF THE SITE AND SERVICE. YOU ACKNOWLEDGE AND AGREE THAT ANY INFORMATION YOU SEND OR RECEIVE DURING YOUR USE OF THE SITE AND SERVICE MAY NOT BE SECURE AND MAY BE INTERCEPTED OR LATER ACQUIRED BY UNAUTHORIZED PARTIES. YOU ACKNOWLEDGE AND AGREE THAT YOUR USE OF THE SITE AND SERVICE IS AT YOUR OWN RISK. RECOGNIZING SUCH, YOU UNDERSTAND AND AGREE THAT, TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, NEITHER METAMASK NOR ITS SUPPLIERS OR LICENSORS WILL BE LIABLE TO YOU FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY OR OTHER DAMAGES OF ANY KIND, INCLUDING WITHOUT LIMITATION DAMAGES FOR LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER TANGIBLE OR INTANGIBLE LOSSES OR ANY OTHER DAMAGES BASED ON CONTRACT, TORT, STRICT LIABILITY OR ANY OTHER THEORY (EVEN IF METAMASK HAD BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES), RESULTING FROM THE SITE OR SERVICE; THE USE OR THE INABILITY TO USE THE SITE OR SERVICE; UNAUTHORIZED ACCESS TO OR ALTERATION OF YOUR TRANSMISSIONS OR DATA; STATEMENTS OR CONDUCT OF ANY THIRD PARTY ON THE SITE OR SERVICE; ANY ACTIONS WE TAKE OR FAIL TO TAKE AS A RESULT OF COMMUNICATIONS YOU SEND TO US; HUMAN ERRORS; TECHNICAL MALFUNCTIONS; FAILURES, INCLUDING PUBLIC UTILITY OR TELEPHONE OUTAGES; OMISSIONS, INTERRUPTIONS, LATENCY, DELETIONS OR DEFECTS OF ANY DEVICE OR NETWORK, PROVIDERS, OR SOFTWARE (INCLUDING, BUT NOT LIMITED TO, THOSE THAT DO NOT PERMIT PARTICIPATION IN THE SERVICE); ANY INJURY OR DAMAGE TO COMPUTER EQUIPMENT; INABILITY TO FULLY ACCESS THE SITE OR SERVICE OR ANY OTHER WEBSITE; THEFT, TAMPERING, DESTRUCTION, OR UNAUTHORIZED ACCESS TO, IMAGES OR OTHER CONTENT OF ANY KIND; DATA THAT IS PROCESSED LATE OR INCORRECTLY OR IS INCOMPLETE OR LOST; TYPOGRAPHICAL, PRINTING OR OTHER ERRORS, OR ANY COMBINATION THEREOF; OR ANY OTHER MATTER RELATING TO THE SITE OR SERVICE.\n\nSOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES OR THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES. ACCORDINGLY, SOME OF THE ABOVE LIMITATIONS MAY NOT APPLY TO YOU.\n\n## 8. Our Proprietary Rights ##\n\nAll title, ownership and intellectual property rights in and to the Service are owned by MetaMask or its licensors. You acknowledge and agree that the Service contains proprietary and confidential information that is protected by applicable intellectual property and other laws. Except as expressly authorized by MetaMask, you agree not to copy, modify, rent, lease, loan, sell, distribute, perform, display or create derivative works based on the Service, in whole or in part. MetaMask issues a license for MetaMask, found [here](https://github.com/MetaMask/metamask-plugin/blob/master/LICENSE). For information on other licenses utilized in the development of MetaMask, please see our attribution page at: [https://metamask.io/attributions.html](https://metamask.io/attributions.html)\n\n## 9. Links ##\n\nThe Service provides, or third parties may provide, links to other World Wide Web or accessible sites, applications or resources. Because MetaMask has no control over such sites, applications and resources, you acknowledge and agree that MetaMask is not responsible for the availability of such external sites, applications or resources, and does not endorse and is not responsible or liable for any content, advertising, products or other materials on or available from such sites or resources. You further acknowledge and agree that MetaMask shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such site or resource.\n\n## 10. Termination and Suspension ##\n\nMetaMask may terminate or suspend all or part of the Service and your MetaMask access immediately, without prior notice or liability, if you breach any of the terms or conditions of the Terms. Upon termination of your access, your right to use the Service will immediately cease.\n\nThe following provisions of the Terms survive any termination of these Terms: INDEMNITY; WARRANTY DISCLAIMERS; LIMITATION ON LIABILITY; OUR PROPRIETARY RIGHTS; LINKS; TERMINATION; NO THIRD PARTY BENEFICIARIES; BINDING ARBITRATION AND CLASS ACTION WAIVER; GENERAL INFORMATION.\n\n## 11. No Third Party Beneficiaries ##\n\nYou agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms.\n\n## 12. Notice and Procedure For Making Claims of Copyright Infringement ##\n\nIf you believe that your copyright or the copyright of a person on whose behalf you are authorized to act has been infringed, please provide MetaMask’s Copyright Agent a written Notice containing the following information:\n\n· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest;\n\n· a description of the copyrighted work or other intellectual property that you claim has been infringed;\n\n· a description of where the material that you claim is infringing is located on the Service;\n\n· your address, telephone number, and email address;\n\n· a statement by you that you have a good faith belief that the disputed use is not authorized by the copyright owner, its agent, or the law;\n\n· a statement by you, made under penalty of perjury, that the above information in your Notice is accurate and that you are the copyright or intellectual property owner or authorized to act on the copyright or intellectual property owner's behalf.\n\nMetaMask’s Copyright Agent can be reached at:\n\nEmail: copyright [at] metamask [dot] io\n\nMail:\n\nAttention:\n\nMetaMask Copyright ℅ ConsenSys\n\n49 Bogart Street\n\nBrooklyn, NY 11206\n\n## 13. Binding Arbitration and Class Action Waiver ##\n\nPLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT\n\n### 13.1 Initial Dispute Resolution ###\n\nThe parties shall use their best efforts to engage directly to settle any dispute, claim, question, or disagreement and engage in good faith negotiations which shall be a condition to either party initiating a lawsuit or arbitration.\n\n### 13.2 Binding Arbitration ###\n\nIf the parties do not reach an agreed upon solution within a period of 30 days from the time informal dispute resolution under the Initial Dispute Resolution provision begins, then either party may initiate binding arbitration as the sole means to resolve claims, subject to the terms set forth below. Specifically, all claims arising out of or relating to these Terms (including their formation, performance and breach), the parties’ relationship with each other and/or your use of the Service shall be finally settled by binding arbitration administered by the American Arbitration Association in accordance with the provisions of its Commercial Arbitration Rules and the supplementary procedures for consumer related disputes of the American Arbitration Association (the \"AAA\"), excluding any rules or procedures governing or permitting class actions.\n\nThe arbitrator, and not any federal, state or local court or agency, shall have exclusive authority to resolve all disputes arising out of or relating to the interpretation, applicability, enforceability or formation of these Terms, including, but not limited to any claim that all or any part of these Terms are void or voidable, or whether a claim is subject to arbitration. The arbitrator shall be empowered to grant whatever relief would be available in a court under law or in equity. The arbitrator’s award shall be written, and binding on the parties and may be entered as a judgment in any court of competent jurisdiction.\n\nThe parties understand that, absent this mandatory provision, they would have the right to sue in court and have a jury trial. They further understand that, in some instances, the costs of arbitration could exceed the costs of litigation and the right to discovery may be more limited in arbitration than in court.\n\n### 13.3 Location ###\n\nBinding arbitration shall take place in New York. You agree to submit to the personal jurisdiction of any federal or state court in New York County, New York, in order to compel arbitration, to stay proceedings pending arbitration, or to confirm, modify, vacate or enter judgment on the award entered by the arbitrator.\n\n### 13.4 Class Action Waiver ###\n\nThe parties further agree that any arbitration shall be conducted in their individual capacities only and not as a class action or other representative action, and the parties expressly waive their right to file a class action or seek relief on a class basis. YOU AND METAMASK AGREE THAT EACH MAY BRING CLAIMS AGAINST THE OTHER ONLY IN YOUR OR ITS INDIVIDUAL CAPACITY, AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS OR REPRESENTATIVE PROCEEDING. If any court or arbitrator determines that the class action waiver set forth in this paragraph is void or unenforceable for any reason or that an arbitration can proceed on a class basis, then the arbitration provision set forth above shall be deemed null and void in its entirety and the parties shall be deemed to have not agreed to arbitrate disputes.\n\n### 13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims ###\n\nNotwithstanding the parties' decision to resolve all disputes through arbitration, either party may bring an action in state or federal court to protect its intellectual property rights (\"intellectual property rights\" means patents, copyrights, moral rights, trademarks, and trade secrets, but not privacy or publicity rights). Either party may also seek relief in a small claims court for disputes or claims within the scope of that court’s jurisdiction.\n\n### 13.6 30-Day Right to Opt Out ###\n\nYou have the right to opt-out and not be bound by the arbitration and class action waiver provisions set forth above by sending written notice of your decision to opt-out to the following address: MetaMask ℅ ConsenSys, 49 Bogart Street, Brooklyn NY 11206 and via email at legal-opt@metamask.io. The notice must be sent within 30 days of September 6, 2016 or your first use of the Service, whichever is later, otherwise you shall be bound to arbitrate disputes in accordance with the terms of those paragraphs. If you opt-out of these arbitration provisions, MetaMask also will not be bound by them.\n\n### 13.7 Changes to This Section ###\n\nMetaMask will provide 60-days’ notice of any changes to this section. Changes will become effective on the 60th day, and will apply prospectively only to any claims arising after the 60th day.\n\nFor any dispute not subject to arbitration you and MetaMask agree to submit to the personal and exclusive jurisdiction of and venue in the federal and state courts located in New York, New York. You further agree to accept service of process by mail, and hereby waive any and all jurisdictional and venue defenses otherwise available.\n\nThe Terms and the relationship between you and MetaMask shall be governed by the laws of the State of New York without regard to conflict of law provisions.\n\n## 14. General Information ##\n\n### 14.1 Entire Agreement ###\n\nThese Terms (and any additional terms, rules and conditions of participation that MetaMask may post on the Service) constitute the entire agreement between you and MetaMask with respect to the Service and supersedes any prior agreements, oral or written, between you and MetaMask. In the event of a conflict between these Terms and the additional terms, rules and conditions of participation, the latter will prevail over the Terms to the extent of the conflict.\n\n### 14.2 Waiver and Severability of Terms ###\n\nThe failure of MetaMask to exercise or enforce any right or provision of the Terms shall not constitute a waiver of such right or provision. If any provision of the Terms is found by an arbitrator or court of competent jurisdiction to be invalid, the parties nevertheless agree that the arbitrator or court should endeavor to give effect to the parties' intentions as reflected in the provision, and the other provisions of the Terms remain in full force and effect.\n\n### 14.3 Statute of Limitations ###\n\nYou agree that regardless of any statute or law to the contrary, any claim or cause of action arising out of or related to the use of the Service or the Terms must be filed within one (1) year after such claim or cause of action arose or be forever barred.\n\n### 14.4 Section Titles ###\n\nThe section titles in the Terms are for convenience only and have no legal or contractual effect.\n\n### 14.5 Communications ###\n\nUsers with questions, complaints or claims with respect to the Service may contact us using the relevant contact information set forth above and at communications@metamask.io.\n\n## 15 Related Links ##\n\n**[Terms of Use](https://metamask.io/terms.html)**\n\n**[Privacy](https://metamask.io/privacy.html)**\n\n**[Attributions](https://metamask.io/attributions.html)**\n\n","id":0},{"read":false,"date":"Mon May 08 2017","title":"Privacy Notice","body":"MetaMask is beta software. \n\nWhen you log in to MetaMask, your current account is visible to every new site you visit.\n\nFor your privacy, for now, please sign out of MetaMask when you're done using a site.\n\nAlso, by default, you will be signed in to a test network. To use real Ether, you must connect to the main network manually in the top left network menu.\n\n","id":2}]},"BlacklistController":{"phishing":{"version":2,"tolerance":2,"fuzzylist":["metamask.io","myetherwallet.com","cryptokitties.co"],"whitelist":["metahash.io","metahash.net","metahash.org","cryptotitties.com","cryptocities.net","cryptoshitties.co","cryptotitties.fun","cryptokitties.forsale","cryptokitties.care","metamate.cc","metamesh.tech","ico.nexus.social","metamesh.org","metatask.io","metmask.com","metarasa.com","metapack.com","metacase.com","metafas.nl","metamako.com","metamast.com","metamax.ru","metadesk.io","metadisk.com","metallsk.ru","metamag.fr","metamaks.ru","metamap.ru","metamaps.cc","metamats.com","metamax.by","metamax.com","metamax.io","metamuse.net","metarank.com","metaxas.com","megamas2.ru","metamask.io","myetherwallet.com","myethlerwallet.com","ethereum.org","myetheroll.com","myetherapi.com","ledgerwallet.com","databrokerdao.com","etherscan.io","etherid.org","ether.cards","etheroll.com","ethnews.com","ethex.market","ethereumdev.io","ethereumdev.kr","dether.io","ethermine.org","slaask.com","etherbtc.io","ethereal.capital","etherisc.com","m.famalk.net","etherecho.com","ethereum.os.tc","theethereum.wiki","metajack.im","etherhub.io","ethereum.network","ethereum.link","ethereum.com","prethereum.org","ethereumj.io","etheraus.com","ethereum.dev","1ethereum.ru","ethereum.nz","nethereum.com","metabank.com","metamas.com","aventus.io","metabase.com","etherdelta.com","metabase.one","cryptokitties.co"],"blacklist":["myetherwallet.uk.com","kodakone.cc","nyeihitervvallet.com","xn--myeterwalet-cm8eoi.com","nucleus.foundation","beetoken-ico.com","data-token.com","tron-labs.com","ocoin.tech","aionfoundation.com","ico-telegram.org","nyeihitervvallat.com","telegramcoin.us","daddi.cloud","daditoken.com","blockarray.org","dadi-cloud.net","wanchainfunding.org","ico-telegram.io","iconfoundation.site","iost.co","beetoken-ico.eu","cindicator.network","wanchainetwork.org","wamchain.org","wanchainltd.org","wanchainalliance.org","nucleus-vision.net","ledgerwallet.by","nucleuss.vision","myenhterswailct.com","cobin-hood.com","wanchainfoundation.org","xn--polniex-ex4c.com","xn--polniex-s1a.com","xn--polonex-ieb.com","xn--polonex-sza.com","xn--polonex-zw4c.com","xn--polonix-ws4c.com","xn--polonix-y8a.com","xn--pooniex-ojb.com","gramico.info","dimnsions.network","www-gemini.com","login-kucoin.net","venchain.foundation","grampreico.com","tgram.cc","ton-gramico.com","wwwpaywithink.com","coniomi.com","paywithnk.com","paywithlnk.com","iluminatto.com.br","pundix.eu","xn--bttrx-esay.com","xn--bttrex-w8a.com","xn--bnance-bwa.com","xn--shpeshift-11a.com","xn--shapeshif-ts6d.com","xn--shapshift-yf7d.com","wwwbluzelle.com","bluzelie.com","nucleus-vision.org","omisegonetwork.site","etlherzero.com","etlherdelta.com","xn--condesk-0ya.com","xn--condesk-sfb.com","xn--coindsk-vs4c.com","iexecplatform.com","tongramico.com","nucleus-vision.eu","intchain.network","wanchain.cloud","bluzelle-ico.com","ethzero-wallet.com","xn--metherwalle-jb9et7d.com","xn--coinesk-jo3c.com","venchainfoundation.com","myenhtersvvailot.com","ether-zero.net","ins.foundation","nastoken.org","telcointoken.com","ether0.org","eterzero.org","bluzelle-ico.eu","bleuzelle.com","appcoinstoken.org","xn--quanstamp-8s6d.com","myehntersvvailct.com","myeherwalllet.com","ico-bluzelle.com","bluzelle.im","bluzelle.one","bluzele.sale","bluzele.co","sether.ws","xn--myetherwalet-6gf.com","xn--rnyethewaliet-om1g.com","rnyethervailet.com","mvetherwaliet.com","rnyetherwailet.com","myethervaliet.com","rnyethervaliet.com","mvetherwalilet.com","xn--myethewalie-3ic0947g.com","xn--mthrwallet-z6ac3y.com","xn--myeherwalie-vici.com","xn--myethervvalie-8vc.com","xn--mythrwallt-06acf.com","xn--mtherwallet-y9a6y.com","myetherwallet.applytoken.tk","ethereum-zero.com","quanstamptoken.tk","bluzelle.network","ether-wallet.org","tron-wallet.info","appcoinsproject.com","vechain.foundation","tronlab.site","tronlabs.network","bluzelle.cc","ethblender.com","ethpaperwallet.net","waltontoken.org","icoselfkey.org","etherzeroclaim.com","etherzero.promo","bluzelle.pro","token-selfkey.org","xn--etherdlta-0f7d.com","sether.in","xn--ttrex-ysa9423c.com","bluzelle.eu","bluzelle.site","gifto.tech","xn--os-g7s.com","selfkey.co","xn--myeherwalet-ns8exy.com","xn--coinelegraph-wk5f.com","dai-stablecoin.com","eos-token.org","venchain.org","gatcoins.io","deepbrainchain.co","myetherwalililet.info","myehvterwallet.com","myehterumswallet.com","nucleusico.com","tronlab.tech","0x-project.com","gift-token-events.mywebcommunity.org","funfairtoken.org","breadtokenapp.com","cloudpetstore.com","myethwalilet.com","selfkeys.org","wallet-ethereum.com","xn--methrwallt-26ar0z.com","xn--mytherwllet-r8a0c.com","bluzelle.promo","tokensale.bluzelle.promo","cedarlake.org","marketingleads4u.com","cashaa.co","xn--inance-hrb.com","wanchain.tech","zenprolocol.com","ethscan.io","etherscan.in","props-project.com","zilliaq.com","reqestnetwork.com","etherdelta.pw","ethereum-giveaway.org","mysimpletoken.org","binancc.com","blnance.org","elherdelta.io","xn--hapeshit-ez9c2y.com","tenxwallet.co","singularitynet.info","mytlherwaliet.info","iconmainnet.ml","tokenselfkey.org","xn--myetewallet-cm8e5y.com","envione.org","myetherwalletet.com","claimbcd.com","ripiocreditnetwork.in","xn--yeterwallet-ml8euo.com","ethclassicwallet.info","myltherwallet.ru.com","etherdella.com","xn--yeterwallet-bm8ewn.com","singularty.net","cloudkitties.co","iconfoundation.io","kittystat.com","gatscoin.io","singularitynet.in","sale.canay.io","canay.io","wabicoin.co","envion.top","sirinslabs.com","tronlab.co","paxful.com.ng","changellyli.com","ethereum-code.com","xn--plonex-6va6c.com","envion.co","envion.cc","envion.site","ethereumchain.info","xn--envon-1sa.org","xn--btstamp-rfb.net","envlon.org","envion-ico.org","spectivvr.org","sirinlbs.com","ethereumdoubler.life","xn--myetherwllet-fnb.com","sirin-labs.com","sirin-labs.org","envion.one","envion.live","propsproject.org","propsprojects.com","decentralland.org","xn--metherwalet-ns8ep4b.com","redpulsetoken.co","propsproject.tech","xn--myeterwalet-nl8emj.com","powrerledger.com","cryptokitties.com","sirinlabs.pro","sirinlabs.co","sirnlabs.com","superbitcoin-blockchain.info","hellobloom.me","mobus.network","powrrledger.com","xn--myeherwalet-ms8eyy.com","qlink-ico.com","gatcoin.in","tokensale.gamefllp.com","gamefllp.com","xn--myeherwalle-vici.com","xn--myetherwalet-39b.com","xn--polonex-ffb.com","xn--birex-leba.com","raiden-network.org","sirintabs.com","xn--metherwallt-79a30a.com","xn--myethrwllet-2kb3p.com","myethlerwallet.eu","xn--btrex-b4a.com","powerrledger.com","xn--cointeegraph-wz4f.com","myerherwalet.com","qauntstanp.com","myetherermwallet.com","xn--myethewalet-ns8eqq.com","xn--nvion-hza.org","nnyetherwallelt.ru.com","ico-wacoin.com","xn--myeterwalet-nl8enj.com","bitcoinsilver.io","t0zero.com","tokensale.gizer.in","gizer.in","wabitoken.com","gladius.ws","xn--metherwallt-8bb4w.com","quanttstamp.com","gladius.im","ethereumstorage.net","powerledgerr.com","xn--myeherwallet-4j5f.com","quamtstamp.com","quntstamp.com","xn--changely-j59c.com","shapeshlft.com","coinbasenews.co.uk","xn--metherwallet-hmb.com","envoin.org","powerledger.com","bitstannp.net","xn--myetherallet-4k5fwn.com","xn--coinbas-pya.com","requestt.network","oracls.network","sirinlabs.website","powrledger.io","slackconfirm.com","shape-shift.io","oracles-network.org","xn--myeherwalle-zb9eia.com","blockstack.one","urtust.io","bittrex.one","t0-ico.com","xn--cinbase-90a.com","xn--metherwalet-ns8ez1g.com","tzero-ico.com","tzero.su","tzero.website","blockstack.network","ico-tzero.com","spectre.site","tzero.pw","spectre-ai.net","xn--waxtokn-y8a.com","dmarket.pro","bittrex.com11648724328774.cf","bittrex.com1987465798.ga","autcus.org","t-zero.org","xn--zero-zxb.com","myetherwalletfork.com","blokclbain.info","datum.sale","spectre-ai.org","powerledgr.com","simpletoken.live","sale.simpletoken.live","qauntstamp.com","raiden-network.com","metalpayme.com","quantstamp-ico.com","myetherwailetclient.com","biockchain.biz","wallets-blockchain.com","golemairdrop.com","omisegoairdrop.net","blodkchainwallet.info","walton-chain.org","elite888-ico.com","bitflyerjp.com","chainlinksmartcontract.com","stormtoken.eu","omise-go.tech","saltending.com","stormltoken.com","xn--quanttamp-42b.com","stormtoken.co","storntoken.com","stromtoken.com","storm-token.com","stormtokens.io","ether-delta.com","ethconnect.live","ethconnect.trade","xn--bttrex-3va.net","quantstamp.com.co","wancha.in","augur-network.com","quantstamp.com.ua","myetherwalletmew.com","myetherumwalletts.com","xn--quanstamp-tmd.com","quantsstamps.com","changellyl.net","xn--myetherwalet-1fb.com","myethereumwallets.com","xn--myetherwalet-e9b.com","quantslamp.com","metelpay.com","xn--eterdelta-m75d.com","linksmartcontract.com","myetherwalletaccess.com","myetherwalletcheck.com","myetherwalletcheck.info","myetherwalletconf.com","myetherwalleteal.com","myetherwalletec.com","myetherwalletgeth.com","myetherwalletmetamask.com","myetherwalletmm.com","myetherwalletmy.com","myetherwalletnh.com","myetherwalletnod.com","myetherwalletrr.com","myetherwalletrty.com","myetherwalletsec.com","myetherwalletsecure.com","myetherwalletutc.com","myetherwalletver.info","myetherwalletview.com","myetherwalletview.info","myetherwalletvrf.com","myetherwalletmist.com","myetherwalletext.com","myetherwalletjson.com","mettalpay.com","bricklblock.io","bittrexy.com","utrust.so","myethierwallet.org","metallpay.com","kraken-wallet.com","dmarkt.io","etherdeltla.com","unlversa.io","universa.sale","mercuryprotocol.live","ripiocredlt.network","myetlherwa11et.com","dentacoin.in","rdrtg.com","myetherwallet.com.rdrgh.com","rdrgh.com","ripiocreditnetwork.co","riaden.network","hydrominer.biz","rdrblock.com","reqest.network","senstoken.com","myetherwallat.services","ripiocredit.net","xn--metherwallet-c06f.com","ico.ripiocredits.com","ripiocredits.com","raidens.network","artoken.co","myetherwalletlgn.com","etherblog.click","stormtoken.site","httpmyetherwallet.com","myetherwalletverify.com","byzantiumfork.com","myetherwallet.com.byzantiumfork.com","www-myethervvallet.com","ether24.info","block-v.io","bittrex.cash","shapishift.io","ripiocerdit.network","rnyetherwa11et.com","claimether.com","enigmatokensale.com","ethereum-org.com","mvetnerwallet.com","myctherwallet.com","myetherwaltet.com","myetherwatlet.com","privatix.me","myetherwalletcnf.com","myetherwalletver.com","privatix.top","privatix.pro","privatex.io","stormtoken.cc","raiden.online","stormstoken.com","myetereumwallet.com","stormtokens.net","myetherwalletconf.info","storrntoken.com","worldofbattles.io","ico.worldofbattles.io","privatix.live","riden.network","raidan.network","ralden.network","mymyetherwallet.com","myetherwallets.net","myetherwalletverify.info","stormxtoken.com","myethereum-wallet.com","myetherwallet-forkprep.pagedemo.co","myetnerwailet.com","www-mvetherwallet.com","etheirdelta.com","myetherwalletiu.com","myetherwaiiett.com","xn--mytherwalet-cbb87i.com","xn--myethrwallet-ivb.co","xn--myeterwallet-f1b.com","myehterwaliet.com","omegaone.co","myetherwaiietw.com","slack.com.ru","polkodot.network","request-network.net","requestnetwork.live","binancie.com","first-eth.info","myewerthwalliet.com","enjincoin.pw","xn--bitrex-k17b.com","alrswap.io","www-request.network","myetnenwallet.com","www-enigma.co","cryptoinsidenews.com","air-swap.tech","launch.airswap.cc","airswap.cc","airswaptoken.com","launch.airswap.in","airswap.in","security-steemit.com.mx","blockchalnwallet.com","blodkchainwallet.com","blodkchaln.com","myethereumwaiiet.com","myethereumwaliet.com","myethereumwalilet.com","myetherswailet.com","myetherswaliet.com","myetherswalilet.com","myetherwalilett.com","myetherwalletl.com","myetherwalletww.com","myethereunwallet.com","myethereumwallct.com","myetherwaiieti.com","myetherwaiiete.com","upfirng.com","paypie.net","paypie.tech","soam.co","myetherwaiict.com","numerai-token.com","www-bankera.com","vvanchain.org","omisegoairdrop.com","xn--enjncoin-41a.io","suncontract.su","myetherwaiietr.com","shapeshiff.io","warchain.org","myethwallett.com","myethervvaliet.com","wanchains.org","etherparty.in","enjincoin.me","etiam.io","invest.smartlands.tech","smartlands.tech","enijncoin.io","wanchain.network","nimiq.su","enjincoin.sale","tenxwallet.io","golem-network.net","myyethwallet.ml","mywetherwailiet.com","omg-omise.com","district0x.tech","centra-token.com","etherdetla.com","etnerparty.io","etherdelta.su","myetherwallett.neocities.org","myetherwallet-secure.com","myethereumwalletntw.info","real-markets.io","wallet-ethereum.org","request-network.com","shapeshifth.io","shiapeshift.in","coin.red-puise.com","ibittreix.com","coinkbase.com","cindicator.pro","myetherwallet.com.ailogin.me","eventchain.co","kinkik.in","myetherumwalletview.com","protostokenhub.com","coinrbase.com","myetherwalletlogin.com","omisegotoken.com","myethereumwalletntw.com","reall.markets","cobinhood.org","cobinhood.io","happy-coin.org","bitfinex.com.co","bitfienex.com","iconn.foundation","centra.vip","smartcontract.live","icon.community","air-token.com","centra.credit","myetherwallet-singin.com","smartcontractlink.com","shapesshift.io","0xtoken.io","augurproject.co","ethereumus.one","myetherumwalet.com","myetherwalletsignin.com","change-bank.org","charge-bank.com","myetherwalletsingin.com","myetherwalletcontract.com","change-bank.io","chainlink.tech","myetherwallet-confirm.com","tokensale.kybernet.network","kybernet.network","kyberr.network","kybernetwork.io","myetherwalletconfirm.com","kvnuke.github.io","kin.kikpro.co","myethereumwallet.co.uk","tokensale-kyber.network","kyber-network.co","tokensale.kyber-network.co","pyro0.github.io","tokensale.kyber.digital","kyber.digital","omise-go.me","my.etherwallet.com.de","bepartof.change-bank.co","change-bank.co","enigma-tokens.co","coinbase.com.eslogin.co","xn--bittrx-mva.com","ethrdelta.github.io","etherdellta.com","ico-nexus.social","red-pulse.tech","bitj0b.io","xn--bttrex-bwa.com","kin-klk.com","kin-crowdsale.com","ethedelta.com","coindash.su","myethwallet.co.uk","swarm.credit","myethereumwallet.uk","iconexu.social","wanchain.co","enigrna.co","linknetwork.co","qtum-token.com","omisego.com.co","rivetzintl.org","etherdelta.one","the-ether.pro","etherdelta.gitnub.io","kirkik.com","monetha.ltd","vlberate.io","ethereumwallet-kr.info","omise-go.org","iconexus.social","bittirrex.com","aventus.pro","atlant.solutions","aventus.group","metamak.io","omise.com.co","herotokens.io","starbase.pro","etherdelta.githulb.io","herotoken.co","kinico.net","dmarket.ltd","etherdelta.gilthub.io","golem-network.com","etnerscan.io","bllttriex.com","monetha.me","monetha.co","monetha-crowdsale.com","starbase.tech","aventus-crowdsale.com","shapeshift.pro","bllttrex.com","kickico.co","statustoken.im","bilttrex.com","tenxpay.io","bittrex.ltd","metalpay.im","aragon.im","coindash.tech","decentraland.tech","decentraland.pro","status-token.com","bittrex.cam","enigmatoken.com","unocoin.company","unocoin.fund","0xproject.io","0xtoken.com","numerai.tech","decentraiand.org","blockcrein.info","blockchealn.info","bllookchain.info","blockcbhain.info","myetherwallet.com.ethpromonodes.com","mettamask.io","tokenswap.org","netherum.com","etherexx.org","etherume.io","ethereum.plus","ehtereum.org","etereurm.org","etheream.com","ethererum.org","ethereum.io","etherdelta-glthub.com","cryptoalliance.herokuapp.com","bitspark2.com","indorsetoken.com","iconexus.tk","iconexus.ml","iconexus.ga","iconexus.cf","etherwallet.online","wallet-ethereum.net","bitsdigit.com","etherswap.org","eos.ac","uasfwallet.com","ziber.io","multiply-ethereum.info","bittrex.comze.com","karbon.vacau.com","etherdelta.gitlhub.io","etherdelta.glthub.io","digitaldevelopersfund.vacau.com","district-0x.io","coin-dash.com","coindash.ru","district0x.net","aragonproject.io","coin-wallet.info","coinswallet.info","contribute-status.im","ether-api.com","ether-wall.com","mycoinwallet.net","ethereumchamber.com","ethereumchamber.net","ethereumchest.com","ethewallet.com","myetherwallet.com.vc","myetherwallet.com.pe","myetherwallet.us.com","myetherwallet.com.u0387831.cp.regruhosting.ru","myethereumwallet.su","myetherweb.com.de","myetherieumwallet.com","myetehrwallet.com","myeterwalet.com","myetherwaiiet.com","myetherwallet.info","myetherwallet.ch","myetherwallet.om","myethervallet.com","myetherwallet.com.cm","myetherwallet.com.co","myetherwallet.com.de","myetherwallet.com.gl","myetherwallet.com.im","myetherwallet.com.ua","secure-myetherwallet.com","update-myetherwallet.com","wwwmyetherwallet.com","myeatherwallet.com","myetharwallet.com","myelherwallel.com","myetherwaillet.com","myetherwaliet.com","myetherwallel.com","myetherwallet.cam","myetherwallet.cc","myetherwallet.co","myetherwallet.cm","myetherwallet.cz","myetherwallet.org","myetherwallet.tech","myetherwallet.top","myetherwallet.net","myetherwallet.ru.com","myetherwallet.com.ru","metherwallet.com","myetrerwallet.com","myetlerwallet.com","myethterwallet.com","myethwallet.io","myethterwallet.co","myehterwallet.co","myaetherwallet.com","myetthterwallet.com","myetherwallet.one","myelterwallet.com","myetherwallet.gdn","myetherwallt.com","myeterwallet.com","myeteherwallet.com","myethearwailet.com","myetherwallelt.com","myetherwallett.com","etherwallet.org","myetherewallet.com","myeherwallet.com","myethcrwallet.com","myetherwallet.link","myetherwallets.com","myethearwaillet.com","myethearwallet.com","myetherawllet.com","myethereallet.com","myetherswallet.com","myetherwalet.com","myetherwaller.com","myetherwalliet.com","myetherwllet.com","etherwallet.io","myetherwallet.ca","myetherwallet.me","myetherwallet.ru","myetherwallet.xyz","myetherwallte.com","myethirwallet.com","myethrewallet.com","etherwallet.net","maetherwallet.com","meyetherwallet.com","my.ether-wallet.pw","myehterwallet.com","myeitherwallet.com","myelherwallet.com","myeltherwallet.com","myerherwallet.com","myethearwalet.com","myetherewalle.com","myethervvallet.com","myetherwallent.com","myetherwallet.fm","myetherwalllet.com","myetherwalltet.com","myetherwollet.com","myetlherwalet.com","myetlherwallet.com","rnyetherwallet.com","etherclassicwallet.com","omg-omise.co","omise-go.com","omise-go.net","omise-omg.com","omise-go.io","tenx-tech.com","bitclaive.com","tokensale-tenx.tech","ubiqcoin.org","metamask.com","ethtrade.io","myetcwallet.com","account-kigo.net","bitcoin-wallet.net","blocklichan.info","bloclkicihan.info","coindash.ml","eos-bonus.com","eos-io.info","ether-wallet.net","ethereum-wallet.info","ethereum-wallet.net","ethereumchest.net","reservations-kigo.net","reservations-lodgix.com","secure-liverez.com","secure-onerooftop.com","settings-liverez.com","software-liverez.com","software-lodgix.com","unhackableetherwallets.com","www-myetherwallet.com","etherwallet.co.za","etherwalletchain.com","etherwallets.net","etherwallets.nl","my-ethwallet.com","my.ether-wallet.co","myetherwallet.com.am","myetherwallet.com.ht","myetherwalletcom.com","myehterwailet.com","xn--myetherwalle-xoc.com","xn--myetherwalle-44i.com","xn--myetherwalle-xhk.com","xn--myetherwallt-cfb.com","xn--myetherwallt-6tb.com","xn--myetherwallt-xub.com","xn--myetherwallt-ovb.com","xn--myetherwallt-fwb.com","xn--myetherwallt-5wb.com","xn--myetherwallt-jzi.com","xn--myetherwallt-2ck.com","xn--myetherwallt-lok.com","xn--myetherwallt-lsl.com","xn--myetherwallt-ce6f.com","xn--myetherwalet-mcc.com","xn--myetherwalet-xhf.com","xn--myetherwalet-lcc.com","xn--myetherwaet-15ba.com","xn--myetherwalet-whf.com","xn--myetherwaet-v2ea.com","xn--myetherwllet-59a.com","xn--myetherwllet-jbb.com","xn--myetherwllet-wbb.com","xn--myetherwllet-9bb.com","xn--myetherwllet-ncb.com","xn--myetherwllet-0cb.com","xn--myetherwllet-5nb.com","xn--myetherwllet-ktd.com","xn--myetherwllet-mre.com","xn--myetherwllet-76e.com","xn--myetherwllet-o0l.com","xn--myetherwllet-c45f.com","xn--myetherallet-ejn.com","xn--myethewallet-4nf.com","xn--myethewallet-iof.com","xn--myethewallet-mpf.com","xn--myethewallet-6bk.com","xn--myethewallet-i31f.com","xn--myethrwallet-feb.com","xn--myethrwallt-fbbf.com","xn--myethrwallet-seb.com","xn--myethrwallt-rbbf.com","xn--myethrwallet-5eb.com","xn--myethrwallt-3bbf.com","xn--myethrwallet-0tb.com","xn--myethrwallt-tpbf.com","xn--myethrwallet-rub.com","xn--myethrwallt-iqbf.com","xn--myethrwallet-ivb.com","xn--myethrwallt-6qbf.com","xn--myethrwallet-8vb.com","xn--myethrwallt-vrbf.com","xn--myethrwallet-zwb.com","xn--myethrwallt-ksbf.com","xn--myethrwallet-dzi.com","xn--myethrwallt-wbif.com","xn--myethrwallet-wck.com","xn--myethrwallt-skjf.com","xn--myethrwallet-fok.com","xn--myethrwallt-fvjf.com","xn--myethrwallet-fsl.com","xn--myethrwallt-fwkf.com","xn--myethrwallet-5d6f.com","xn--myethrwallt-319ef.com","xn--myeterwallet-ufk.com","xn--myeterwallet-nrl.com","xn--myeterwallet-von.com","xn--myeterwallet-jl6c.com","xn--myeherwallet-ooc.com","xn--myeherwalle-6hci.com","xn--myeherwallet-v4i.com","xn--myeherwalle-zgii.com","xn--myeherwallet-ohk.com","xn--myeherwalle-6oji.com","xn--mytherwallet-ceb.com","xn--mythrwallet-cbbc.com","xn--mythrwallt-c7acf.com","xn--mytherwallet-peb.com","xn--mythrwallet-obbc.com","xn--mythrwallt-n7acf.com","xn--mytherwallet-2eb.com","xn--mythrwallet-0bbc.com","xn--mythrwallt-y7acf.com","xn--mytherwallet-xtb.com","xn--mythrwallet-qpbc.com","xn--mythrwallt-jlbcf.com","xn--mytherwallet-oub.com","xn--mythrwallet-fqbc.com","xn--mythrwallt-5lbcf.com","xn--mythrwallet-3qbc.com","xn--mythrwallt-smbcf.com","xn--mytherwallet-5vb.com","xn--mythrwallet-srbc.com","xn--mythrwallt-fnbcf.com","xn--mytherwallet-wwb.com","xn--mythrwallet-hsbc.com","xn--mythrwallt-1nbcf.com","xn--mytherwallet-9yi.com","xn--mythrwallet-tbic.com","xn--mythrwallt-dnhcf.com","xn--mytherwallet-tck.com","xn--mythrwallet-pkjc.com","xn--mythrwallt-lsicf.com","xn--mytherwallet-cok.com","xn--mythrwallet-cvjc.com","xn--mythrwallt-c2icf.com","xn--mytherwallet-csl.com","xn--mythrwallet-cwkc.com","xn--mythrwallt-c0jcf.com","xn--mytherwallet-2d6f.com","xn--mythrwallet-019ec.com","xn--mythrwallt-yq3ecf.com","xn--metherwallet-qlb.com","xn--metherwallet-1uf.com","xn--metherwallet-iyi.com","xn--metherwallet-zhk.com","xn--metherwallet-3ml.com","xn--mytherwallet-fvb.com","xn--myetherwallt-7db.com","xn--myetherwallt-leb.com","xn--myetherwallt-yeb.com","xn--yetherwallet-vjf.com","xn--yetherwallet-dfk.com","xn--yetherwallet-1t1f.com","xn--yetherwallet-634f.com","xn--myeherwallet-fpc.com","xn--myethewallt-crb.com","xn--metherwallet-1vc.com","xn--myeherwallt-kbb8039g.com","xn--myeherwallet-vk5f.com","xn--yethewallet-iw8ejl.com","xn--bittrx-th8b.com","xn--polniex-n0a.com","thekey.vin","thekey-vip.com","digitexftures.com","ethzero-wallet.org","zeepln.io","wepowers.network","wepower.vision"]}},"CurrencyController":{"currentCurrency":"usd","conversionRate":1112,"conversionDate":1517351401}}} \ No newline at end of file +{"meta":{"version":20},"data":{"config":{},"NetworkController":{"provider":{"type":"mainnet","rpcTarget":"https://mainnet.infura.io/metamask"},"network":"1"},"firstTimeInfo":{"version":"3.12.1","date":1517351427287},"NoticeController":{"noticesList":[{"read":false,"date":"Thu Feb 09 2017","title":"Terms of Use","body":"# Terms of Use #\n\n**THIS AGREEMENT IS SUBJECT TO BINDING ARBITRATION AND A WAIVER OF CLASS ACTION RIGHTS AS DETAILED IN SECTION 13. PLEASE READ THE AGREEMENT CAREFULLY.**\n\n_Our Terms of Use have been updated as of September 5, 2016_\n\n## 1. Acceptance of Terms ##\n\nMetaMask provides a platform for managing Ethereum (or \"ETH\") accounts, and allowing ordinary websites to interact with the Ethereum blockchain, while keeping the user in control over what transactions they approve, through our website located at[ ](http://metamask.io)[https://metamask.io/](https://metamask.io/) and browser plugin (the \"Site\") — which includes text, images, audio, code and other materials (collectively, the “Content”) and all of the features, and services provided. The Site, and any other features, tools, materials, or other services offered from time to time by MetaMask are referred to here as the “Service.” Please read these Terms of Use (the “Terms” or “Terms of Use”) carefully before using the Service. By using or otherwise accessing the Services, or clicking to accept or agree to these Terms where that option is made available, you (1) accept and agree to these Terms (2) consent to the collection, use, disclosure and other handling of information as described in our Privacy Policy and (3) any additional terms, rules and conditions of participation issued by MetaMask from time to time. If you do not agree to the Terms, then you may not access or use the Content or Services.\n\n## 2. Modification of Terms of Use ##\n\nExcept for Section 13, providing for binding arbitration and waiver of class action rights, MetaMask reserves the right, at its sole discretion, to modify or replace the Terms of Use at any time. The most current version of these Terms will be posted on our Site. You shall be responsible for reviewing and becoming familiar with any such modifications. Use of the Services by you after any modification to the Terms constitutes your acceptance of the Terms of Use as modified.\n\n\n\n## 3. Eligibility ##\n\nYou hereby represent and warrant that you are fully able and competent to enter into the terms, conditions, obligations, affirmations, representations and warranties set forth in these Terms and to abide by and comply with these Terms.\n\nMetaMask is a global platform and by accessing the Content or Services, you are representing and warranting that, you are of the legal age of majority in your jurisdiction as is required to access such Services and Content and enter into arrangements as provided by the Service. You further represent that you are otherwise legally permitted to use the service in your jurisdiction including owning cryptographic tokens of value, and interacting with the Services or Content in any way. You further represent you are responsible for ensuring compliance with the laws of your jurisdiction and acknowledge that MetaMask is not liable for your compliance with such laws.\n\n## 4 Account Password and Security ##\n\nWhen setting up an account within MetaMask, you will be responsible for keeping your own account secrets, which may be a twelve-word seed phrase, an account file, or other locally stored secret information. MetaMask encrypts this information locally with a password you provide, that we never send to our servers. You agree to (a) never use the same password for MetaMask that you have ever used outside of this service; (b) keep your secret information and password confidential and do not share them with anyone else; (c) immediately notify MetaMask of any unauthorized use of your account or breach of security. MetaMask cannot and will not be liable for any loss or damage arising from your failure to comply with this section.\n\n## 5. Representations, Warranties, and Risks ##\n\n### 5.1. Warranty Disclaimer ###\n\nYou expressly understand and agree that your use of the Service is at your sole risk. The Service (including the Service and the Content) are provided on an \"AS IS\" and \"as available\" basis, without warranties of any kind, either express or implied, including, without limitation, implied warranties of merchantability, fitness for a particular purpose or non-infringement. You acknowledge that MetaMask has no control over, and no duty to take any action regarding: which users gain access to or use the Service; what effects the Content may have on you; how you may interpret or use the Content; or what actions you may take as a result of having been exposed to the Content. You release MetaMask from all liability for you having acquired or not acquired Content through the Service. MetaMask makes no representations concerning any Content contained in or accessed through the Service, and MetaMask will not be responsible or liable for the accuracy, copyright compliance, legality or decency of material contained in or accessed through the Service.\n\n### 5.2 Sophistication and Risk of Cryptographic Systems ###\n\nBy utilizing the Service or interacting with the Content or platform in any way, you represent that you understand the inherent risks associated with cryptographic systems; and warrant that you have an understanding of the usage and intricacies of native cryptographic tokens, like Ether (ETH) and Bitcoin (BTC), smart contract based tokens such as those that follow the Ethereum Token Standard (https://github.com/ethereum/EIPs/issues/20), and blockchain-based software systems.\n\n### 5.3 Risk of Regulatory Actions in One or More Jurisdictions ###\n\nMetaMask and ETH could be impacted by one or more regulatory inquiries or regulatory action, which could impede or limit the ability of MetaMask to continue to develop, or which could impede or limit your ability to access or use the Service or Ethereum blockchain.\n\n### 5.4 Risk of Weaknesses or Exploits in the Field of Cryptography ###\n\nYou acknowledge and understand that Cryptography is a progressing field. Advances in code cracking or technical advances such as the development of quantum computers may present risks to cryptocurrencies and Services of Content, which could result in the theft or loss of your cryptographic tokens or property. To the extent possible, MetaMask intends to update the protocol underlying Services to account for any advances in cryptography and to incorporate additional security measures, but does not guarantee or otherwise represent full security of the system. By using the Service or accessing Content, you acknowledge these inherent risks.\n\n### 5.5 Volatility of Crypto Currencies ###\n\nYou understand that Ethereum and other blockchain technologies and associated currencies or tokens are highly volatile due to many factors including but not limited to adoption, speculation, technology and security risks. You also acknowledge that the cost of transacting on such technologies is variable and may increase at any time causing impact to any activities taking place on the Ethereum blockchain. You acknowledge these risks and represent that MetaMask cannot be held liable for such fluctuations or increased costs.\n\n### 5.6 Application Security ###\n\nYou acknowledge that Ethereum applications are code subject to flaws and acknowledge that you are solely responsible for evaluating any code provided by the Services or Content and the trustworthiness of any third-party websites, products, smart-contracts, or Content you access or use through the Service. You further expressly acknowledge and represent that Ethereum applications can be written maliciously or negligently, that MetaMask cannot be held liable for your interaction with such applications and that such applications may cause the loss of property or even identity. This warning and others later provided by MetaMask in no way evidence or represent an on-going duty to alert you to all of the potential risks of utilizing the Service or Content.\n\n## 6. Indemnity ##\n\nYou agree to release and to indemnify, defend and hold harmless MetaMask and its parents, subsidiaries, affiliates and agencies, as well as the officers, directors, employees, shareholders and representatives of any of the foregoing entities, from and against any and all losses, liabilities, expenses, damages, costs (including attorneys’ fees and court costs) claims or actions of any kind whatsoever arising or resulting from your use of the Service, your violation of these Terms of Use, and any of your acts or omissions that implicate publicity rights, defamation or invasion of privacy. MetaMask reserves the right, at its own expense, to assume exclusive defense and control of any matter otherwise subject to indemnification by you and, in such case, you agree to cooperate with MetaMask in the defense of such matter.\n\n## 7. Limitation on liability ##\n\nYOU ACKNOWLEDGE AND AGREE THAT YOU ASSUME FULL RESPONSIBILITY FOR YOUR USE OF THE SITE AND SERVICE. YOU ACKNOWLEDGE AND AGREE THAT ANY INFORMATION YOU SEND OR RECEIVE DURING YOUR USE OF THE SITE AND SERVICE MAY NOT BE SECURE AND MAY BE INTERCEPTED OR LATER ACQUIRED BY UNAUTHORIZED PARTIES. YOU ACKNOWLEDGE AND AGREE THAT YOUR USE OF THE SITE AND SERVICE IS AT YOUR OWN RISK. RECOGNIZING SUCH, YOU UNDERSTAND AND AGREE THAT, TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, NEITHER METAMASK NOR ITS SUPPLIERS OR LICENSORS WILL BE LIABLE TO YOU FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY OR OTHER DAMAGES OF ANY KIND, INCLUDING WITHOUT LIMITATION DAMAGES FOR LOSS OF PROFITS, GOODWILL, USE, DATA OR OTHER TANGIBLE OR INTANGIBLE LOSSES OR ANY OTHER DAMAGES BASED ON CONTRACT, TORT, STRICT LIABILITY OR ANY OTHER THEORY (EVEN IF METAMASK HAD BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES), RESULTING FROM THE SITE OR SERVICE; THE USE OR THE INABILITY TO USE THE SITE OR SERVICE; UNAUTHORIZED ACCESS TO OR ALTERATION OF YOUR TRANSMISSIONS OR DATA; STATEMENTS OR CONDUCT OF ANY THIRD PARTY ON THE SITE OR SERVICE; ANY ACTIONS WE TAKE OR FAIL TO TAKE AS A RESULT OF COMMUNICATIONS YOU SEND TO US; HUMAN ERRORS; TECHNICAL MALFUNCTIONS; FAILURES, INCLUDING PUBLIC UTILITY OR TELEPHONE OUTAGES; OMISSIONS, INTERRUPTIONS, LATENCY, DELETIONS OR DEFECTS OF ANY DEVICE OR NETWORK, PROVIDERS, OR SOFTWARE (INCLUDING, BUT NOT LIMITED TO, THOSE THAT DO NOT PERMIT PARTICIPATION IN THE SERVICE); ANY INJURY OR DAMAGE TO COMPUTER EQUIPMENT; INABILITY TO FULLY ACCESS THE SITE OR SERVICE OR ANY OTHER WEBSITE; THEFT, TAMPERING, DESTRUCTION, OR UNAUTHORIZED ACCESS TO, IMAGES OR OTHER CONTENT OF ANY KIND; DATA THAT IS PROCESSED LATE OR INCORRECTLY OR IS INCOMPLETE OR LOST; TYPOGRAPHICAL, PRINTING OR OTHER ERRORS, OR ANY COMBINATION THEREOF; OR ANY OTHER MATTER RELATING TO THE SITE OR SERVICE.\n\nSOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES OR THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES. ACCORDINGLY, SOME OF THE ABOVE LIMITATIONS MAY NOT APPLY TO YOU.\n\n## 8. Our Proprietary Rights ##\n\nAll title, ownership and intellectual property rights in and to the Service are owned by MetaMask or its licensors. You acknowledge and agree that the Service contains proprietary and confidential information that is protected by applicable intellectual property and other laws. Except as expressly authorized by MetaMask, you agree not to copy, modify, rent, lease, loan, sell, distribute, perform, display or create derivative works based on the Service, in whole or in part. MetaMask issues a license for MetaMask, found [here](https://github.com/MetaMask/metamask-plugin/blob/master/LICENSE). For information on other licenses utilized in the development of MetaMask, please see our attribution page at: [https://metamask.io/attributions.html](https://metamask.io/attributions.html)\n\n## 9. Links ##\n\nThe Service provides, or third parties may provide, links to other World Wide Web or accessible sites, applications or resources. Because MetaMask has no control over such sites, applications and resources, you acknowledge and agree that MetaMask is not responsible for the availability of such external sites, applications or resources, and does not endorse and is not responsible or liable for any content, advertising, products or other materials on or available from such sites or resources. You further acknowledge and agree that MetaMask shall not be responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with use of or reliance on any such content, goods or services available on or through any such site or resource.\n\n## 10. Termination and Suspension ##\n\nMetaMask may terminate or suspend all or part of the Service and your MetaMask access immediately, without prior notice or liability, if you breach any of the terms or conditions of the Terms. Upon termination of your access, your right to use the Service will immediately cease.\n\nThe following provisions of the Terms survive any termination of these Terms: INDEMNITY; WARRANTY DISCLAIMERS; LIMITATION ON LIABILITY; OUR PROPRIETARY RIGHTS; LINKS; TERMINATION; NO THIRD PARTY BENEFICIARIES; BINDING ARBITRATION AND CLASS ACTION WAIVER; GENERAL INFORMATION.\n\n## 11. No Third Party Beneficiaries ##\n\nYou agree that, except as otherwise expressly provided in these Terms, there shall be no third party beneficiaries to the Terms.\n\n## 12. Notice and Procedure For Making Claims of Copyright Infringement ##\n\nIf you believe that your copyright or the copyright of a person on whose behalf you are authorized to act has been infringed, please provide MetaMask’s Copyright Agent a written Notice containing the following information:\n\n· an electronic or physical signature of the person authorized to act on behalf of the owner of the copyright or other intellectual property interest;\n\n· a description of the copyrighted work or other intellectual property that you claim has been infringed;\n\n· a description of where the material that you claim is infringing is located on the Service;\n\n· your address, telephone number, and email address;\n\n· a statement by you that you have a good faith belief that the disputed use is not authorized by the copyright owner, its agent, or the law;\n\n· a statement by you, made under penalty of perjury, that the above information in your Notice is accurate and that you are the copyright or intellectual property owner or authorized to act on the copyright or intellectual property owner's behalf.\n\nMetaMask’s Copyright Agent can be reached at:\n\nEmail: copyright [at] metamask [dot] io\n\nMail:\n\nAttention:\n\nMetaMask Copyright ℅ ConsenSys\n\n49 Bogart Street\n\nBrooklyn, NY 11206\n\n## 13. Binding Arbitration and Class Action Waiver ##\n\nPLEASE READ THIS SECTION CAREFULLY – IT MAY SIGNIFICANTLY AFFECT YOUR LEGAL RIGHTS, INCLUDING YOUR RIGHT TO FILE A LAWSUIT IN COURT\n\n### 13.1 Initial Dispute Resolution ###\n\nThe parties shall use their best efforts to engage directly to settle any dispute, claim, question, or disagreement and engage in good faith negotiations which shall be a condition to either party initiating a lawsuit or arbitration.\n\n### 13.2 Binding Arbitration ###\n\nIf the parties do not reach an agreed upon solution within a period of 30 days from the time informal dispute resolution under the Initial Dispute Resolution provision begins, then either party may initiate binding arbitration as the sole means to resolve claims, subject to the terms set forth below. Specifically, all claims arising out of or relating to these Terms (including their formation, performance and breach), the parties’ relationship with each other and/or your use of the Service shall be finally settled by binding arbitration administered by the American Arbitration Association in accordance with the provisions of its Commercial Arbitration Rules and the supplementary procedures for consumer related disputes of the American Arbitration Association (the \"AAA\"), excluding any rules or procedures governing or permitting class actions.\n\nThe arbitrator, and not any federal, state or local court or agency, shall have exclusive authority to resolve all disputes arising out of or relating to the interpretation, applicability, enforceability or formation of these Terms, including, but not limited to any claim that all or any part of these Terms are void or voidable, or whether a claim is subject to arbitration. The arbitrator shall be empowered to grant whatever relief would be available in a court under law or in equity. The arbitrator’s award shall be written, and binding on the parties and may be entered as a judgment in any court of competent jurisdiction.\n\nThe parties understand that, absent this mandatory provision, they would have the right to sue in court and have a jury trial. They further understand that, in some instances, the costs of arbitration could exceed the costs of litigation and the right to discovery may be more limited in arbitration than in court.\n\n### 13.3 Location ###\n\nBinding arbitration shall take place in New York. You agree to submit to the personal jurisdiction of any federal or state court in New York County, New York, in order to compel arbitration, to stay proceedings pending arbitration, or to confirm, modify, vacate or enter judgment on the award entered by the arbitrator.\n\n### 13.4 Class Action Waiver ###\n\nThe parties further agree that any arbitration shall be conducted in their individual capacities only and not as a class action or other representative action, and the parties expressly waive their right to file a class action or seek relief on a class basis. YOU AND METAMASK AGREE THAT EACH MAY BRING CLAIMS AGAINST THE OTHER ONLY IN YOUR OR ITS INDIVIDUAL CAPACITY, AND NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY PURPORTED CLASS OR REPRESENTATIVE PROCEEDING. If any court or arbitrator determines that the class action waiver set forth in this paragraph is void or unenforceable for any reason or that an arbitration can proceed on a class basis, then the arbitration provision set forth above shall be deemed null and void in its entirety and the parties shall be deemed to have not agreed to arbitrate disputes.\n\n### 13.5 Exception - Litigation of Intellectual Property and Small Claims Court Claims ###\n\nNotwithstanding the parties' decision to resolve all disputes through arbitration, either party may bring an action in state or federal court to protect its intellectual property rights (\"intellectual property rights\" means patents, copyrights, moral rights, trademarks, and trade secrets, but not privacy or publicity rights). Either party may also seek relief in a small claims court for disputes or claims within the scope of that court’s jurisdiction.\n\n### 13.6 30-Day Right to Opt Out ###\n\nYou have the right to opt-out and not be bound by the arbitration and class action waiver provisions set forth above by sending written notice of your decision to opt-out to the following address: MetaMask ℅ ConsenSys, 49 Bogart Street, Brooklyn NY 11206 and via email at support@metamask.io. The notice must be sent within 30 days of September 6, 2016 or your first use of the Service, whichever is later, otherwise you shall be bound to arbitrate disputes in accordance with the terms of those paragraphs. If you opt-out of these arbitration provisions, MetaMask also will not be bound by them.\n\n### 13.7 Changes to This Section ###\n\nMetaMask will provide 60-days’ notice of any changes to this section. Changes will become effective on the 60th day, and will apply prospectively only to any claims arising after the 60th day.\n\nFor any dispute not subject to arbitration you and MetaMask agree to submit to the personal and exclusive jurisdiction of and venue in the federal and state courts located in New York, New York. You further agree to accept service of process by mail, and hereby waive any and all jurisdictional and venue defenses otherwise available.\n\nThe Terms and the relationship between you and MetaMask shall be governed by the laws of the State of New York without regard to conflict of law provisions.\n\n## 14. General Information ##\n\n### 14.1 Entire Agreement ###\n\nThese Terms (and any additional terms, rules and conditions of participation that MetaMask may post on the Service) constitute the entire agreement between you and MetaMask with respect to the Service and supersedes any prior agreements, oral or written, between you and MetaMask. In the event of a conflict between these Terms and the additional terms, rules and conditions of participation, the latter will prevail over the Terms to the extent of the conflict.\n\n### 14.2 Waiver and Severability of Terms ###\n\nThe failure of MetaMask to exercise or enforce any right or provision of the Terms shall not constitute a waiver of such right or provision. If any provision of the Terms is found by an arbitrator or court of competent jurisdiction to be invalid, the parties nevertheless agree that the arbitrator or court should endeavor to give effect to the parties' intentions as reflected in the provision, and the other provisions of the Terms remain in full force and effect.\n\n### 14.3 Statute of Limitations ###\n\nYou agree that regardless of any statute or law to the contrary, any claim or cause of action arising out of or related to the use of the Service or the Terms must be filed within one (1) year after such claim or cause of action arose or be forever barred.\n\n### 14.4 Section Titles ###\n\nThe section titles in the Terms are for convenience only and have no legal or contractual effect.\n\n### 14.5 Communications ###\n\nUsers with questions, complaints or claims with respect to the Service may contact us using the relevant contact information set forth above and at communications@metamask.io.\n\n## 15 Related Links ##\n\n**[Terms of Use](https://metamask.io/terms.html)**\n\n**[Privacy](https://metamask.io/privacy.html)**\n\n**[Attributions](https://metamask.io/attributions.html)**\n\n","id":0},{"read":false,"date":"Mon May 08 2017","title":"Privacy Notice","body":"MetaMask is beta software. \n\nWhen you log in to MetaMask, your current account is visible to every new site you visit.\n\nFor your privacy, for now, please sign out of MetaMask when you're done using a site.\n\nAlso, by default, you will be signed in to a test network. To use real Ether, you must connect to the main network manually in the top left network menu.\n\n","id":2}]},"BlacklistController":{"phishing":{"version":2,"tolerance":2,"fuzzylist":["metamask.io","myetherwallet.com","cryptokitties.co"],"whitelist":["metahash.io","metahash.net","metahash.org","cryptotitties.com","cryptocities.net","cryptoshitties.co","cryptotitties.fun","cryptokitties.forsale","cryptokitties.care","metamate.cc","metamesh.tech","ico.nexus.social","metamesh.org","metatask.io","metmask.com","metarasa.com","metapack.com","metacase.com","metafas.nl","metamako.com","metamast.com","metamax.ru","metadesk.io","metadisk.com","metallsk.ru","metamag.fr","metamaks.ru","metamap.ru","metamaps.cc","metamats.com","metamax.by","metamax.com","metamax.io","metamuse.net","metarank.com","metaxas.com","megamas2.ru","metamask.io","myetherwallet.com","myethlerwallet.com","ethereum.org","myetheroll.com","myetherapi.com","ledgerwallet.com","databrokerdao.com","etherscan.io","etherid.org","ether.cards","etheroll.com","ethnews.com","ethex.market","ethereumdev.io","ethereumdev.kr","dether.io","ethermine.org","slaask.com","etherbtc.io","ethereal.capital","etherisc.com","m.famalk.net","etherecho.com","ethereum.os.tc","theethereum.wiki","metajack.im","etherhub.io","ethereum.network","ethereum.link","ethereum.com","prethereum.org","ethereumj.io","etheraus.com","ethereum.dev","1ethereum.ru","ethereum.nz","nethereum.com","metabank.com","metamas.com","aventus.io","metabase.com","etherdelta.com","metabase.one","cryptokitties.co"],"blacklist":["myetherwallet.uk.com","kodakone.cc","nyeihitervvallet.com","xn--myeterwalet-cm8eoi.com","nucleus.foundation","beetoken-ico.com","data-token.com","tron-labs.com","ocoin.tech","aionfoundation.com","ico-telegram.org","nyeihitervvallat.com","telegramcoin.us","daddi.cloud","daditoken.com","blockarray.org","dadi-cloud.net","wanchainfunding.org","ico-telegram.io","iconfoundation.site","iost.co","beetoken-ico.eu","cindicator.network","wanchainetwork.org","wamchain.org","wanchainltd.org","wanchainalliance.org","nucleus-vision.net","ledgerwallet.by","nucleuss.vision","myenhterswailct.com","cobin-hood.com","wanchainfoundation.org","xn--polniex-ex4c.com","xn--polniex-s1a.com","xn--polonex-ieb.com","xn--polonex-sza.com","xn--polonex-zw4c.com","xn--polonix-ws4c.com","xn--polonix-y8a.com","xn--pooniex-ojb.com","gramico.info","dimnsions.network","www-gemini.com","login-kucoin.net","venchain.foundation","grampreico.com","tgram.cc","ton-gramico.com","wwwpaywithink.com","coniomi.com","paywithnk.com","paywithlnk.com","iluminatto.com.br","pundix.eu","xn--bttrx-esay.com","xn--bttrex-w8a.com","xn--bnance-bwa.com","xn--shpeshift-11a.com","xn--shapeshif-ts6d.com","xn--shapshift-yf7d.com","wwwbluzelle.com","bluzelie.com","nucleus-vision.org","omisegonetwork.site","etlherzero.com","etlherdelta.com","xn--condesk-0ya.com","xn--condesk-sfb.com","xn--coindsk-vs4c.com","iexecplatform.com","tongramico.com","nucleus-vision.eu","intchain.network","wanchain.cloud","bluzelle-ico.com","ethzero-wallet.com","xn--metherwalle-jb9et7d.com","xn--coinesk-jo3c.com","venchainfoundation.com","myenhtersvvailot.com","ether-zero.net","ins.foundation","nastoken.org","telcointoken.com","ether0.org","eterzero.org","bluzelle-ico.eu","bleuzelle.com","appcoinstoken.org","xn--quanstamp-8s6d.com","myehntersvvailct.com","myeherwalllet.com","ico-bluzelle.com","bluzelle.im","bluzelle.one","bluzele.sale","bluzele.co","sether.ws","xn--myetherwalet-6gf.com","xn--rnyethewaliet-om1g.com","rnyethervailet.com","mvetherwaliet.com","rnyetherwailet.com","myethervaliet.com","rnyethervaliet.com","mvetherwalilet.com","xn--myethewalie-3ic0947g.com","xn--mthrwallet-z6ac3y.com","xn--myeherwalie-vici.com","xn--myethervvalie-8vc.com","xn--mythrwallt-06acf.com","xn--mtherwallet-y9a6y.com","myetherwallet.applytoken.tk","ethereum-zero.com","quanstamptoken.tk","bluzelle.network","ether-wallet.org","tron-wallet.info","appcoinsproject.com","vechain.foundation","tronlab.site","tronlabs.network","bluzelle.cc","ethblender.com","ethpaperwallet.net","waltontoken.org","icoselfkey.org","etherzeroclaim.com","etherzero.promo","bluzelle.pro","token-selfkey.org","xn--etherdlta-0f7d.com","sether.in","xn--ttrex-ysa9423c.com","bluzelle.eu","bluzelle.site","gifto.tech","xn--os-g7s.com","selfkey.co","xn--myeherwalet-ns8exy.com","xn--coinelegraph-wk5f.com","dai-stablecoin.com","eos-token.org","venchain.org","gatcoins.io","deepbrainchain.co","myetherwalililet.info","myehvterwallet.com","myehterumswallet.com","nucleusico.com","tronlab.tech","0x-project.com","gift-token-events.mywebcommunity.org","funfairtoken.org","breadtokenapp.com","cloudpetstore.com","myethwalilet.com","selfkeys.org","wallet-ethereum.com","xn--methrwallt-26ar0z.com","xn--mytherwllet-r8a0c.com","bluzelle.promo","tokensale.bluzelle.promo","cedarlake.org","marketingleads4u.com","cashaa.co","xn--inance-hrb.com","wanchain.tech","zenprolocol.com","ethscan.io","etherscan.in","props-project.com","zilliaq.com","reqestnetwork.com","etherdelta.pw","ethereum-giveaway.org","mysimpletoken.org","binancc.com","blnance.org","elherdelta.io","xn--hapeshit-ez9c2y.com","tenxwallet.co","singularitynet.info","mytlherwaliet.info","iconmainnet.ml","tokenselfkey.org","xn--myetewallet-cm8e5y.com","envione.org","myetherwalletet.com","claimbcd.com","ripiocreditnetwork.in","xn--yeterwallet-ml8euo.com","ethclassicwallet.info","myltherwallet.ru.com","etherdella.com","xn--yeterwallet-bm8ewn.com","singularty.net","cloudkitties.co","iconfoundation.io","kittystat.com","gatscoin.io","singularitynet.in","sale.canay.io","canay.io","wabicoin.co","envion.top","sirinslabs.com","tronlab.co","paxful.com.ng","changellyli.com","ethereum-code.com","xn--plonex-6va6c.com","envion.co","envion.cc","envion.site","ethereumchain.info","xn--envon-1sa.org","xn--btstamp-rfb.net","envlon.org","envion-ico.org","spectivvr.org","sirinlbs.com","ethereumdoubler.life","xn--myetherwllet-fnb.com","sirin-labs.com","sirin-labs.org","envion.one","envion.live","propsproject.org","propsprojects.com","decentralland.org","xn--metherwalet-ns8ep4b.com","redpulsetoken.co","propsproject.tech","xn--myeterwalet-nl8emj.com","powrerledger.com","cryptokitties.com","sirinlabs.pro","sirinlabs.co","sirnlabs.com","superbitcoin-blockchain.info","hellobloom.me","mobus.network","powrrledger.com","xn--myeherwalet-ms8eyy.com","qlink-ico.com","gatcoin.in","tokensale.gamefllp.com","gamefllp.com","xn--myeherwalle-vici.com","xn--myetherwalet-39b.com","xn--polonex-ffb.com","xn--birex-leba.com","raiden-network.org","sirintabs.com","xn--metherwallt-79a30a.com","xn--myethrwllet-2kb3p.com","myethlerwallet.eu","xn--btrex-b4a.com","powerrledger.com","xn--cointeegraph-wz4f.com","myerherwalet.com","qauntstanp.com","myetherermwallet.com","xn--myethewalet-ns8eqq.com","xn--nvion-hza.org","nnyetherwallelt.ru.com","ico-wacoin.com","xn--myeterwalet-nl8enj.com","bitcoinsilver.io","t0zero.com","tokensale.gizer.in","gizer.in","wabitoken.com","gladius.ws","xn--metherwallt-8bb4w.com","quanttstamp.com","gladius.im","ethereumstorage.net","powerledgerr.com","xn--myeherwallet-4j5f.com","quamtstamp.com","quntstamp.com","xn--changely-j59c.com","shapeshlft.com","coinbasenews.co.uk","xn--metherwallet-hmb.com","envoin.org","powerledger.com","bitstannp.net","xn--myetherallet-4k5fwn.com","xn--coinbas-pya.com","requestt.network","oracls.network","sirinlabs.website","powrledger.io","slackconfirm.com","shape-shift.io","oracles-network.org","xn--myeherwalle-zb9eia.com","blockstack.one","urtust.io","bittrex.one","t0-ico.com","xn--cinbase-90a.com","xn--metherwalet-ns8ez1g.com","tzero-ico.com","tzero.su","tzero.website","blockstack.network","ico-tzero.com","spectre.site","tzero.pw","spectre-ai.net","xn--waxtokn-y8a.com","dmarket.pro","bittrex.com11648724328774.cf","bittrex.com1987465798.ga","autcus.org","t-zero.org","xn--zero-zxb.com","myetherwalletfork.com","blokclbain.info","datum.sale","spectre-ai.org","powerledgr.com","simpletoken.live","sale.simpletoken.live","qauntstamp.com","raiden-network.com","metalpayme.com","quantstamp-ico.com","myetherwailetclient.com","biockchain.biz","wallets-blockchain.com","golemairdrop.com","omisegoairdrop.net","blodkchainwallet.info","walton-chain.org","elite888-ico.com","bitflyerjp.com","chainlinksmartcontract.com","stormtoken.eu","omise-go.tech","saltending.com","stormltoken.com","xn--quanttamp-42b.com","stormtoken.co","storntoken.com","stromtoken.com","storm-token.com","stormtokens.io","ether-delta.com","ethconnect.live","ethconnect.trade","xn--bttrex-3va.net","quantstamp.com.co","wancha.in","augur-network.com","quantstamp.com.ua","myetherwalletmew.com","myetherumwalletts.com","xn--quanstamp-tmd.com","quantsstamps.com","changellyl.net","xn--myetherwalet-1fb.com","myethereumwallets.com","xn--myetherwalet-e9b.com","quantslamp.com","metelpay.com","xn--eterdelta-m75d.com","linksmartcontract.com","myetherwalletaccess.com","myetherwalletcheck.com","myetherwalletcheck.info","myetherwalletconf.com","myetherwalleteal.com","myetherwalletec.com","myetherwalletgeth.com","myetherwalletmetamask.com","myetherwalletmm.com","myetherwalletmy.com","myetherwalletnh.com","myetherwalletnod.com","myetherwalletrr.com","myetherwalletrty.com","myetherwalletsec.com","myetherwalletsecure.com","myetherwalletutc.com","myetherwalletver.info","myetherwalletview.com","myetherwalletview.info","myetherwalletvrf.com","myetherwalletmist.com","myetherwalletext.com","myetherwalletjson.com","mettalpay.com","bricklblock.io","bittrexy.com","utrust.so","myethierwallet.org","metallpay.com","kraken-wallet.com","dmarkt.io","etherdeltla.com","unlversa.io","universa.sale","mercuryprotocol.live","ripiocredlt.network","myetlherwa11et.com","dentacoin.in","rdrtg.com","myetherwallet.com.rdrgh.com","rdrgh.com","ripiocreditnetwork.co","riaden.network","hydrominer.biz","rdrblock.com","reqest.network","senstoken.com","myetherwallat.services","ripiocredit.net","xn--metherwallet-c06f.com","ico.ripiocredits.com","ripiocredits.com","raidens.network","artoken.co","myetherwalletlgn.com","etherblog.click","stormtoken.site","httpmyetherwallet.com","myetherwalletverify.com","byzantiumfork.com","myetherwallet.com.byzantiumfork.com","www-myethervvallet.com","ether24.info","block-v.io","bittrex.cash","shapishift.io","ripiocerdit.network","rnyetherwa11et.com","claimether.com","enigmatokensale.com","ethereum-org.com","mvetnerwallet.com","myctherwallet.com","myetherwaltet.com","myetherwatlet.com","privatix.me","myetherwalletcnf.com","myetherwalletver.com","privatix.top","privatix.pro","privatex.io","stormtoken.cc","raiden.online","stormstoken.com","myetereumwallet.com","stormtokens.net","myetherwalletconf.info","storrntoken.com","worldofbattles.io","ico.worldofbattles.io","privatix.live","riden.network","raidan.network","ralden.network","mymyetherwallet.com","myetherwallets.net","myetherwalletverify.info","stormxtoken.com","myethereum-wallet.com","myetherwallet-forkprep.pagedemo.co","myetnerwailet.com","www-mvetherwallet.com","etheirdelta.com","myetherwalletiu.com","myetherwaiiett.com","xn--mytherwalet-cbb87i.com","xn--myethrwallet-ivb.co","xn--myeterwallet-f1b.com","myehterwaliet.com","omegaone.co","myetherwaiietw.com","slack.com.ru","polkodot.network","request-network.net","requestnetwork.live","binancie.com","first-eth.info","myewerthwalliet.com","enjincoin.pw","xn--bitrex-k17b.com","alrswap.io","www-request.network","myetnenwallet.com","www-enigma.co","cryptoinsidenews.com","air-swap.tech","launch.airswap.cc","airswap.cc","airswaptoken.com","launch.airswap.in","airswap.in","security-steemit.com.mx","blockchalnwallet.com","blodkchainwallet.com","blodkchaln.com","myethereumwaiiet.com","myethereumwaliet.com","myethereumwalilet.com","myetherswailet.com","myetherswaliet.com","myetherswalilet.com","myetherwalilett.com","myetherwalletl.com","myetherwalletww.com","myethereunwallet.com","myethereumwallct.com","myetherwaiieti.com","myetherwaiiete.com","upfirng.com","paypie.net","paypie.tech","soam.co","myetherwaiict.com","numerai-token.com","www-bankera.com","vvanchain.org","omisegoairdrop.com","xn--enjncoin-41a.io","suncontract.su","myetherwaiietr.com","shapeshiff.io","warchain.org","myethwallett.com","myethervvaliet.com","wanchains.org","etherparty.in","enjincoin.me","etiam.io","invest.smartlands.tech","smartlands.tech","enijncoin.io","wanchain.network","nimiq.su","enjincoin.sale","tenxwallet.io","golem-network.net","myyethwallet.ml","mywetherwailiet.com","omg-omise.com","district0x.tech","centra-token.com","etherdetla.com","etnerparty.io","etherdelta.su","myetherwallett.neocities.org","myetherwallet-secure.com","myethereumwalletntw.info","real-markets.io","wallet-ethereum.org","request-network.com","shapeshifth.io","shiapeshift.in","coin.red-puise.com","ibittreix.com","coinkbase.com","cindicator.pro","myetherwallet.com.ailogin.me","eventchain.co","kinkik.in","myetherumwalletview.com","protostokenhub.com","coinrbase.com","myetherwalletlogin.com","omisegotoken.com","myethereumwalletntw.com","reall.markets","cobinhood.org","cobinhood.io","happy-coin.org","bitfinex.com.co","bitfienex.com","iconn.foundation","centra.vip","smartcontract.live","icon.community","air-token.com","centra.credit","myetherwallet-singin.com","smartcontractlink.com","shapesshift.io","0xtoken.io","augurproject.co","ethereumus.one","myetherumwalet.com","myetherwalletsignin.com","change-bank.org","charge-bank.com","myetherwalletsingin.com","myetherwalletcontract.com","change-bank.io","chainlink.tech","myetherwallet-confirm.com","tokensale.kybernet.network","kybernet.network","kyberr.network","kybernetwork.io","myetherwalletconfirm.com","kvnuke.github.io","kin.kikpro.co","myethereumwallet.co.uk","tokensale-kyber.network","kyber-network.co","tokensale.kyber-network.co","pyro0.github.io","tokensale.kyber.digital","kyber.digital","omise-go.me","my.etherwallet.com.de","bepartof.change-bank.co","change-bank.co","enigma-tokens.co","coinbase.com.eslogin.co","xn--bittrx-mva.com","ethrdelta.github.io","etherdellta.com","ico-nexus.social","red-pulse.tech","bitj0b.io","xn--bttrex-bwa.com","kin-klk.com","kin-crowdsale.com","ethedelta.com","coindash.su","myethwallet.co.uk","swarm.credit","myethereumwallet.uk","iconexu.social","wanchain.co","enigrna.co","linknetwork.co","qtum-token.com","omisego.com.co","rivetzintl.org","etherdelta.one","the-ether.pro","etherdelta.gitnub.io","kirkik.com","monetha.ltd","vlberate.io","ethereumwallet-kr.info","omise-go.org","iconexus.social","bittirrex.com","aventus.pro","atlant.solutions","aventus.group","metamak.io","omise.com.co","herotokens.io","starbase.pro","etherdelta.githulb.io","herotoken.co","kinico.net","dmarket.ltd","etherdelta.gilthub.io","golem-network.com","etnerscan.io","bllttriex.com","monetha.me","monetha.co","monetha-crowdsale.com","starbase.tech","aventus-crowdsale.com","shapeshift.pro","bllttrex.com","kickico.co","statustoken.im","bilttrex.com","tenxpay.io","bittrex.ltd","metalpay.im","aragon.im","coindash.tech","decentraland.tech","decentraland.pro","status-token.com","bittrex.cam","enigmatoken.com","unocoin.company","unocoin.fund","0xproject.io","0xtoken.com","numerai.tech","decentraiand.org","blockcrein.info","blockchealn.info","bllookchain.info","blockcbhain.info","myetherwallet.com.ethpromonodes.com","mettamask.io","tokenswap.org","netherum.com","etherexx.org","etherume.io","ethereum.plus","ehtereum.org","etereurm.org","etheream.com","ethererum.org","ethereum.io","etherdelta-glthub.com","cryptoalliance.herokuapp.com","bitspark2.com","indorsetoken.com","iconexus.tk","iconexus.ml","iconexus.ga","iconexus.cf","etherwallet.online","wallet-ethereum.net","bitsdigit.com","etherswap.org","eos.ac","uasfwallet.com","ziber.io","multiply-ethereum.info","bittrex.comze.com","karbon.vacau.com","etherdelta.gitlhub.io","etherdelta.glthub.io","digitaldevelopersfund.vacau.com","district-0x.io","coin-dash.com","coindash.ru","district0x.net","aragonproject.io","coin-wallet.info","coinswallet.info","contribute-status.im","ether-api.com","ether-wall.com","mycoinwallet.net","ethereumchamber.com","ethereumchamber.net","ethereumchest.com","ethewallet.com","myetherwallet.com.vc","myetherwallet.com.pe","myetherwallet.us.com","myetherwallet.com.u0387831.cp.regruhosting.ru","myethereumwallet.su","myetherweb.com.de","myetherieumwallet.com","myetehrwallet.com","myeterwalet.com","myetherwaiiet.com","myetherwallet.info","myetherwallet.ch","myetherwallet.om","myethervallet.com","myetherwallet.com.cm","myetherwallet.com.co","myetherwallet.com.de","myetherwallet.com.gl","myetherwallet.com.im","myetherwallet.com.ua","secure-myetherwallet.com","update-myetherwallet.com","wwwmyetherwallet.com","myeatherwallet.com","myetharwallet.com","myelherwallel.com","myetherwaillet.com","myetherwaliet.com","myetherwallel.com","myetherwallet.cam","myetherwallet.cc","myetherwallet.co","myetherwallet.cm","myetherwallet.cz","myetherwallet.org","myetherwallet.tech","myetherwallet.top","myetherwallet.net","myetherwallet.ru.com","myetherwallet.com.ru","metherwallet.com","myetrerwallet.com","myetlerwallet.com","myethterwallet.com","myethwallet.io","myethterwallet.co","myehterwallet.co","myaetherwallet.com","myetthterwallet.com","myetherwallet.one","myelterwallet.com","myetherwallet.gdn","myetherwallt.com","myeterwallet.com","myeteherwallet.com","myethearwailet.com","myetherwallelt.com","myetherwallett.com","etherwallet.org","myetherewallet.com","myeherwallet.com","myethcrwallet.com","myetherwallet.link","myetherwallets.com","myethearwaillet.com","myethearwallet.com","myetherawllet.com","myethereallet.com","myetherswallet.com","myetherwalet.com","myetherwaller.com","myetherwalliet.com","myetherwllet.com","etherwallet.io","myetherwallet.ca","myetherwallet.me","myetherwallet.ru","myetherwallet.xyz","myetherwallte.com","myethirwallet.com","myethrewallet.com","etherwallet.net","maetherwallet.com","meyetherwallet.com","my.ether-wallet.pw","myehterwallet.com","myeitherwallet.com","myelherwallet.com","myeltherwallet.com","myerherwallet.com","myethearwalet.com","myetherewalle.com","myethervvallet.com","myetherwallent.com","myetherwallet.fm","myetherwalllet.com","myetherwalltet.com","myetherwollet.com","myetlherwalet.com","myetlherwallet.com","rnyetherwallet.com","etherclassicwallet.com","omg-omise.co","omise-go.com","omise-go.net","omise-omg.com","omise-go.io","tenx-tech.com","bitclaive.com","tokensale-tenx.tech","ubiqcoin.org","metamask.com","ethtrade.io","myetcwallet.com","account-kigo.net","bitcoin-wallet.net","blocklichan.info","bloclkicihan.info","coindash.ml","eos-bonus.com","eos-io.info","ether-wallet.net","ethereum-wallet.info","ethereum-wallet.net","ethereumchest.net","reservations-kigo.net","reservations-lodgix.com","secure-liverez.com","secure-onerooftop.com","settings-liverez.com","software-liverez.com","software-lodgix.com","unhackableetherwallets.com","www-myetherwallet.com","etherwallet.co.za","etherwalletchain.com","etherwallets.net","etherwallets.nl","my-ethwallet.com","my.ether-wallet.co","myetherwallet.com.am","myetherwallet.com.ht","myetherwalletcom.com","myehterwailet.com","xn--myetherwalle-xoc.com","xn--myetherwalle-44i.com","xn--myetherwalle-xhk.com","xn--myetherwallt-cfb.com","xn--myetherwallt-6tb.com","xn--myetherwallt-xub.com","xn--myetherwallt-ovb.com","xn--myetherwallt-fwb.com","xn--myetherwallt-5wb.com","xn--myetherwallt-jzi.com","xn--myetherwallt-2ck.com","xn--myetherwallt-lok.com","xn--myetherwallt-lsl.com","xn--myetherwallt-ce6f.com","xn--myetherwalet-mcc.com","xn--myetherwalet-xhf.com","xn--myetherwalet-lcc.com","xn--myetherwaet-15ba.com","xn--myetherwalet-whf.com","xn--myetherwaet-v2ea.com","xn--myetherwllet-59a.com","xn--myetherwllet-jbb.com","xn--myetherwllet-wbb.com","xn--myetherwllet-9bb.com","xn--myetherwllet-ncb.com","xn--myetherwllet-0cb.com","xn--myetherwllet-5nb.com","xn--myetherwllet-ktd.com","xn--myetherwllet-mre.com","xn--myetherwllet-76e.com","xn--myetherwllet-o0l.com","xn--myetherwllet-c45f.com","xn--myetherallet-ejn.com","xn--myethewallet-4nf.com","xn--myethewallet-iof.com","xn--myethewallet-mpf.com","xn--myethewallet-6bk.com","xn--myethewallet-i31f.com","xn--myethrwallet-feb.com","xn--myethrwallt-fbbf.com","xn--myethrwallet-seb.com","xn--myethrwallt-rbbf.com","xn--myethrwallet-5eb.com","xn--myethrwallt-3bbf.com","xn--myethrwallet-0tb.com","xn--myethrwallt-tpbf.com","xn--myethrwallet-rub.com","xn--myethrwallt-iqbf.com","xn--myethrwallet-ivb.com","xn--myethrwallt-6qbf.com","xn--myethrwallet-8vb.com","xn--myethrwallt-vrbf.com","xn--myethrwallet-zwb.com","xn--myethrwallt-ksbf.com","xn--myethrwallet-dzi.com","xn--myethrwallt-wbif.com","xn--myethrwallet-wck.com","xn--myethrwallt-skjf.com","xn--myethrwallet-fok.com","xn--myethrwallt-fvjf.com","xn--myethrwallet-fsl.com","xn--myethrwallt-fwkf.com","xn--myethrwallet-5d6f.com","xn--myethrwallt-319ef.com","xn--myeterwallet-ufk.com","xn--myeterwallet-nrl.com","xn--myeterwallet-von.com","xn--myeterwallet-jl6c.com","xn--myeherwallet-ooc.com","xn--myeherwalle-6hci.com","xn--myeherwallet-v4i.com","xn--myeherwalle-zgii.com","xn--myeherwallet-ohk.com","xn--myeherwalle-6oji.com","xn--mytherwallet-ceb.com","xn--mythrwallet-cbbc.com","xn--mythrwallt-c7acf.com","xn--mytherwallet-peb.com","xn--mythrwallet-obbc.com","xn--mythrwallt-n7acf.com","xn--mytherwallet-2eb.com","xn--mythrwallet-0bbc.com","xn--mythrwallt-y7acf.com","xn--mytherwallet-xtb.com","xn--mythrwallet-qpbc.com","xn--mythrwallt-jlbcf.com","xn--mytherwallet-oub.com","xn--mythrwallet-fqbc.com","xn--mythrwallt-5lbcf.com","xn--mythrwallet-3qbc.com","xn--mythrwallt-smbcf.com","xn--mytherwallet-5vb.com","xn--mythrwallet-srbc.com","xn--mythrwallt-fnbcf.com","xn--mytherwallet-wwb.com","xn--mythrwallet-hsbc.com","xn--mythrwallt-1nbcf.com","xn--mytherwallet-9yi.com","xn--mythrwallet-tbic.com","xn--mythrwallt-dnhcf.com","xn--mytherwallet-tck.com","xn--mythrwallet-pkjc.com","xn--mythrwallt-lsicf.com","xn--mytherwallet-cok.com","xn--mythrwallet-cvjc.com","xn--mythrwallt-c2icf.com","xn--mytherwallet-csl.com","xn--mythrwallet-cwkc.com","xn--mythrwallt-c0jcf.com","xn--mytherwallet-2d6f.com","xn--mythrwallet-019ec.com","xn--mythrwallt-yq3ecf.com","xn--metherwallet-qlb.com","xn--metherwallet-1uf.com","xn--metherwallet-iyi.com","xn--metherwallet-zhk.com","xn--metherwallet-3ml.com","xn--mytherwallet-fvb.com","xn--myetherwallt-7db.com","xn--myetherwallt-leb.com","xn--myetherwallt-yeb.com","xn--yetherwallet-vjf.com","xn--yetherwallet-dfk.com","xn--yetherwallet-1t1f.com","xn--yetherwallet-634f.com","xn--myeherwallet-fpc.com","xn--myethewallt-crb.com","xn--metherwallet-1vc.com","xn--myeherwallt-kbb8039g.com","xn--myeherwallet-vk5f.com","xn--yethewallet-iw8ejl.com","xn--bittrx-th8b.com","xn--polniex-n0a.com","thekey.vin","thekey-vip.com","digitexftures.com","ethzero-wallet.org","zeepln.io","wepowers.network","wepower.vision"]}},"CurrencyController":{"currentCurrency":"usd","conversionRate":1112,"conversionDate":1517351401}}} -- cgit v1.2.3 From 2fffe098736e2461b9238c7dcd91f9ef3d61dcc1 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Thu, 12 Jul 2018 20:43:43 -0400 Subject: detect tokens through infura --- test/unit/app/controllers/detect-tokens-test.js | 26 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'test') diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js index dca48c6bb..860ed7050 100644 --- a/test/unit/app/controllers/detect-tokens-test.js +++ b/test/unit/app/controllers/detect-tokens-test.js @@ -1,8 +1,8 @@ const assert = require('assert') const sinon = require('sinon') const DetectTokensController = require('../../../../app/scripts/controllers/detect-tokens') +const NetworkController = require('../../../../app/scripts/controllers/network/network') const PreferencesController = require('../../../../app/scripts/controllers/preferences') -const ObservableStore = require('obs-store') describe('DetectTokensController', () => { const sandbox = sinon.createSandbox() @@ -22,7 +22,8 @@ describe('DetectTokensController', () => { it('should be called on every polling period', async () => { clock = sandbox.useFakeTimers() - const network = new ObservableStore({provider: {type: 'mainnet'}}) + const network = new NetworkController() + network.setProviderType('mainnet') const preferences = new PreferencesController() const controller = new DetectTokensController({preferences: preferences, network: network}) controller.isActive = true @@ -40,7 +41,8 @@ describe('DetectTokensController', () => { }) it('should not check tokens while in test network', async () => { - var network = new ObservableStore({provider: {type: 'rinkeby'}}) + const network = new NetworkController() + network.setProviderType('rinkeby') const preferences = new PreferencesController() const controller = new DetectTokensController({preferences: preferences, network: network}) controller.isActive = true @@ -54,14 +56,17 @@ describe('DetectTokensController', () => { }) it('should only check and add tokens while in main network', async () => { - const network = new ObservableStore({provider: {type: 'mainnet'}}) + const network = new NetworkController() + network.setProviderType('mainnet') const preferences = new PreferencesController() const controller = new DetectTokensController({preferences: preferences, network: network}) controller.isActive = true sandbox.stub(controller, 'detectTokenBalance') - .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4').returns(true) - .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388').returns(true) + .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4') + .returns(preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8)) + .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388') + .returns(preferences.addToken('0xbc86727e770de68b1060c91f6bb6945c73e10388', 'XNK', 18)) await controller.exploreNewTokens() assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, @@ -69,15 +74,18 @@ describe('DetectTokensController', () => { }) it('should not detect same token while in main network', async () => { - const network = new ObservableStore({provider: {type: 'mainnet'}}) + const network = new NetworkController() + network.setProviderType('mainnet') const preferences = new PreferencesController() preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8) const controller = new DetectTokensController({preferences: preferences, network: network}) controller.isActive = true sandbox.stub(controller, 'detectTokenBalance') - .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4').returns(true) - .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388').returns(true) + .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4') + .returns(preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8)) + .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388') + .returns(preferences.addToken('0xbc86727e770de68b1060c91f6bb6945c73e10388', 'XNK', 18)) await controller.exploreNewTokens() assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, -- cgit v1.2.3 From 41879a983582c832fe3b6b19df3c057a1cc13d2a Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Mon, 16 Jul 2018 16:08:19 -0400 Subject: added test for preferences controller --- .../app/controllers/preferences-controller-test.js | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'test') diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js index e5e751b57..e055500b1 100644 --- a/test/unit/app/controllers/preferences-controller-test.js +++ b/test/unit/app/controllers/preferences-controller-test.js @@ -52,6 +52,31 @@ describe('preferences controller', function () { }) }) + describe('removeAddress', function () { + it('should remove an address from state', function () { + preferencesController.setAddresses([ + '0xda22le', + '0x7e57e2', + ]) + + preferencesController.removeAddress('0xda22le') + + assert.equal(preferencesController.store.getState().identities['0xda22le'], undefined) + }) + + it('should switch accounts if the selected address is removed', function () { + preferencesController.setAddresses([ + '0xda22le', + '0x7e57e2', + ]) + + preferencesController.setSelectedAddress('0x7e57e2') + preferencesController.removeAddress('0x7e57e2') + + assert.equal(preferencesController.getSelectedAddress(), '0xda22le') + }) + }) + describe('setAccountLabel', function () { it('should update a label for the given account', function () { preferencesController.setAddresses([ -- cgit v1.2.3 From e5512c306ded1d2a521a0ba0d2c3cdd5878e53bb Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Mon, 16 Jul 2018 19:36:08 -0400 Subject: added unit tests for metamaskcontroller --- .../app/controllers/metamask-controller-test.js | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'test') diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 0dda4609b..bef126f1f 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -222,6 +222,76 @@ describe('MetaMaskController', function () { }) }) + describe('connectHardware', function () { + + it('should throw if it receives an unknown device name', async function () { + try { + await metamaskController.connectHardware('Some random device name', 0) + } catch (e) { + assert.equal(e, 'Error: MetamaskController:connectHardware - Unknown device') + } + }) + + it('should add the Trezor Hardware keyring', async function () { + await metamaskController.connectHardware('trezor', 0).catch((e) => null) + const keyrings = await metamaskController.keyringController.getKeyringsByType( + 'Trezor Hardware' + ) + assert.equal(keyrings.length, 1) + }) + + }) + + describe('checkHardwareStatus', function () { + it('should throw if it receives an unknown device name', async function () { + try { + await metamaskController.checkHardwareStatus('Some random device name') + } catch (e) { + assert.equal(e, 'Error: MetamaskController:checkHardwareStatus - Unknown device') + } + }) + + it('should be locked by default', async function () { + await metamaskController.connectHardware('trezor', 0).catch((e) => null) + const status = await metamaskController.checkHardwareStatus('trezor') + assert.equal(status, false) + }) + }) + + describe('forgetDevice', function () { + it('should throw if it receives an unknown device name', async function () { + try { + await metamaskController.forgetDevice('Some random device name') + } catch (e) { + assert.equal(e, 'Error: MetamaskController:forgetDevice - Unknown device') + } + }) + + it('should wipe all the keyring info', async function () { + await metamaskController.connectHardware('trezor', 0).catch((e) => null) + await metamaskController.forgetDevice('trezor') + const keyrings = await metamaskController.keyringController.getKeyringsByType( + 'Trezor Hardware' + ) + + assert.deepEqual(keyrings[0].accounts, []) + assert.deepEqual(keyrings[0].page, 0) + assert.deepEqual(keyrings[0].isUnlocked(), false) + }) + }) + + describe('unlockTrezorAccount', function () { + it('should set accountToUnlock in the keyring', async function () { + await metamaskController.connectHardware('trezor', 0).catch((e) => null) + const accountToUnlock = 10 + await metamaskController.unlockTrezorAccount(accountToUnlock).catch((e) => null) + const keyrings = await metamaskController.keyringController.getKeyringsByType( + 'Trezor Hardware' + ) + assert.equal(keyrings[0].unlockedAccount, accountToUnlock) + }) + }) + describe('#setCustomRpc', function () { const customRPC = 'https://custom.rpc/' let rpcTarget -- cgit v1.2.3 From 4737ea49c72b24a712b7c3215bed93383ce3ad81 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Mon, 16 Jul 2018 17:09:57 -0700 Subject: Increase clickable area and padding of Retry Transaction bar --- test/integration/lib/tx-list-items.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/integration/lib/tx-list-items.js b/test/integration/lib/tx-list-items.js index 6b67b1d2e..b7aca44d5 100644 --- a/test/integration/lib/tx-list-items.js +++ b/test/integration/lib/tx-list-items.js @@ -31,8 +31,8 @@ async function runTxListItemsTest (assert, done) { assert.equal($(unapprovedTx).hasClass('tx-list-pending-item-container'), true, 'unapprovedTx has the correct class') const retryTx = txListItems[1] - const retryTxLink = await findAsync($(retryTx), '.tx-list-item-retry-link') - assert.equal(retryTxLink[0].textContent, 'Increase the gas price on your transaction', 'retryTx has expected link') + const retryTxLink = await findAsync($(retryTx), '.tx-list-item-retry-container span') + assert.equal(retryTxLink[0].textContent, 'Taking too long? Increase the gas price on your transaction', 'retryTx has expected link') const approvedTx = txListItems[2] const approvedTxRenderedStatus = await findAsync($(approvedTx), '.tx-list-status') -- cgit v1.2.3 From de4265c629f8e68d882c2ded0e20417327cf4d2f Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Tue, 17 Jul 2018 01:17:18 -0400 Subject: added more unit tests --- .../app/controllers/metamask-controller-test.js | 57 +++++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index bef126f1f..a08371f86 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -233,10 +233,12 @@ describe('MetaMaskController', function () { }) it('should add the Trezor Hardware keyring', async function () { + sinon.spy(metamaskController.keyringController, 'addNewKeyring') await metamaskController.connectHardware('trezor', 0).catch((e) => null) const keyrings = await metamaskController.keyringController.getKeyringsByType( 'Trezor Hardware' ) + assert.equal(metamaskController.keyringController.addNewKeyring.getCall(0).args, 'Trezor Hardware') assert.equal(keyrings.length, 1) }) @@ -281,15 +283,66 @@ describe('MetaMaskController', function () { }) describe('unlockTrezorAccount', function () { - it('should set accountToUnlock in the keyring', async function () { + let accountToUnlock + let windowOpenStub + let addNewAccountStub + let getAccountsStub + beforeEach(async function () { + accountToUnlock = 10 + windowOpenStub = sinon.stub(window, 'open') + windowOpenStub.returns(noop) + + addNewAccountStub = sinon.stub(metamaskController.keyringController, 'addNewAccount') + addNewAccountStub.returns({}) + + getAccountsStub = sinon.stub(metamaskController.keyringController, 'getAccounts') + // Need to return different address to mock the behavior of + // adding a new account from the keyring + getAccountsStub.onCall(0).returns(Promise.resolve(['0x1'])) + getAccountsStub.onCall(1).returns(Promise.resolve(['0x2'])) + getAccountsStub.onCall(2).returns(Promise.resolve(['0x3'])) + getAccountsStub.onCall(3).returns(Promise.resolve(['0x4'])) + sinon.spy(metamaskController.preferencesController, 'setAddresses') + sinon.spy(metamaskController.preferencesController, 'setSelectedAddress') + sinon.spy(metamaskController.preferencesController, 'setAccountLabel') await metamaskController.connectHardware('trezor', 0).catch((e) => null) - const accountToUnlock = 10 await metamaskController.unlockTrezorAccount(accountToUnlock).catch((e) => null) + }) + + afterEach(function () { + metamaskController.keyringController.addNewAccount.restore() + window.open.restore() + }) + + it('should set accountToUnlock in the keyring', async function () { const keyrings = await metamaskController.keyringController.getKeyringsByType( 'Trezor Hardware' ) assert.equal(keyrings[0].unlockedAccount, accountToUnlock) }) + + + it('should call keyringController.addNewAccount', async function () { + assert(metamaskController.keyringController.addNewAccount.calledOnce) + }) + + it('should call keyringController.getAccounts ', async function () { + assert(metamaskController.keyringController.getAccounts.called) + }) + + it('should call preferencesController.setAddresses', async function () { + assert(metamaskController.preferencesController.setAddresses.calledOnce) + }) + + it('should call preferencesController.setSelectedAddress', async function () { + assert(metamaskController.preferencesController.setSelectedAddress.calledOnce) + }) + + it('should call preferencesController.setAccountLabel', async function () { + assert(metamaskController.preferencesController.setAccountLabel.calledOnce) + }) + + }) describe('#setCustomRpc', function () { -- cgit v1.2.3 From e89350b19fdac56968303e5c48806a4605fb4b22 Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Tue, 17 Jul 2018 01:44:28 -0400 Subject: added tests for removeAccount --- .../app/controllers/metamask-controller-test.js | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'test') diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index a08371f86..9164fe246 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -485,6 +485,39 @@ describe('MetaMaskController', function () { }) }) + describe('#removeAccount', function () { + let ret + const addressToRemove = '0x1' + + beforeEach(async function () { + sinon.stub(metamaskController.preferencesController, 'removeAddress') + sinon.stub(metamaskController.accountTracker, 'removeAccount') + sinon.stub(metamaskController.keyringController, 'removeAccount') + + ret = await metamaskController.removeAccount(addressToRemove) + + }) + + afterEach(function () { + metamaskController.keyringController.removeAccount.restore() + metamaskController.accountTracker.removeAccount.restore() + metamaskController.preferencesController.removeAddress.restore() + }) + + it('should call preferencesController.removeAddress', async function () { + assert(metamaskController.preferencesController.removeAddress.calledWith(addressToRemove)) + }) + it('should call accountTracker.removeAccount', async function () { + assert(metamaskController.accountTracker.removeAccount.calledWith(addressToRemove)) + }) + it('should call keyringController.removeAccount', async function () { + assert(metamaskController.keyringController.removeAccount.calledWith(addressToRemove)) + }) + it('should return address', async function () { + assert.equal(ret, '0x1') + }) + }) + describe('#clearSeedWordCache', function () { it('should have set seed words', function () { -- cgit v1.2.3 From e16f5ab54d1e69e59fe4689fde3fa34e61c88974 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Sat, 14 Jul 2018 23:36:42 -0700 Subject: Fix tests --- test/e2e/beta/metamask-beta-ui.spec.js | 16 ++++---- test/unit/components/pending-tx-test.js | 67 --------------------------------- 2 files changed, 8 insertions(+), 75 deletions(-) delete mode 100644 test/unit/components/pending-tx-test.js (limited to 'test') diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index caa49d450..ee1aa0ff1 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -513,7 +513,7 @@ describe('MetaMask', function () { it('displays the contract creation data', async () => { const dataTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Data')]`)) dataTab.click() - await (regularDelayMs) + await delay(regularDelayMs) await findElement(driver, By.xpath(`//div[contains(text(), '127.0.0.1')]`)) @@ -523,7 +523,7 @@ describe('MetaMask', function () { const detailsTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Details')]`)) detailsTab.click() - await (regularDelayMs) + await delay(regularDelayMs) }) it('confirms a deploy contract transaction', async () => { @@ -548,7 +548,7 @@ describe('MetaMask', function () { await delay(regularDelayMs) await driver.switchTo().window(extension) - await delay(regularDelayMs) + await delay(largeDelayMs) await findElements(driver, By.css('.tx-list-pending-item-container')) const [txListValue] = await findElements(driver, By.css('.tx-list-value')) @@ -741,7 +741,7 @@ describe('MetaMask', function () { it('displays the token transfer data', async () => { const dataTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Data')]`)) dataTab.click() - await (regularDelayMs) + await delay(regularDelayMs) const functionType = await findElement(driver, By.css('.confirm-page-container-content__function-type')) const functionTypeText = await functionType.getText() @@ -753,7 +753,7 @@ describe('MetaMask', function () { const detailsTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Details')]`)) detailsTab.click() - await (regularDelayMs) + await delay(regularDelayMs) }) it('submits the transaction', async function () { @@ -901,7 +901,7 @@ describe('MetaMask', function () { it('displays the token approval data', async () => { const dataTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Data')]`)) dataTab.click() - await (regularDelayMs) + await delay(regularDelayMs) const functionType = await findElement(driver, By.css('.confirm-page-container-content__function-type')) const functionTypeText = await functionType.getText() @@ -913,12 +913,12 @@ describe('MetaMask', function () { const detailsTab = await findElement(driver, By.xpath(`//li[contains(text(), 'Details')]`)) detailsTab.click() - await (regularDelayMs) + await delay(regularDelayMs) const approvalWarning = await findElement(driver, By.css('.confirm-page-container-warning__warning')) const approvalWarningText = await approvalWarning.getText() assert(approvalWarningText.match(/By approving this/)) - await (regularDelayMs) + await delay(regularDelayMs) }) it('opens the gas edit modal', async () => { diff --git a/test/unit/components/pending-tx-test.js b/test/unit/components/pending-tx-test.js deleted file mode 100644 index c68e013ac..000000000 --- a/test/unit/components/pending-tx-test.js +++ /dev/null @@ -1,67 +0,0 @@ -const assert = require('assert') -const h = require('react-hyperscript') -const PendingTx = require('../../../ui/app/components/pending-tx') -const ethUtil = require('ethereumjs-util') - -const { createMockStore } = require('redux-test-utils') -const { shallowWithStore } = require('../../lib/shallow-with-store') - -const identities = { abc: {}, def: {} } -const mockState = { - metamask: { - accounts: { abc: {} }, - identities, - conversionRate: 10, - selectedAddress: 'abc', - }, -} - -describe('PendingTx', function () { - const gasPrice = '0x4A817C800' // 20 Gwei - const txData = { - 'id': 5021615666270214, - 'time': 1494458763011, - 'status': 'unapproved', - 'metamaskNetworkId': '1494442339676', - 'txParams': { - 'from': '0xfdea65c8e26263f6d9a1b5de9555d2931a33b826', - 'to': '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', - 'value': '0xde0b6b3a7640000', - gasPrice, - 'gas': '0x7b0c', - }, - 'gasLimitSpecified': false, - 'estimatedGas': '0x5208', - } - const newGasPrice = '0x77359400' - - const computedBalances = {} - computedBalances[Object.keys(identities)[0]] = { - ethBalance: '0x00000000000000056bc75e2d63100000', - } - const props = { - txData, - computedBalances, - sendTransaction: (txMeta, event) => { - // Assert changes: - const result = ethUtil.addHexPrefix(txMeta.txParams.gasPrice) - assert.notEqual(result, gasPrice, 'gas price should change') - assert.equal(result, newGasPrice, 'gas price assigned.') - }, - } - - let pendingTxComponent - let store - let component - beforeEach(function () { - store = createMockStore(mockState) - component = shallowWithStore(h(PendingTx, props), store) - pendingTxComponent = component - }) - - it('should render correctly', function (done) { - assert.equal(pendingTxComponent.props().identities, identities) - done() - }) -}) - -- cgit v1.2.3 From aa5a987765677b4945e9eefe03cae8dcc93318cd Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Tue, 17 Jul 2018 21:54:04 -0400 Subject: added some e2e tests --- test/e2e/beta/from-import-beta-ui.spec.js | 47 +++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'test') diff --git a/test/e2e/beta/from-import-beta-ui.spec.js b/test/e2e/beta/from-import-beta-ui.spec.js index b396dc5b9..938d22cd9 100644 --- a/test/e2e/beta/from-import-beta-ui.spec.js +++ b/test/e2e/beta/from-import-beta-ui.spec.js @@ -321,4 +321,51 @@ describe('Using MetaMask with an existing account', function () { }) }) + describe('Connects to a Hardware wallet', () => { + it('choose Connect Hardware Wallet from the account menu', async () => { + await driver.findElement(By.css('.account-menu__icon')).click() + await delay(regularDelayMs) + + const [connectAccount] = await findElements(driver, By.xpath(`//div[contains(text(), 'Connect Hardware Wallet')]`)) + await connectAccount.click() + await delay(regularDelayMs) + }) + + it('should open the TREZOR Connect popup', async () => { + const connectButtons = await findElements(driver, By.xpath(`//button[contains(text(), 'Connect to Trezor')]`)) + await connectButtons[0].click() + await delay(regularDelayMs) + const allWindows = await driver.getAllWindowHandles() + switch (process.env.SELENIUM_BROWSER) { + case 'chrome': + assert.equal(allWindows.length, 2) + break + default: + assert.equal(allWindows.length, 1) + } + }) + + it('should show the "Browser not supported" screen for non Chrome browsers', async () => { + if (process.env.SELENIUM_BROWSER !== 'chrome') { + const title = await findElements(driver, By.xpath(`//h3[contains(text(), 'Bummer! Your Browser is not supported...')]`)) + assert.equal(title.length, 1) + + const downloadChromeButtons = await findElements(driver, By.xpath(`//button[contains(text(), 'Download Google Chrome')]`)) + assert.equal(downloadChromeButtons.length, 1) + + await downloadChromeButtons[0].click() + await delay(regularDelayMs) + + const [newUITab, downloadChromeTab] = await driver.getAllWindowHandles() + + await driver.switchTo().window(downloadChromeTab) + await delay(regularDelayMs) + const tabUrl = await driver.getCurrentUrl() + assert.equal(tabUrl, 'https://www.google.com/chrome/') + await driver.close() + await delay(regularDelayMs) + await driver.switchTo().window(newUITab) + } + }) + }) }) -- cgit v1.2.3 From cbb14f1d5e50c10865838a98452ecfb4b6cb8d6a Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Tue, 17 Jul 2018 21:57:19 -0400 Subject: fix browser not supported screen --- test/e2e/beta/from-import-beta-ui.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/e2e/beta/from-import-beta-ui.spec.js b/test/e2e/beta/from-import-beta-ui.spec.js index 938d22cd9..32f57b157 100644 --- a/test/e2e/beta/from-import-beta-ui.spec.js +++ b/test/e2e/beta/from-import-beta-ui.spec.js @@ -347,7 +347,7 @@ describe('Using MetaMask with an existing account', function () { it('should show the "Browser not supported" screen for non Chrome browsers', async () => { if (process.env.SELENIUM_BROWSER !== 'chrome') { - const title = await findElements(driver, By.xpath(`//h3[contains(text(), 'Bummer! Your Browser is not supported...')]`)) + const title = await findElements(driver, By.xpath(`//h3[contains(text(), 'Your Browser is not supported...')]`)) assert.equal(title.length, 1) const downloadChromeButtons = await findElements(driver, By.xpath(`//button[contains(text(), 'Download Google Chrome')]`)) -- cgit v1.2.3 From 3b97d816ffcaebc7606d4564ea95918f647ba413 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Thu, 19 Jul 2018 15:56:38 -0400 Subject: detect tokens when submit password and new account selected --- test/unit/app/controllers/detect-tokens-test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js index 860ed7050..49492c543 100644 --- a/test/unit/app/controllers/detect-tokens-test.js +++ b/test/unit/app/controllers/detect-tokens-test.js @@ -28,7 +28,7 @@ describe('DetectTokensController', () => { const controller = new DetectTokensController({preferences: preferences, network: network}) controller.isActive = true - var stub = sandbox.stub(controller, 'exploreNewTokens') + var stub = sandbox.stub(controller, 'detectNewTokens') clock.tick(1) sandbox.assert.notCalled(stub) @@ -51,7 +51,7 @@ describe('DetectTokensController', () => { .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4').returns(true) .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388').returns(true) - await controller.exploreNewTokens() + await controller.detectNewTokens() sandbox.assert.notCalled(stub) }) @@ -68,7 +68,7 @@ describe('DetectTokensController', () => { .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388') .returns(preferences.addToken('0xbc86727e770de68b1060c91f6bb6945c73e10388', 'XNK', 18)) - await controller.exploreNewTokens() + await controller.detectNewTokens() assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}]) }) @@ -87,7 +87,7 @@ describe('DetectTokensController', () => { .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388') .returns(preferences.addToken('0xbc86727e770de68b1060c91f6bb6945c73e10388', 'XNK', 18)) - await controller.exploreNewTokens() + await controller.detectNewTokens() assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}]) }) -- cgit v1.2.3 From 009b1cefbe3d19dcad01078927b1a55c3439b22f Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Thu, 19 Jul 2018 19:46:46 -0400 Subject: keyring unlocked detect and unit tests --- test/unit/app/controllers/detect-tokens-test.js | 38 +++++++++++++++++++++---- 1 file changed, 32 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js index 49492c543..dcb3c431f 100644 --- a/test/unit/app/controllers/detect-tokens-test.js +++ b/test/unit/app/controllers/detect-tokens-test.js @@ -1,14 +1,17 @@ const assert = require('assert') const sinon = require('sinon') +const ObservableStore = require('obs-store') const DetectTokensController = require('../../../../app/scripts/controllers/detect-tokens') const NetworkController = require('../../../../app/scripts/controllers/network/network') const PreferencesController = require('../../../../app/scripts/controllers/preferences') describe('DetectTokensController', () => { - const sandbox = sinon.createSandbox() + const sandbox = sinon.createSandbox() let clock + let keyringMemStore before(async () => { - }) + keyringMemStore = new ObservableStore({ isUnlocked: false}) + }) after(() => { sandbox.restore() }) @@ -25,7 +28,7 @@ describe('DetectTokensController', () => { const network = new NetworkController() network.setProviderType('mainnet') const preferences = new PreferencesController() - const controller = new DetectTokensController({preferences: preferences, network: network}) + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) controller.isActive = true var stub = sandbox.stub(controller, 'detectNewTokens') @@ -44,7 +47,7 @@ describe('DetectTokensController', () => { const network = new NetworkController() network.setProviderType('rinkeby') const preferences = new PreferencesController() - const controller = new DetectTokensController({preferences: preferences, network: network}) + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) controller.isActive = true var stub = sandbox.stub(controller, 'detectTokenBalance') @@ -59,7 +62,7 @@ describe('DetectTokensController', () => { const network = new NetworkController() network.setProviderType('mainnet') const preferences = new PreferencesController() - const controller = new DetectTokensController({preferences: preferences, network: network}) + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) controller.isActive = true sandbox.stub(controller, 'detectTokenBalance') @@ -78,7 +81,7 @@ describe('DetectTokensController', () => { network.setProviderType('mainnet') const preferences = new PreferencesController() preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8) - const controller = new DetectTokensController({preferences: preferences, network: network}) + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) controller.isActive = true sandbox.stub(controller, 'detectTokenBalance') @@ -91,4 +94,27 @@ describe('DetectTokensController', () => { assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}]) }) + + it('should trigger detect new tokens when change address', async () => { + const network = new NetworkController() + network.setProviderType('mainnet') + const preferences = new PreferencesController() + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) + controller.isActive = true + var stub = sandbox.stub(controller, 'detectNewTokens') + await preferences.setSelectedAddress('0xbc86727e770de68b1060c91f6bb6945c73e10388') + sandbox.assert.called(stub) + }) + + it('should trigger detect new tokens when submit password', async () => { + const network = new NetworkController() + network.setProviderType('mainnet') + const preferences = new PreferencesController() + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) + controller.isActive = true + controller.selectedAddress = '0x0' + var stub = sandbox.stub(controller, 'detectNewTokens') + await controller._keyringMemStore.updateState({ isUnlocked: true }) + sandbox.assert.called(stub) + }) }) -- cgit v1.2.3 From cb045fd8feec88bd631329ab9b3285aeed0f2e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20Mi=C3=B1o?= Date: Fri, 20 Jul 2018 12:36:24 -0400 Subject: Auto-detect tokens #3034 (#4683) * detect tokens polling * network store to detect token * tests for spec * passtest-lint * fix lint * improve tests * detect tokens through infura * detect tokens when submit password and new account selected * keyring unlocked detect and unit tests * add changelog --- test/unit/app/controllers/detect-tokens-test.js | 120 ++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 test/unit/app/controllers/detect-tokens-test.js (limited to 'test') diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js new file mode 100644 index 000000000..dcb3c431f --- /dev/null +++ b/test/unit/app/controllers/detect-tokens-test.js @@ -0,0 +1,120 @@ +const assert = require('assert') +const sinon = require('sinon') +const ObservableStore = require('obs-store') +const DetectTokensController = require('../../../../app/scripts/controllers/detect-tokens') +const NetworkController = require('../../../../app/scripts/controllers/network/network') +const PreferencesController = require('../../../../app/scripts/controllers/preferences') + +describe('DetectTokensController', () => { + const sandbox = sinon.createSandbox() + let clock + let keyringMemStore + before(async () => { + keyringMemStore = new ObservableStore({ isUnlocked: false}) + }) + after(() => { + sandbox.restore() + }) + + it('should poll on correct interval', async () => { + const stub = sinon.stub(global, 'setInterval') + new DetectTokensController({ interval: 1337 }) // eslint-disable-line no-new + assert.strictEqual(stub.getCall(0).args[1], 1337) + stub.restore() + }) + + it('should be called on every polling period', async () => { + clock = sandbox.useFakeTimers() + const network = new NetworkController() + network.setProviderType('mainnet') + const preferences = new PreferencesController() + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) + controller.isActive = true + + var stub = sandbox.stub(controller, 'detectNewTokens') + + clock.tick(1) + sandbox.assert.notCalled(stub) + clock.tick(180000) + sandbox.assert.called(stub) + clock.tick(180000) + sandbox.assert.calledTwice(stub) + clock.tick(180000) + sandbox.assert.calledThrice(stub) + }) + + it('should not check tokens while in test network', async () => { + const network = new NetworkController() + network.setProviderType('rinkeby') + const preferences = new PreferencesController() + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) + controller.isActive = true + + var stub = sandbox.stub(controller, 'detectTokenBalance') + .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4').returns(true) + .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388').returns(true) + + await controller.detectNewTokens() + sandbox.assert.notCalled(stub) + }) + + it('should only check and add tokens while in main network', async () => { + const network = new NetworkController() + network.setProviderType('mainnet') + const preferences = new PreferencesController() + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) + controller.isActive = true + + sandbox.stub(controller, 'detectTokenBalance') + .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4') + .returns(preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8)) + .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388') + .returns(preferences.addToken('0xbc86727e770de68b1060c91f6bb6945c73e10388', 'XNK', 18)) + + await controller.detectNewTokens() + assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, + {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}]) + }) + + it('should not detect same token while in main network', async () => { + const network = new NetworkController() + network.setProviderType('mainnet') + const preferences = new PreferencesController() + preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8) + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) + controller.isActive = true + + sandbox.stub(controller, 'detectTokenBalance') + .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4') + .returns(preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8)) + .withArgs('0xBC86727E770de68B1060C91f6BB6945c73e10388') + .returns(preferences.addToken('0xbc86727e770de68b1060c91f6bb6945c73e10388', 'XNK', 18)) + + await controller.detectNewTokens() + assert.deepEqual(preferences.store.getState().tokens, [{address: '0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', decimals: 8, symbol: 'J8T'}, + {address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', decimals: 18, symbol: 'XNK'}]) + }) + + it('should trigger detect new tokens when change address', async () => { + const network = new NetworkController() + network.setProviderType('mainnet') + const preferences = new PreferencesController() + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) + controller.isActive = true + var stub = sandbox.stub(controller, 'detectNewTokens') + await preferences.setSelectedAddress('0xbc86727e770de68b1060c91f6bb6945c73e10388') + sandbox.assert.called(stub) + }) + + it('should trigger detect new tokens when submit password', async () => { + const network = new NetworkController() + network.setProviderType('mainnet') + const preferences = new PreferencesController() + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) + controller.isActive = true + controller.selectedAddress = '0x0' + var stub = sandbox.stub(controller, 'detectNewTokens') + await controller._keyringMemStore.updateState({ isUnlocked: true }) + sandbox.assert.called(stub) + }) +}) -- cgit v1.2.3 From 9c955549338f49d8b5eb6ca003c2c65c725aa328 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Fri, 20 Jul 2018 19:58:03 -0400 Subject: fix detection on submit password --- test/unit/app/controllers/detect-tokens-test.js | 33 ++++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/test/unit/app/controllers/detect-tokens-test.js b/test/unit/app/controllers/detect-tokens-test.js index dcb3c431f..426ffe23a 100644 --- a/test/unit/app/controllers/detect-tokens-test.js +++ b/test/unit/app/controllers/detect-tokens-test.js @@ -29,7 +29,8 @@ describe('DetectTokensController', () => { network.setProviderType('mainnet') const preferences = new PreferencesController() const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) - controller.isActive = true + controller.isOpen = true + controller.isUnlocked = true var stub = sandbox.stub(controller, 'detectNewTokens') @@ -48,7 +49,8 @@ describe('DetectTokensController', () => { network.setProviderType('rinkeby') const preferences = new PreferencesController() const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) - controller.isActive = true + controller.isOpen = true + controller.isUnlocked = true var stub = sandbox.stub(controller, 'detectTokenBalance') .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4').returns(true) @@ -63,7 +65,8 @@ describe('DetectTokensController', () => { network.setProviderType('mainnet') const preferences = new PreferencesController() const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) - controller.isActive = true + controller.isOpen = true + controller.isUnlocked = true sandbox.stub(controller, 'detectTokenBalance') .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4') @@ -82,7 +85,8 @@ describe('DetectTokensController', () => { const preferences = new PreferencesController() preferences.addToken('0x0d262e5dc4a06a0f1c90ce79c7a60c09dfc884e4', 'J8T', 8) const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) - controller.isActive = true + controller.isOpen = true + controller.isUnlocked = true sandbox.stub(controller, 'detectTokenBalance') .withArgs('0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4') @@ -100,7 +104,8 @@ describe('DetectTokensController', () => { network.setProviderType('mainnet') const preferences = new PreferencesController() const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) - controller.isActive = true + controller.isOpen = true + controller.isUnlocked = true var stub = sandbox.stub(controller, 'detectNewTokens') await preferences.setSelectedAddress('0xbc86727e770de68b1060c91f6bb6945c73e10388') sandbox.assert.called(stub) @@ -111,10 +116,26 @@ describe('DetectTokensController', () => { network.setProviderType('mainnet') const preferences = new PreferencesController() const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) - controller.isActive = true + controller.isOpen = true controller.selectedAddress = '0x0' var stub = sandbox.stub(controller, 'detectNewTokens') await controller._keyringMemStore.updateState({ isUnlocked: true }) sandbox.assert.called(stub) }) + + it('should not trigger detect new tokens when not open or not unlocked', async () => { + const network = new NetworkController() + network.setProviderType('mainnet') + const preferences = new PreferencesController() + const controller = new DetectTokensController({ preferences: preferences, network: network, keyringMemStore: keyringMemStore }) + controller.isOpen = true + controller.isUnlocked = false + var stub = sandbox.stub(controller, 'detectTokenBalance') + clock.tick(180000) + sandbox.assert.notCalled(stub) + controller.isOpen = false + controller.isUnlocked = true + clock.tick(180000) + sandbox.assert.notCalled(stub) + }) }) -- cgit v1.2.3 From cb8ea12db626e82b7230317fc74b6b80ce20f793 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Tue, 24 Jul 2018 11:24:36 -0230 Subject: Updates e2e beta tests to ensure that popup window closes after confirming a simple send. --- test/e2e/beta/metamask-beta-ui.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index ee1aa0ff1..ca1977c5a 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -472,7 +472,7 @@ describe('MetaMask', function () { await confirmButton.click() await delay(regularDelayMs) - await closeAllWindowHandlesExcept(driver, [extension, dapp]) + await waitUntilXWindowHandles(driver, 2) await driver.switchTo().window(extension) await delay(regularDelayMs) }) -- cgit v1.2.3