mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 01:39:44 +01:00
Merge branch 'uat-next' of https://github.com/MetaMask/metamask-extension into cb-254
This commit is contained in:
commit
eb919f4710
17
CHANGELOG.md
17
CHANGELOG.md
@ -2,6 +2,23 @@
|
|||||||
|
|
||||||
## Current Master
|
## Current Master
|
||||||
|
|
||||||
|
## 3.14.1 2018-2-1
|
||||||
|
|
||||||
|
- Further fix scrolling for Firefox.
|
||||||
|
|
||||||
|
## 3.14.0 2018-2-1
|
||||||
|
|
||||||
|
- Removed unneeded data from storage
|
||||||
|
- Add a "reset account" feature to Settings
|
||||||
|
- Add warning for importing some kinds of files.
|
||||||
|
- Scrollable Setting view for Firefox.
|
||||||
|
|
||||||
|
## 3.13.8 2018-1-29
|
||||||
|
|
||||||
|
- Fix provider for Kovan network.
|
||||||
|
- Bump limit for EventEmitter listeners before warning.
|
||||||
|
- Display Error when empty string is entered as a token address.
|
||||||
|
|
||||||
## 3.13.7 2018-1-22
|
## 3.13.7 2018-1-22
|
||||||
|
|
||||||
- Add ability to bypass gas estimation loading indicator.
|
- Add ability to bypass gas estimation loading indicator.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "MetaMask",
|
"name": "MetaMask",
|
||||||
"short_name": "Metamask",
|
"short_name": "Metamask",
|
||||||
"version": "3.13.7",
|
"version": "3.14.1",
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"author": "https://metamask.io",
|
"author": "https://metamask.io",
|
||||||
"description": "Ethereum Browser Extension",
|
"description": "Ethereum Browser Extension",
|
||||||
|
@ -152,6 +152,10 @@ module.exports = class TransactionController extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wipeTransactions (address) {
|
||||||
|
this.txStateManager.wipeTransactions(address)
|
||||||
|
}
|
||||||
|
|
||||||
// Adds a tx to the txlist
|
// Adds a tx to the txlist
|
||||||
addTx (txMeta) {
|
addTx (txMeta) {
|
||||||
this.txStateManager.addTx(txMeta)
|
this.txStateManager.addTx(txMeta)
|
||||||
|
@ -42,6 +42,17 @@ ConfigManager.prototype.getData = function () {
|
|||||||
return this.store.getState()
|
return this.store.getState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfigManager.prototype.setPasswordForgotten = function (passwordForgottenState) {
|
||||||
|
const data = this.getData()
|
||||||
|
data.forgottenPassword = passwordForgottenState
|
||||||
|
this.setData(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigManager.prototype.getPasswordForgotten = function (passwordForgottenState) {
|
||||||
|
const data = this.getData()
|
||||||
|
return data.forgottenPassword
|
||||||
|
}
|
||||||
|
|
||||||
ConfigManager.prototype.setWallet = function (wallet) {
|
ConfigManager.prototype.setWallet = function (wallet) {
|
||||||
var data = this.getData()
|
var data = this.getData()
|
||||||
data.wallet = wallet
|
data.wallet = wallet
|
||||||
|
@ -221,6 +221,17 @@ module.exports = class TransactionStateManger extends EventEmitter {
|
|||||||
this._setTxStatus(txId, 'failed')
|
this._setTxStatus(txId, 'failed')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wipeTransactions (address) {
|
||||||
|
// network only tx
|
||||||
|
const txs = this.getFullTxList()
|
||||||
|
const network = this.getNetwork()
|
||||||
|
|
||||||
|
// Filter out the ones from the current account and network
|
||||||
|
const otherAccountTxs = txs.filter((txMeta) => !(txMeta.txParams.from === address && txMeta.metamaskNetworkId === network))
|
||||||
|
|
||||||
|
// Update state
|
||||||
|
this._saveTxList(otherAccountTxs)
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// PRIVATE METHODS
|
// PRIVATE METHODS
|
||||||
//
|
//
|
||||||
|
@ -43,6 +43,8 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
constructor (opts) {
|
constructor (opts) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
this.defaultMaxListeners = 20
|
||||||
|
|
||||||
this.sendUpdate = debounce(this.privateSendUpdate.bind(this), 200)
|
this.sendUpdate = debounce(this.privateSendUpdate.bind(this), 200)
|
||||||
|
|
||||||
this.opts = opts
|
this.opts = opts
|
||||||
@ -84,9 +86,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
})
|
})
|
||||||
this.infuraController.scheduleInfuraNetworkCheck()
|
this.infuraController.scheduleInfuraNetworkCheck()
|
||||||
|
|
||||||
this.blacklistController = new BlacklistController({
|
this.blacklistController = new BlacklistController()
|
||||||
initState: initState.BlacklistController,
|
|
||||||
})
|
|
||||||
this.blacklistController.scheduleUpdates()
|
this.blacklistController.scheduleUpdates()
|
||||||
|
|
||||||
// rpc provider
|
// rpc provider
|
||||||
@ -198,12 +198,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
this.networkController.store.subscribe((state) => {
|
this.networkController.store.subscribe((state) => {
|
||||||
this.store.updateState({ NetworkController: state })
|
this.store.updateState({ NetworkController: state })
|
||||||
})
|
})
|
||||||
this.blacklistController.store.subscribe((state) => {
|
|
||||||
this.store.updateState({ BlacklistController: state })
|
|
||||||
})
|
|
||||||
this.recentBlocksController.store.subscribe((state) => {
|
|
||||||
this.store.updateState({ RecentBlocks: state })
|
|
||||||
})
|
|
||||||
this.infuraController.store.subscribe((state) => {
|
this.infuraController.store.subscribe((state) => {
|
||||||
this.store.updateState({ InfuraController: state })
|
this.store.updateState({ InfuraController: state })
|
||||||
})
|
})
|
||||||
@ -315,6 +310,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
{
|
{
|
||||||
lostAccounts: this.configManager.getLostAccounts(),
|
lostAccounts: this.configManager.getLostAccounts(),
|
||||||
seedWords: this.configManager.getSeedWords(),
|
seedWords: this.configManager.getSeedWords(),
|
||||||
|
forgottenPassword: this.configManager.getPasswordForgotten(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -337,6 +333,8 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
setCurrentCurrency: this.setCurrentCurrency.bind(this),
|
setCurrentCurrency: this.setCurrentCurrency.bind(this),
|
||||||
setUseBlockie: this.setUseBlockie.bind(this),
|
setUseBlockie: this.setUseBlockie.bind(this),
|
||||||
markAccountsFound: this.markAccountsFound.bind(this),
|
markAccountsFound: this.markAccountsFound.bind(this),
|
||||||
|
markPasswordForgotten: this.markPasswordForgotten.bind(this),
|
||||||
|
unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this),
|
||||||
|
|
||||||
// coinbase
|
// coinbase
|
||||||
buyEth: this.buyEth.bind(this),
|
buyEth: this.buyEth.bind(this),
|
||||||
@ -347,6 +345,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
addNewAccount: nodeify(this.addNewAccount, this),
|
addNewAccount: nodeify(this.addNewAccount, this),
|
||||||
placeSeedWords: this.placeSeedWords.bind(this),
|
placeSeedWords: this.placeSeedWords.bind(this),
|
||||||
clearSeedWordCache: this.clearSeedWordCache.bind(this),
|
clearSeedWordCache: this.clearSeedWordCache.bind(this),
|
||||||
|
resetAccount: this.resetAccount.bind(this),
|
||||||
importAccountWithStrategy: this.importAccountWithStrategy.bind(this),
|
importAccountWithStrategy: this.importAccountWithStrategy.bind(this),
|
||||||
|
|
||||||
// vault management
|
// vault management
|
||||||
@ -607,6 +606,13 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
cb(null, this.preferencesController.getSelectedAddress())
|
cb(null, this.preferencesController.getSelectedAddress())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetAccount (cb) {
|
||||||
|
const selectedAddress = this.preferencesController.getSelectedAddress()
|
||||||
|
this.txController.wipeTransactions(selectedAddress)
|
||||||
|
cb(null, selectedAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
importAccountWithStrategy (strategy, args, cb) {
|
importAccountWithStrategy (strategy, args, cb) {
|
||||||
accountImporter.importAccount(strategy, args)
|
accountImporter.importAccount(strategy, args)
|
||||||
.then((privateKey) => {
|
.then((privateKey) => {
|
||||||
@ -791,6 +797,18 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
cb(null, this.getState())
|
cb(null, this.getState())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
markPasswordForgotten(cb) {
|
||||||
|
this.configManager.setPasswordForgotten(true)
|
||||||
|
this.sendUpdate()
|
||||||
|
cb()
|
||||||
|
}
|
||||||
|
|
||||||
|
unMarkPasswordForgotten(cb) {
|
||||||
|
this.configManager.setPasswordForgotten(false)
|
||||||
|
this.sendUpdate()
|
||||||
|
cb()
|
||||||
|
}
|
||||||
|
|
||||||
restoreOldVaultAccounts (migratorOutput) {
|
restoreOldVaultAccounts (migratorOutput) {
|
||||||
const { serialized } = migratorOutput
|
const { serialized } = migratorOutput
|
||||||
return this.keyringController.restoreKeyring(serialized)
|
return this.keyringController.restoreKeyring(serialized)
|
||||||
|
34
app/scripts/migrations/021.js
Normal file
34
app/scripts/migrations/021.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const version = 21
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
This migration removes the BlackListController from disk state
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
const clone = require('clone')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
version,
|
||||||
|
|
||||||
|
migrate: function (originalVersionedData) {
|
||||||
|
const versionedData = clone(originalVersionedData)
|
||||||
|
versionedData.meta.version = version
|
||||||
|
try {
|
||||||
|
const state = versionedData.data
|
||||||
|
const newState = transformState(state)
|
||||||
|
versionedData.data = newState
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`MetaMask Migration #${version}` + err.stack)
|
||||||
|
}
|
||||||
|
return Promise.resolve(versionedData)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformState (state) {
|
||||||
|
const newState = state
|
||||||
|
delete newState.BlacklistController
|
||||||
|
delete newState.RecentBlocks
|
||||||
|
return newState
|
||||||
|
}
|
||||||
|
|
@ -31,4 +31,5 @@ module.exports = [
|
|||||||
require('./018'),
|
require('./018'),
|
||||||
require('./019'),
|
require('./019'),
|
||||||
require('./020'),
|
require('./020'),
|
||||||
|
require('./021'),
|
||||||
]
|
]
|
||||||
|
26
development/backGroundConnectionModifiers.js
Normal file
26
development/backGroundConnectionModifiers.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
module.exports = {
|
||||||
|
"confirm sig requests": {
|
||||||
|
signMessage: (msgData, cb) => {
|
||||||
|
const stateUpdate = {
|
||||||
|
unapprovedMsgs: {},
|
||||||
|
unapprovedMsgCount: 0,
|
||||||
|
}
|
||||||
|
return cb(null, stateUpdate)
|
||||||
|
},
|
||||||
|
signPersonalMessage: (msgData, cb) => {
|
||||||
|
const stateUpdate = {
|
||||||
|
unapprovedPersonalMsgs: {},
|
||||||
|
unapprovedPersonalMsgsCount: 0,
|
||||||
|
}
|
||||||
|
return cb(null, stateUpdate)
|
||||||
|
},
|
||||||
|
signTypedMessage: (msgData, cb) => {
|
||||||
|
const stateUpdate = {
|
||||||
|
unapprovedTypedMessages: {},
|
||||||
|
unapprovedTypedMessagesCount: 0,
|
||||||
|
}
|
||||||
|
return cb(null, stateUpdate)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,14 @@ function NewComponent () {
|
|||||||
|
|
||||||
NewComponent.prototype.render = function () {
|
NewComponent.prototype.render = function () {
|
||||||
const props = this.props
|
const props = this.props
|
||||||
let { states, selectedKey, actions, store } = props
|
let {
|
||||||
|
states,
|
||||||
|
selectedKey,
|
||||||
|
actions,
|
||||||
|
store,
|
||||||
|
modifyBackgroundConnection,
|
||||||
|
backGroundConnectionModifiers,
|
||||||
|
} = props
|
||||||
|
|
||||||
const state = this.state || {}
|
const state = this.state || {}
|
||||||
const selected = state.selected || selectedKey
|
const selected = state.selected || selectedKey
|
||||||
@ -23,6 +30,8 @@ NewComponent.prototype.render = function () {
|
|||||||
value: selected,
|
value: selected,
|
||||||
onChange:(event) => {
|
onChange:(event) => {
|
||||||
const selectedKey = event.target.value
|
const selectedKey = event.target.value
|
||||||
|
const backgroundConnectionModifier = backGroundConnectionModifiers[selectedKey]
|
||||||
|
modifyBackgroundConnection(backgroundConnectionModifier || {})
|
||||||
store.dispatch(actions.update(selectedKey))
|
store.dispatch(actions.update(selectedKey))
|
||||||
this.setState({ selected: selectedKey })
|
this.setState({ selected: selectedKey })
|
||||||
},
|
},
|
||||||
|
132
development/states/add-token.json
Normal file
132
development/states/add-token.json
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
{
|
||||||
|
"metamask": {
|
||||||
|
"isInitialized": true,
|
||||||
|
"isUnlocked": true,
|
||||||
|
"featureFlags": {"betaUI": true},
|
||||||
|
"rpcTarget": "https://rawtestrpc.metamask.io/",
|
||||||
|
"identities": {
|
||||||
|
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
|
||||||
|
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
|
||||||
|
"name": "Send Account 1"
|
||||||
|
},
|
||||||
|
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
|
||||||
|
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb",
|
||||||
|
"name": "Send Account 2"
|
||||||
|
},
|
||||||
|
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
|
||||||
|
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d",
|
||||||
|
"name": "Send Account 3"
|
||||||
|
},
|
||||||
|
"0xd85a4b6a394794842887b8284293d69163007bbb": {
|
||||||
|
"address": "0xd85a4b6a394794842887b8284293d69163007bbb",
|
||||||
|
"name": "Send Account 4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unapprovedTxs": {},
|
||||||
|
"conversionRate": 1200.88200327,
|
||||||
|
"conversionDate": 1489013762,
|
||||||
|
"noActiveNotices": true,
|
||||||
|
"frequentRpcList": [],
|
||||||
|
"network": "3",
|
||||||
|
"accounts": {
|
||||||
|
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
|
||||||
|
"code": "0x",
|
||||||
|
"balance": "0x47c9d71831c76efe",
|
||||||
|
"nonce": "0x1b",
|
||||||
|
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"
|
||||||
|
},
|
||||||
|
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
|
||||||
|
"code": "0x",
|
||||||
|
"balance": "0x37452b1315889f80",
|
||||||
|
"nonce": "0xa",
|
||||||
|
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb"
|
||||||
|
},
|
||||||
|
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
|
||||||
|
"code": "0x",
|
||||||
|
"balance": "0x30c9d71831c76efe",
|
||||||
|
"nonce": "0x1c",
|
||||||
|
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d"
|
||||||
|
},
|
||||||
|
"0xd85a4b6a394794842887b8284293d69163007bbb": {
|
||||||
|
"code": "0x",
|
||||||
|
"balance": "0x0",
|
||||||
|
"nonce": "0x0",
|
||||||
|
"address": "0xd85a4b6a394794842887b8284293d69163007bbb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"addressBook": [
|
||||||
|
{
|
||||||
|
"address": "0x06195827297c7a80a443b6894d3bdb8824b43896",
|
||||||
|
"name": "Address Book Account 1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tokens": [],
|
||||||
|
"transactions": {},
|
||||||
|
"selectedAddressTxList": [],
|
||||||
|
"unapprovedMsgs": {},
|
||||||
|
"unapprovedMsgCount": 0,
|
||||||
|
"unapprovedPersonalMsgs": {},
|
||||||
|
"unapprovedPersonalMsgCount": 0,
|
||||||
|
"keyringTypes": [
|
||||||
|
"Simple Key Pair",
|
||||||
|
"HD Key Tree"
|
||||||
|
],
|
||||||
|
"keyrings": [
|
||||||
|
{
|
||||||
|
"type": "HD Key Tree",
|
||||||
|
"accounts": [
|
||||||
|
"fdea65c8e26263f6d9a1b5de9555d2931a33b825",
|
||||||
|
"c5b8dbac4c1d3f152cdeb400e2313f309c410acb",
|
||||||
|
"2f8d4a878cfa04a6e60d46362f5644deab66572d"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Simple Key Pair",
|
||||||
|
"accounts": [
|
||||||
|
"0xd85a4b6a394794842887b8284293d69163007bbb"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"selectedAddress": "0xd85a4b6a394794842887b8284293d69163007bbb",
|
||||||
|
"currentCurrency": "USD",
|
||||||
|
"provider": {
|
||||||
|
"type": "testnet"
|
||||||
|
},
|
||||||
|
"shapeShiftTxList": [],
|
||||||
|
"lostAccounts": [],
|
||||||
|
"send": {
|
||||||
|
"gasLimit": null,
|
||||||
|
"gasPrice": null,
|
||||||
|
"gasTotal": "0xb451dc41b578",
|
||||||
|
"tokenBalance": null,
|
||||||
|
"from": "",
|
||||||
|
"to": "",
|
||||||
|
"amount": "0x0",
|
||||||
|
"memo": "",
|
||||||
|
"errors": {},
|
||||||
|
"maxModeOn": false,
|
||||||
|
"editingTransactionId": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"appState": {
|
||||||
|
"menuOpen": false,
|
||||||
|
"currentView": {
|
||||||
|
"name": "accountDetail",
|
||||||
|
"detailView": null,
|
||||||
|
"context": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
|
||||||
|
},
|
||||||
|
"accountDetail": {
|
||||||
|
"subview": "transactions"
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"modalState": {},
|
||||||
|
"previousModalState": {}
|
||||||
|
},
|
||||||
|
"transForward": true,
|
||||||
|
"isLoading": false,
|
||||||
|
"warning": null,
|
||||||
|
"scrollToBottom": false,
|
||||||
|
"forgottenPassword": null
|
||||||
|
},
|
||||||
|
"identities": {}
|
||||||
|
}
|
175
development/states/confirm-sig-requests.json
Normal file
175
development/states/confirm-sig-requests.json
Normal file
File diff suppressed because one or more lines are too long
@ -35,7 +35,8 @@
|
|||||||
"type": "testnet"
|
"type": "testnet"
|
||||||
},
|
},
|
||||||
"shapeShiftTxList": [],
|
"shapeShiftTxList": [],
|
||||||
"lostAccounts": []
|
"lostAccounts": [],
|
||||||
|
"tokens": []
|
||||||
},
|
},
|
||||||
"appState": {
|
"appState": {
|
||||||
"menuOpen": false,
|
"menuOpen": false,
|
||||||
@ -48,7 +49,12 @@
|
|||||||
},
|
},
|
||||||
"transForward": true,
|
"transForward": true,
|
||||||
"isLoading": false,
|
"isLoading": false,
|
||||||
"warning": null
|
"warning": null,
|
||||||
|
"modal": {
|
||||||
|
"modalState": {"name": null},
|
||||||
|
"open": false,
|
||||||
|
"previousModalState": {"name": null}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"identities": {},
|
"identities": {},
|
||||||
"computedBalances": {}
|
"computedBalances": {}
|
||||||
|
@ -303,7 +303,7 @@ gulp.task('apply-prod-environment', function(done) {
|
|||||||
|
|
||||||
gulp.task('dev', gulp.series('build:scss', 'dev:js', 'copy', gulp.parallel('watch:scss', 'copy:watch', 'dev:reload')))
|
gulp.task('dev', gulp.series('build:scss', 'dev:js', 'copy', gulp.parallel('watch:scss', 'copy:watch', 'dev:reload')))
|
||||||
|
|
||||||
gulp.task('build', gulp.series('clean', 'build:scss', gulp.parallel('build:js', 'copy', 'deps')))
|
gulp.task('build', gulp.series('clean', 'build:scss', gulp.parallel('build:js', 'copy')))
|
||||||
gulp.task('dist', gulp.series('apply-prod-environment', 'build', 'zip'))
|
gulp.task('dist', gulp.series('apply-prod-environment', 'build', 'zip'))
|
||||||
|
|
||||||
// task generators
|
// task generators
|
||||||
|
@ -67,7 +67,7 @@ class CreatePasswordScreen extends Component {
|
|||||||
? <LoadingScreen loadingMessage="Creating your new account" />
|
? <LoadingScreen loadingMessage="Creating your new account" />
|
||||||
: (
|
: (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="alpha-warning">Warning This is Experimental software and is a Developer BETA </h2>
|
<h2 className="alpha-warning">Warning: This is Experimental software and is a Developer BETA</h2>
|
||||||
<div className="first-view-main">
|
<div className="first-view-main">
|
||||||
<div className="mascara-info">
|
<div className="mascara-info">
|
||||||
<Mascot
|
<Mascot
|
||||||
|
@ -67,27 +67,37 @@ class ImportSeedPhraseScreen extends Component {
|
|||||||
<div className="import-account__selector-label">
|
<div className="import-account__selector-label">
|
||||||
Enter your secret twelve word phrase here to restore your vault.
|
Enter your secret twelve word phrase here to restore your vault.
|
||||||
</div>
|
</div>
|
||||||
<textarea
|
<div className="import-account__input-wrapper">
|
||||||
className="import-account__secret-phrase"
|
<label className="import-account__input-label">Wallet Seed</label>
|
||||||
onChange={e => this.setState({seedPhrase: e.target.value})}
|
<textarea
|
||||||
/>
|
className="import-account__secret-phrase"
|
||||||
|
onChange={e => this.setState({seedPhrase: e.target.value})}
|
||||||
|
placeholder="Separate each word with a single space"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<span
|
<span
|
||||||
className="error"
|
className="error"
|
||||||
>
|
>
|
||||||
{this.props.warning}
|
{this.props.warning}
|
||||||
</span>
|
</span>
|
||||||
<input
|
<div className="import-account__input-wrapper">
|
||||||
className="first-time-flow__input"
|
<label className="import-account__input-label">New Password</label>
|
||||||
type="password"
|
<input
|
||||||
placeholder="New Password (min 8 characters)"
|
className="first-time-flow__input"
|
||||||
onChange={e => this.setState({password: e.target.value})}
|
type="password"
|
||||||
/>
|
placeholder="New Password (min 8 characters)"
|
||||||
<input
|
onChange={e => this.setState({password: e.target.value})}
|
||||||
className="first-time-flow__input create-password__confirm-input"
|
/>
|
||||||
type="password"
|
</div>
|
||||||
placeholder="Confirm Password"
|
<div className="import-account__input-wrapper">
|
||||||
onChange={e => this.setState({confirmPassword: e.target.value})}
|
<label className="import-account__input-label">Confirm Password</label>
|
||||||
/>
|
<input
|
||||||
|
className="first-time-flow__input"
|
||||||
|
type="password"
|
||||||
|
placeholder="Confirm Password"
|
||||||
|
onChange={e => this.setState({confirmPassword: e.target.value})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
className="first-time-flow__button"
|
className="first-time-flow__button"
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
|
@ -44,10 +44,14 @@
|
|||||||
.buy-ether {
|
.buy-ether {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
margin: 67px 0 0 146px;
|
margin: 67px 0 50px 146px;
|
||||||
max-width: 35rem;
|
max-width: 35rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.import-account {
|
||||||
|
max-width: initial;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 575px) {
|
@media only screen and (max-width: 575px) {
|
||||||
.create-password,
|
.create-password,
|
||||||
.unique-image,
|
.unique-image,
|
||||||
@ -135,14 +139,16 @@
|
|||||||
.backup-phrase__title,
|
.backup-phrase__title,
|
||||||
.import-account__title,
|
.import-account__title,
|
||||||
.buy-ether__title {
|
.buy-ether__title {
|
||||||
width: 280px;
|
|
||||||
color: #1B344D;
|
color: #1B344D;
|
||||||
font-size: 40px;
|
font-size: 40px;
|
||||||
font-weight: 500;
|
|
||||||
line-height: 51px;
|
line-height: 51px;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.import-account__title {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.tou__title,
|
.tou__title,
|
||||||
.backup-phrase__title {
|
.backup-phrase__title {
|
||||||
width: 480px;
|
width: 480px;
|
||||||
@ -288,9 +294,7 @@
|
|||||||
.import-account__back-button:hover {
|
.import-account__back-button:hover {
|
||||||
margin-bottom: 18px;
|
margin-bottom: 18px;
|
||||||
color: #22232C;
|
color: #22232C;
|
||||||
font-family: Montserrat Regular;
|
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 500;
|
|
||||||
line-height: 21px;
|
line-height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,6 +315,12 @@ button.backup-phrase__reveal-button:hover {
|
|||||||
|
|
||||||
.import-account__secret-phrase {
|
.import-account__secret-phrase {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
margin: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-account__secret-phrase::placeholder {
|
||||||
|
color: #9B9B9B;
|
||||||
|
font-weight: 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
.backup-phrase__confirm-seed-options {
|
.backup-phrase__confirm-seed-options {
|
||||||
@ -350,9 +360,7 @@ button.backup-phrase__confirm-seed-option:hover {
|
|||||||
|
|
||||||
.import-account__selector-label {
|
.import-account__selector-label {
|
||||||
color: #1B344D;
|
color: #1B344D;
|
||||||
font-family: Montserrat Light;
|
font-size: 16px;
|
||||||
font-size: 18px;
|
|
||||||
line-height: 23px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.import-account__dropdown {
|
.import-account__dropdown {
|
||||||
@ -394,7 +402,6 @@ button.backup-phrase__confirm-seed-option:hover {
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
width: 422px;
|
width: 422px;
|
||||||
color: #FF001F;
|
color: #FF001F;
|
||||||
font-family: Montserrat Light;
|
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 21px;
|
line-height: 21px;
|
||||||
}
|
}
|
||||||
@ -402,10 +409,8 @@ button.backup-phrase__confirm-seed-option:hover {
|
|||||||
.import-account__input-label {
|
.import-account__input-label {
|
||||||
margin-bottom: 9px;
|
margin-bottom: 9px;
|
||||||
color: #1B344D;
|
color: #1B344D;
|
||||||
font-family: Montserrat Light;
|
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
line-height: 23px;
|
line-height: 23px;
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.import-account__input {
|
.import-account__input {
|
||||||
@ -549,7 +554,7 @@ button.backup-phrase__confirm-seed-option:hover {
|
|||||||
width: 350px;
|
width: 350px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
padding: 15px 28px;
|
padding: 15px;
|
||||||
border: 1px solid #CDCDCD;
|
border: 1px solid #CDCDCD;
|
||||||
background-color: #FFFFFF;
|
background-color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
15
mock-dev.js
15
mock-dev.js
@ -20,6 +20,7 @@ const Root = require('./ui/app/root')
|
|||||||
const configureStore = require('./ui/app/store')
|
const configureStore = require('./ui/app/store')
|
||||||
const actions = require('./ui/app/actions')
|
const actions = require('./ui/app/actions')
|
||||||
const states = require('./development/states')
|
const states = require('./development/states')
|
||||||
|
const backGroundConnectionModifiers = require('./development/backGroundConnectionModifiers')
|
||||||
const Selector = require('./development/selector')
|
const Selector = require('./development/selector')
|
||||||
const MetamaskController = require('./app/scripts/metamask-controller')
|
const MetamaskController = require('./app/scripts/metamask-controller')
|
||||||
const firstTimeState = require('./app/scripts/first-time-state')
|
const firstTimeState = require('./app/scripts/first-time-state')
|
||||||
@ -85,6 +86,11 @@ actions.update = function(stateName) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function modifyBackgroundConnection(backgroundConnectionModifier) {
|
||||||
|
const modifiedBackgroundConnection = Object.assign({}, controller.getApi(), backgroundConnectionModifier)
|
||||||
|
actions._setBackgroundConnection(modifiedBackgroundConnection)
|
||||||
|
}
|
||||||
|
|
||||||
var css = MetaMaskUiCss()
|
var css = MetaMaskUiCss()
|
||||||
injectCss(css)
|
injectCss(css)
|
||||||
|
|
||||||
@ -113,7 +119,14 @@ function startApp(){
|
|||||||
},
|
},
|
||||||
}, 'Reset State'),
|
}, 'Reset State'),
|
||||||
|
|
||||||
h(Selector, { actions, selectedKey: selectedView, states, store }),
|
h(Selector, {
|
||||||
|
actions,
|
||||||
|
selectedKey: selectedView,
|
||||||
|
states,
|
||||||
|
store,
|
||||||
|
modifyBackgroundConnection,
|
||||||
|
backGroundConnectionModifiers,
|
||||||
|
}),
|
||||||
|
|
||||||
h('#app-content', {
|
h('#app-content', {
|
||||||
style: {
|
style: {
|
||||||
|
@ -25,7 +25,7 @@ inherits(AddTokenScreen, Component)
|
|||||||
function AddTokenScreen () {
|
function AddTokenScreen () {
|
||||||
this.state = {
|
this.state = {
|
||||||
warning: null,
|
warning: null,
|
||||||
address: null,
|
address: '',
|
||||||
symbol: 'TOKEN',
|
symbol: 'TOKEN',
|
||||||
decimals: 18,
|
decimals: 18,
|
||||||
}
|
}
|
||||||
@ -190,7 +190,7 @@ AddTokenScreen.prototype.validateInputs = function () {
|
|||||||
|
|
||||||
const validAddress = ethUtil.isValidAddress(address)
|
const validAddress = ethUtil.isValidAddress(address)
|
||||||
if (!validAddress) {
|
if (!validAddress) {
|
||||||
msg += 'Address is invalid. '
|
msg += 'Address is invalid.'
|
||||||
}
|
}
|
||||||
|
|
||||||
const validDecimals = decimals >= 0 && decimals < 36
|
const validDecimals = decimals >= 0 && decimals < 36
|
||||||
|
@ -30,7 +30,12 @@ ConfigScreen.prototype.render = function () {
|
|||||||
var warning = state.warning
|
var warning = state.warning
|
||||||
|
|
||||||
return (
|
return (
|
||||||
h('.flex-column.flex-grow', [
|
h('.flex-column.flex-grow', {
|
||||||
|
style:{
|
||||||
|
maxHeight: '465px',
|
||||||
|
overflowY: 'auto',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
|
||||||
h(Modal, {}, []),
|
h(Modal, {}, []),
|
||||||
|
|
||||||
@ -57,6 +62,7 @@ ConfigScreen.prototype.render = function () {
|
|||||||
h('.flex-space-around', {
|
h('.flex-space-around', {
|
||||||
style: {
|
style: {
|
||||||
padding: '20px',
|
padding: '20px',
|
||||||
|
overflow: 'auto',
|
||||||
},
|
},
|
||||||
}, [
|
}, [
|
||||||
|
|
||||||
@ -144,6 +150,40 @@ ConfigScreen.prototype.render = function () {
|
|||||||
}, 'Reveal Seed Words'),
|
}, 'Reveal Seed Words'),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
h('hr.horizontal-line'),
|
||||||
|
|
||||||
|
h('div', {
|
||||||
|
style: {
|
||||||
|
marginTop: '20px',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
|
||||||
|
h('p', {
|
||||||
|
style: {
|
||||||
|
fontFamily: 'Montserrat Light',
|
||||||
|
fontSize: '13px',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
'Resetting is for developer use only. ',
|
||||||
|
h('a', {
|
||||||
|
href: 'http://metamask.helpscoutdocs.com/article/36-resetting-an-account',
|
||||||
|
target: '_blank',
|
||||||
|
onClick (event) { this.navigateTo(event.target.href) },
|
||||||
|
}, 'Read more.'),
|
||||||
|
]),
|
||||||
|
h('br'),
|
||||||
|
|
||||||
|
h('button', {
|
||||||
|
style: {
|
||||||
|
alignSelf: 'center',
|
||||||
|
},
|
||||||
|
onClick (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
state.dispatch(actions.resetAccount())
|
||||||
|
},
|
||||||
|
}, 'Reset Account'),
|
||||||
|
]),
|
||||||
|
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
@ -220,3 +260,7 @@ function currentProviderDisplay (metamaskState) {
|
|||||||
h('span', value),
|
h('span', value),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfigScreen.prototype.navigateTo = function (url) {
|
||||||
|
global.platform.openWindow({ url })
|
||||||
|
}
|
||||||
|
14
package.json
14
package.json
@ -78,7 +78,7 @@
|
|||||||
"eth-bin-to-ops": "^1.0.1",
|
"eth-bin-to-ops": "^1.0.1",
|
||||||
"eth-block-tracker": "^2.3.0",
|
"eth-block-tracker": "^2.3.0",
|
||||||
"eth-json-rpc-filters": "^1.2.5",
|
"eth-json-rpc-filters": "^1.2.5",
|
||||||
"eth-json-rpc-infura": "^2.0.11",
|
"eth-json-rpc-infura": "^3.0.0",
|
||||||
"eth-keyring-controller": "^2.1.4",
|
"eth-keyring-controller": "^2.1.4",
|
||||||
"eth-contract-metadata": "^1.1.5",
|
"eth-contract-metadata": "^1.1.5",
|
||||||
"eth-hd-keyring": "^1.2.1",
|
"eth-hd-keyring": "^1.2.1",
|
||||||
@ -195,7 +195,7 @@
|
|||||||
"deep-freeze-strict": "^1.1.1",
|
"deep-freeze-strict": "^1.1.1",
|
||||||
"del": "^3.0.0",
|
"del": "^3.0.0",
|
||||||
"envify": "^4.0.0",
|
"envify": "^4.0.0",
|
||||||
"enzyme": "^3.2.0",
|
"enzyme": "^3.3.0",
|
||||||
"enzyme-adapter-react-15": "^1.0.5",
|
"enzyme-adapter-react-15": "^1.0.5",
|
||||||
"eslint-plugin-chai": "0.0.1",
|
"eslint-plugin-chai": "0.0.1",
|
||||||
"eslint-plugin-mocha": "^4.9.0",
|
"eslint-plugin-mocha": "^4.9.0",
|
||||||
@ -204,6 +204,7 @@
|
|||||||
"fs-promise": "^2.0.3",
|
"fs-promise": "^2.0.3",
|
||||||
"gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed",
|
"gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed",
|
||||||
"gulp-babel": "^7.0.0",
|
"gulp-babel": "^7.0.0",
|
||||||
|
"gulp-eslint": "^4.0.0",
|
||||||
"gulp-if": "^2.0.2",
|
"gulp-if": "^2.0.2",
|
||||||
"gulp-json-editor": "^2.2.1",
|
"gulp-json-editor": "^2.2.1",
|
||||||
"gulp-livereload": "^3.8.1",
|
"gulp-livereload": "^3.8.1",
|
||||||
@ -214,9 +215,8 @@
|
|||||||
"gulp-uglify": "^3.0.0",
|
"gulp-uglify": "^3.0.0",
|
||||||
"gulp-uglify-es": "^1.0.0",
|
"gulp-uglify-es": "^1.0.0",
|
||||||
"gulp-util": "^3.0.7",
|
"gulp-util": "^3.0.7",
|
||||||
"gulp-watch": "^4.3.5",
|
"gulp-watch": "^5.0.0",
|
||||||
"gulp-zip": "^4.0.0",
|
"gulp-zip": "^4.0.0",
|
||||||
"gulp-eslint": "^4.0.0",
|
|
||||||
"isomorphic-fetch": "^2.2.1",
|
"isomorphic-fetch": "^2.2.1",
|
||||||
"jsdom": "^11.1.0",
|
"jsdom": "^11.1.0",
|
||||||
"jsdom-global": "^3.0.2",
|
"jsdom-global": "^3.0.2",
|
||||||
@ -227,7 +227,7 @@
|
|||||||
"karma-firefox-launcher": "^1.0.1",
|
"karma-firefox-launcher": "^1.0.1",
|
||||||
"karma-qunit": "^1.2.1",
|
"karma-qunit": "^1.2.1",
|
||||||
"lodash.assign": "^4.0.6",
|
"lodash.assign": "^4.0.6",
|
||||||
"mocha": "^4.0.0",
|
"mocha": "^5.0.0",
|
||||||
"mocha-eslint": "^4.0.0",
|
"mocha-eslint": "^4.0.0",
|
||||||
"mocha-jsdom": "^1.1.0",
|
"mocha-jsdom": "^1.1.0",
|
||||||
"mocha-sinon": "^2.0.0",
|
"mocha-sinon": "^2.0.0",
|
||||||
@ -240,11 +240,11 @@
|
|||||||
"react-addons-test-utils": "^15.5.1",
|
"react-addons-test-utils": "^15.5.1",
|
||||||
"react-test-renderer": "^15.6.2",
|
"react-test-renderer": "^15.6.2",
|
||||||
"react-testutils-additions": "^15.2.0",
|
"react-testutils-additions": "^15.2.0",
|
||||||
"redux-test-utils": "^0.1.3",
|
"redux-test-utils": "^0.2.2",
|
||||||
"sinon": "^4.0.0",
|
"sinon": "^4.0.0",
|
||||||
"stylelint-config-standard": "^17.0.0",
|
"stylelint-config-standard": "^17.0.0",
|
||||||
"tape": "^4.5.1",
|
"tape": "^4.5.1",
|
||||||
"testem": "^1.10.3",
|
"testem": "^2.0.0",
|
||||||
"uglifyify": "^4.0.2",
|
"uglifyify": "^4.0.2",
|
||||||
"vinyl-buffer": "^1.0.1",
|
"vinyl-buffer": "^1.0.1",
|
||||||
"vinyl-source-stream": "^2.0.0",
|
"vinyl-source-stream": "^2.0.0",
|
||||||
|
153
test/integration/lib/add-token.js
Normal file
153
test/integration/lib/add-token.js
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
const reactTriggerChange = require('react-trigger-change')
|
||||||
|
|
||||||
|
QUnit.module('Add token flow')
|
||||||
|
|
||||||
|
QUnit.test('successful add token flow', (assert) => {
|
||||||
|
const done = assert.async()
|
||||||
|
runAddTokenFlowTest(assert)
|
||||||
|
.then(done)
|
||||||
|
.catch(err => {
|
||||||
|
assert.notOk(err, `Error was thrown: ${err.stack}`)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
async function runAddTokenFlowTest (assert, done) {
|
||||||
|
const selectState = $('select')
|
||||||
|
selectState.val('add token')
|
||||||
|
reactTriggerChange(selectState[0])
|
||||||
|
|
||||||
|
await timeout(2000)
|
||||||
|
|
||||||
|
// Check that no tokens have been added
|
||||||
|
assert.ok($('.token-list-item').length === 0, 'no tokens added')
|
||||||
|
|
||||||
|
// Go to Add Token screen
|
||||||
|
let addTokenButton = $('button.btn-clear.wallet-view__add-token-button')
|
||||||
|
assert.ok(addTokenButton[0], 'add token button present')
|
||||||
|
addTokenButton[0].click()
|
||||||
|
|
||||||
|
await timeout(1000)
|
||||||
|
|
||||||
|
// Verify Add Token screen
|
||||||
|
let addTokenWrapper = $('.add-token__wrapper')
|
||||||
|
assert.ok(addTokenWrapper[0], 'add token wrapper renders')
|
||||||
|
|
||||||
|
let addTokenTitle = $('.add-token__title')
|
||||||
|
assert.equal(addTokenTitle[0].textContent, 'Add Token', 'add token title is correct')
|
||||||
|
|
||||||
|
// Cancel Add Token
|
||||||
|
const cancelAddTokenButton = $('button.btn-cancel.add-token__button')
|
||||||
|
assert.ok(cancelAddTokenButton[0], 'cancel add token button present')
|
||||||
|
cancelAddTokenButton.click()
|
||||||
|
|
||||||
|
await timeout(1000)
|
||||||
|
|
||||||
|
assert.ok($('.wallet-view')[0], 'cancelled and returned to account detail wallet view')
|
||||||
|
|
||||||
|
// Return to Add Token Screen
|
||||||
|
addTokenButton = $('button.btn-clear.wallet-view__add-token-button')
|
||||||
|
assert.ok(addTokenButton[0], 'add token button present')
|
||||||
|
addTokenButton[0].click()
|
||||||
|
|
||||||
|
await timeout(1000)
|
||||||
|
|
||||||
|
// Verify Add Token Screen
|
||||||
|
addTokenWrapper = $('.add-token__wrapper')
|
||||||
|
addTokenTitle = $('.add-token__title')
|
||||||
|
assert.ok(addTokenWrapper[0], 'add token wrapper renders')
|
||||||
|
assert.equal(addTokenTitle[0].textContent, 'Add Token', 'add token title is correct')
|
||||||
|
|
||||||
|
// Search for token
|
||||||
|
const searchInput = $('input.add-token__input')
|
||||||
|
searchInput.val('a')
|
||||||
|
reactTriggerChange(searchInput[0])
|
||||||
|
|
||||||
|
await timeout()
|
||||||
|
|
||||||
|
// Click token to add
|
||||||
|
const tokenWrapper = $('div.add-token__token-wrapper')
|
||||||
|
assert.ok(tokenWrapper[0], 'token found')
|
||||||
|
const tokenImageProp = tokenWrapper.find('.add-token__token-icon').css('background-image')
|
||||||
|
const tokenImageUrl = tokenImageProp.slice(5, -2)
|
||||||
|
tokenWrapper[0].click()
|
||||||
|
|
||||||
|
await timeout()
|
||||||
|
|
||||||
|
// Click Next button
|
||||||
|
let nextButton = $('button.btn-clear.add-token__button')
|
||||||
|
assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
|
||||||
|
nextButton[0].click()
|
||||||
|
|
||||||
|
await timeout()
|
||||||
|
|
||||||
|
// Confirm Add token
|
||||||
|
assert.equal(
|
||||||
|
$('.add-token__description')[0].textContent,
|
||||||
|
'Would you like to add these tokens?',
|
||||||
|
'confirm add token rendered'
|
||||||
|
)
|
||||||
|
assert.ok($('button.btn-clear.add-token__button')[0], 'confirm add token button found')
|
||||||
|
$('button.btn-clear.add-token__button')[0].click()
|
||||||
|
|
||||||
|
await timeout(2000)
|
||||||
|
|
||||||
|
// Verify added token image
|
||||||
|
let heroBalance = $('.hero-balance')
|
||||||
|
assert.ok(heroBalance, 'rendered hero balance')
|
||||||
|
assert.ok(tokenImageUrl.indexOf(heroBalance.find('img').attr('src')) > -1, 'token added')
|
||||||
|
|
||||||
|
// Return to Add Token Screen
|
||||||
|
addTokenButton = $('button.btn-clear.wallet-view__add-token-button')
|
||||||
|
assert.ok(addTokenButton[0], 'add token button present')
|
||||||
|
addTokenButton[0].click()
|
||||||
|
|
||||||
|
await timeout(1000)
|
||||||
|
|
||||||
|
const addCustom = $('.add-token__add-custom')
|
||||||
|
assert.ok(addCustom[0], 'add custom token button present')
|
||||||
|
addCustom[0].click()
|
||||||
|
|
||||||
|
await timeout()
|
||||||
|
|
||||||
|
// Input token contract address
|
||||||
|
const customInput = $('input.add-token__add-custom-input')
|
||||||
|
customInput.val('0x177af043D3A1Aed7cc5f2397C70248Fc6cDC056c')
|
||||||
|
reactTriggerChange(customInput[0])
|
||||||
|
|
||||||
|
await timeout(1000)
|
||||||
|
|
||||||
|
// Click Next button
|
||||||
|
nextButton = $('button.btn-clear.add-token__button')
|
||||||
|
assert.equal(nextButton[0].textContent, 'Next', 'next button rendered')
|
||||||
|
nextButton[0].click()
|
||||||
|
|
||||||
|
await timeout(1000)
|
||||||
|
|
||||||
|
// Verify symbol length error since contract address won't return symbol
|
||||||
|
const errorMessage = $('.add-token__add-custom-error-message')
|
||||||
|
assert.ok(errorMessage[0], 'error rendered')
|
||||||
|
$('button.btn-cancel.add-token__button')[0].click()
|
||||||
|
|
||||||
|
await timeout(2000)
|
||||||
|
|
||||||
|
// // Confirm Add token
|
||||||
|
// assert.equal(
|
||||||
|
// $('.add-token__description')[0].textContent,
|
||||||
|
// 'Would you like to add these tokens?',
|
||||||
|
// 'confirm add token rendered'
|
||||||
|
// )
|
||||||
|
// assert.ok($('button.btn-clear.add-token__button')[0], 'confirm add token button found')
|
||||||
|
// $('button.btn-clear.add-token__button')[0].click()
|
||||||
|
|
||||||
|
// // Verify added token image
|
||||||
|
// heroBalance = $('.hero-balance')
|
||||||
|
// assert.ok(heroBalance, 'rendered hero balance')
|
||||||
|
// assert.ok(heroBalance.find('.identicon')[0], 'token added')
|
||||||
|
}
|
||||||
|
|
||||||
|
function timeout (time) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
setTimeout(resolve, time || 1500)
|
||||||
|
})
|
||||||
|
}
|
67
test/integration/lib/confirm-sig-requests.js
Normal file
67
test/integration/lib/confirm-sig-requests.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
const reactTriggerChange = require('react-trigger-change')
|
||||||
|
|
||||||
|
const PASSWORD = 'password123'
|
||||||
|
|
||||||
|
QUnit.module('confirm sig requests')
|
||||||
|
|
||||||
|
QUnit.test('successful confirmation of sig requests', (assert) => {
|
||||||
|
const done = assert.async()
|
||||||
|
runConfirmSigRequestsTest(assert).then(done).catch((err) => {
|
||||||
|
assert.notOk(err, `Error was thrown: ${err.stack}`)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
async function runConfirmSigRequestsTest(assert, done) {
|
||||||
|
let selectState = $('select')
|
||||||
|
selectState.val('confirm sig requests')
|
||||||
|
reactTriggerChange(selectState[0])
|
||||||
|
|
||||||
|
await timeout(2000)
|
||||||
|
|
||||||
|
let confirmSigHeadline = $('.request-signature__headline')
|
||||||
|
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
|
||||||
|
|
||||||
|
let confirmSigRowValue = $('.request-signature__row-value')
|
||||||
|
assert.ok(confirmSigRowValue[0].textContent.match(/^\#\sTerms\sof\sUse/))
|
||||||
|
|
||||||
|
let confirmSigSignButton = $('.request-signature__footer__sign-button')
|
||||||
|
confirmSigSignButton[0].click()
|
||||||
|
|
||||||
|
await timeout(2000)
|
||||||
|
|
||||||
|
confirmSigHeadline = $('.request-signature__headline')
|
||||||
|
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
|
||||||
|
|
||||||
|
let confirmSigMessage = $('.request-signature__notice')
|
||||||
|
assert.ok(confirmSigMessage[0].textContent.match(/^Signing\sthis\smessage/))
|
||||||
|
|
||||||
|
confirmSigRowValue = $('.request-signature__row-value')
|
||||||
|
assert.equal(confirmSigRowValue[0].textContent, '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0')
|
||||||
|
|
||||||
|
confirmSigSignButton = $('.request-signature__footer__sign-button')
|
||||||
|
confirmSigSignButton[0].click()
|
||||||
|
|
||||||
|
await timeout(2000)
|
||||||
|
|
||||||
|
confirmSigHeadline = $('.request-signature__headline')
|
||||||
|
assert.equal(confirmSigHeadline[0].textContent, 'Your signature is being requested')
|
||||||
|
|
||||||
|
confirmSigRowValue = $('.request-signature__row-value')
|
||||||
|
assert.equal(confirmSigRowValue[0].textContent, 'Hi, Alice!')
|
||||||
|
assert.equal(confirmSigRowValue[1].textContent, '1337')
|
||||||
|
|
||||||
|
confirmSigSignButton = $('.request-signature__footer__sign-button')
|
||||||
|
confirmSigSignButton[0].click()
|
||||||
|
|
||||||
|
await timeout(2000)
|
||||||
|
|
||||||
|
const txView = $('.tx-view')
|
||||||
|
assert.ok(txView[0], 'Should return to the account details screen after confirming')
|
||||||
|
}
|
||||||
|
|
||||||
|
function timeout (time) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
setTimeout(resolve, time || 1500)
|
||||||
|
})
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
const reactTriggerChange = require('react-trigger-change')
|
||||||
const PASSWORD = 'password123'
|
const PASSWORD = 'password123'
|
||||||
const runMascaraFirstTimeTest = require('./mascara-first-time')
|
const runMascaraFirstTimeTest = require('./mascara-first-time')
|
||||||
|
|
||||||
@ -16,6 +17,12 @@ async function runFirstTimeUsageTest(assert, done) {
|
|||||||
return runMascaraFirstTimeTest(assert, done)
|
return runMascaraFirstTimeTest(assert, done)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selectState = $('select')
|
||||||
|
selectState.val('first time')
|
||||||
|
reactTriggerChange(selectState[0])
|
||||||
|
|
||||||
|
await timeout(2000)
|
||||||
|
|
||||||
const app = $('#app-content')
|
const app = $('#app-content')
|
||||||
|
|
||||||
// recurse notices
|
// recurse notices
|
||||||
|
@ -30,16 +30,10 @@ async function runSendFlowTest(assert, done) {
|
|||||||
|
|
||||||
await timeout(1000)
|
await timeout(1000)
|
||||||
|
|
||||||
const sendContainer = $('.send-v2__container')
|
const sendTitle = $('.page-container__title')
|
||||||
assert.ok(sendContainer[0], 'send container renders')
|
assert.equal(sendTitle[0].textContent, 'Send ETH', 'Send screen title is correct')
|
||||||
|
|
||||||
const sendHeader = $('.send-v2__send-header-icon')
|
const sendCopy = $('.page-container__subtitle')
|
||||||
assert.ok(sendHeader[0], 'send screen has a header icon')
|
|
||||||
|
|
||||||
const sendTitle = $('.send-v2__title')
|
|
||||||
assert.equal(sendTitle[0].textContent, 'Send Funds', 'Send screen title is correct')
|
|
||||||
|
|
||||||
const sendCopy = $('.send-v2__copy')
|
|
||||||
assert.equal(sendCopy[0].textContent, 'Only send ETH to an Ethereum address.', 'Send screen has copy')
|
assert.equal(sendCopy[0].textContent, 'Only send ETH to an Ethereum address.', 'Send screen has copy')
|
||||||
|
|
||||||
const sendFromField = $('.send-v2__form-field')
|
const sendFromField = $('.send-v2__form-field')
|
||||||
@ -120,7 +114,7 @@ async function runSendFlowTest(assert, done) {
|
|||||||
|
|
||||||
const customizeGasModal = $('.send-v2__customize-gas')
|
const customizeGasModal = $('.send-v2__customize-gas')
|
||||||
assert.ok(customizeGasModal[0], 'should render the customize gas modal')
|
assert.ok(customizeGasModal[0], 'should render the customize gas modal')
|
||||||
|
|
||||||
const customizeGasPriceInput = $('.send-v2__gas-modal-card').first().find('input')
|
const customizeGasPriceInput = $('.send-v2__gas-modal-card').first().find('input')
|
||||||
customizeGasPriceInput.val(50)
|
customizeGasPriceInput.val(50)
|
||||||
reactTriggerChange(customizeGasPriceInput[0])
|
reactTriggerChange(customizeGasPriceInput[0])
|
||||||
@ -146,7 +140,8 @@ async function runSendFlowTest(assert, done) {
|
|||||||
'send gas field should show customized gas total converted to USD'
|
'send gas field should show customized gas total converted to USD'
|
||||||
)
|
)
|
||||||
|
|
||||||
const sendButton = $('.send-v2__next-btn')
|
const sendButton = $('button.btn-clear.page-container__footer-button')
|
||||||
|
assert.equal(sendButton[0].textContent, 'Next', 'next button rendered')
|
||||||
sendButton[0].click()
|
sendButton[0].click()
|
||||||
|
|
||||||
await timeout(2000)
|
await timeout(2000)
|
||||||
@ -200,7 +195,8 @@ async function runSendFlowTest(assert, done) {
|
|||||||
|
|
||||||
await timeout()
|
await timeout()
|
||||||
|
|
||||||
const sendButtonInEdit = $('.send-v2__next-btn')
|
const sendButtonInEdit = $('.btn-clear.page-container__footer-button')
|
||||||
|
assert.equal(sendButtonInEdit[0].textContent, 'Next', 'next button in edit rendered')
|
||||||
sendButtonInEdit[0].click()
|
sendButtonInEdit[0].click()
|
||||||
|
|
||||||
await timeout()
|
await timeout()
|
||||||
|
1
test/lib/migrations/002.json
Normal file
1
test/lib/migrations/002.json
Normal file
File diff suppressed because one or more lines are too long
@ -1,16 +1,20 @@
|
|||||||
const { shallow, mount } = require('enzyme')
|
const { shallow, mount } = require('enzyme')
|
||||||
|
|
||||||
exports.shallowWithStore = function shallowWithStore (component, store) {
|
module.exports = {
|
||||||
|
shallowWithStore,
|
||||||
|
mountWithStore,
|
||||||
|
}
|
||||||
|
|
||||||
|
function shallowWithStore (component, store) {
|
||||||
const context = {
|
const context = {
|
||||||
store,
|
store,
|
||||||
}
|
}
|
||||||
|
return shallow(component, {context})
|
||||||
return shallow(component, { context })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.mountWithStore = function mountWithStore (component, store) {
|
function mountWithStore (component, store) {
|
||||||
const context = {
|
const context = {
|
||||||
store,
|
store,
|
||||||
}
|
}
|
||||||
return mount(component, { context })
|
return mount(component, {context})
|
||||||
}
|
}
|
||||||
|
16
test/unit/migrations/021-test.js
Normal file
16
test/unit/migrations/021-test.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const assert = require('assert')
|
||||||
|
|
||||||
|
const wallet2 = require('../../lib/migrations/002.json')
|
||||||
|
const migration21 = require('../../../app/scripts/migrations/021')
|
||||||
|
|
||||||
|
describe('wallet2 is migrated successfully with out the BlacklistController', () => {
|
||||||
|
it('should delete BlacklistController key', (done) => {
|
||||||
|
migration21.migrate(wallet2)
|
||||||
|
.then((migratedData) => {
|
||||||
|
assert.equal(migratedData.meta.version, 21)
|
||||||
|
assert(!migratedData.data.BlacklistController)
|
||||||
|
assert(!migratedData.data.RecentBlocks)
|
||||||
|
done()
|
||||||
|
}).catch(done)
|
||||||
|
})
|
||||||
|
})
|
@ -238,4 +238,47 @@ describe('TransactionStateManger', function () {
|
|||||||
assert.equal(txStateManager.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`)
|
assert.equal(txStateManager.getFilteredTxList(filterParams).length, 5, `getFilteredTxList - ${JSON.stringify(filterParams)}`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('#wipeTransactions', function () {
|
||||||
|
|
||||||
|
const specificAddress = '0xaa'
|
||||||
|
const otherAddress = '0xbb'
|
||||||
|
|
||||||
|
it('should remove only the transactions from a specific address', function () {
|
||||||
|
|
||||||
|
const txMetas = [
|
||||||
|
{ id: 0, status: 'unapproved', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: currentNetworkId },
|
||||||
|
{ id: 1, status: 'confirmed', txParams: { from: otherAddress, to: specificAddress }, metamaskNetworkId: currentNetworkId },
|
||||||
|
{ id: 2, status: 'confirmed', txParams: { from: otherAddress, to: specificAddress }, metamaskNetworkId: currentNetworkId },
|
||||||
|
]
|
||||||
|
txMetas.forEach((txMeta) => txStateManager.addTx(txMeta, noop))
|
||||||
|
|
||||||
|
txStateManager.wipeTransactions(specificAddress)
|
||||||
|
|
||||||
|
const transactionsFromCurrentAddress = txStateManager.getTxList().filter((txMeta) => txMeta.txParams.from === specificAddress)
|
||||||
|
const transactionsFromOtherAddresses = txStateManager.getTxList().filter((txMeta) => txMeta.txParams.from !== specificAddress)
|
||||||
|
|
||||||
|
assert.equal(transactionsFromCurrentAddress.length, 0)
|
||||||
|
assert.equal(transactionsFromOtherAddresses.length, 2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not remove the transactions from other networks', function () {
|
||||||
|
const txMetas = [
|
||||||
|
{ id: 0, status: 'unapproved', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: currentNetworkId },
|
||||||
|
{ id: 1, status: 'confirmed', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: otherNetworkId },
|
||||||
|
{ id: 2, status: 'confirmed', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: otherNetworkId },
|
||||||
|
]
|
||||||
|
|
||||||
|
txMetas.forEach((txMeta) => txStateManager.addTx(txMeta, noop))
|
||||||
|
|
||||||
|
txStateManager.wipeTransactions(specificAddress)
|
||||||
|
|
||||||
|
const txsFromCurrentNetworkAndAddress = txStateManager.getTxList().filter((txMeta) => txMeta.txParams.from === specificAddress)
|
||||||
|
const txFromOtherNetworks = txStateManager.getFullTxList().filter((txMeta) => txMeta.metamaskNetworkId === otherNetworkId)
|
||||||
|
|
||||||
|
assert.equal(txsFromCurrentNetworkAndAddress.length, 0)
|
||||||
|
assert.equal(txFromOtherNetworks.length, 2)
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
43
test/unit/ui/add-token.spec.js
Normal file
43
test/unit/ui/add-token.spec.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const assert = require('assert')
|
||||||
|
const { createMockStore } = require('redux-test-utils')
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
const { shallowWithStore } = require('../../lib/shallow-with-store')
|
||||||
|
const AddTokenScreen = require('../../../old-ui/app/add-token')
|
||||||
|
|
||||||
|
describe('Add Token Screen', function () {
|
||||||
|
let addTokenComponent, store, component
|
||||||
|
const mockState = {
|
||||||
|
metamask: {
|
||||||
|
identities: {
|
||||||
|
'0x7d3517b0d011698406d6e0aed8453f0be2697926': {
|
||||||
|
'address': '0x7d3517b0d011698406d6e0aed8453f0be2697926',
|
||||||
|
'name': 'Add Token Name',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
beforeEach(function () {
|
||||||
|
store = createMockStore(mockState)
|
||||||
|
component = shallowWithStore(h(AddTokenScreen), store)
|
||||||
|
addTokenComponent = component.dive()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#ValidateInputs', function () {
|
||||||
|
|
||||||
|
it('Default State', function () {
|
||||||
|
addTokenComponent.instance().validateInputs()
|
||||||
|
const state = addTokenComponent.state()
|
||||||
|
assert.equal(state.warning, 'Address is invalid.')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Address is a Metamask Identity', function () {
|
||||||
|
addTokenComponent.setState({
|
||||||
|
address: '0x7d3517b0d011698406d6e0aed8453f0be2697926',
|
||||||
|
})
|
||||||
|
addTokenComponent.instance().validateInputs()
|
||||||
|
const state = addTokenComponent.state()
|
||||||
|
assert.equal(state.warning, 'Personal address detected. Input the token contract address.')
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
@ -13,12 +13,7 @@ function AccountAndTransactionDetails () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AccountAndTransactionDetails.prototype.render = function () {
|
AccountAndTransactionDetails.prototype.render = function () {
|
||||||
return h('div', {
|
return h('div.account-and-transaction-details', [
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
flex: '1 0 auto',
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
// wallet
|
// wallet
|
||||||
h(WalletView, {
|
h(WalletView, {
|
||||||
style: {
|
style: {
|
||||||
|
@ -47,6 +47,8 @@ var actions = {
|
|||||||
SHOW_RESTORE_VAULT: 'SHOW_RESTORE_VAULT',
|
SHOW_RESTORE_VAULT: 'SHOW_RESTORE_VAULT',
|
||||||
FORGOT_PASSWORD: 'FORGOT_PASSWORD',
|
FORGOT_PASSWORD: 'FORGOT_PASSWORD',
|
||||||
forgotPassword: forgotPassword,
|
forgotPassword: forgotPassword,
|
||||||
|
markPasswordForgotten,
|
||||||
|
unMarkPasswordForgotten,
|
||||||
SHOW_INIT_MENU: 'SHOW_INIT_MENU',
|
SHOW_INIT_MENU: 'SHOW_INIT_MENU',
|
||||||
SHOW_NEW_VAULT_SEED: 'SHOW_NEW_VAULT_SEED',
|
SHOW_NEW_VAULT_SEED: 'SHOW_NEW_VAULT_SEED',
|
||||||
SHOW_INFO_PAGE: 'SHOW_INFO_PAGE',
|
SHOW_INFO_PAGE: 'SHOW_INFO_PAGE',
|
||||||
@ -70,12 +72,14 @@ var actions = {
|
|||||||
addNewAccount,
|
addNewAccount,
|
||||||
NEW_ACCOUNT_SCREEN: 'NEW_ACCOUNT_SCREEN',
|
NEW_ACCOUNT_SCREEN: 'NEW_ACCOUNT_SCREEN',
|
||||||
navigateToNewAccountScreen,
|
navigateToNewAccountScreen,
|
||||||
|
resetAccount,
|
||||||
showNewVaultSeed: showNewVaultSeed,
|
showNewVaultSeed: showNewVaultSeed,
|
||||||
showInfoPage: showInfoPage,
|
showInfoPage: showInfoPage,
|
||||||
// seed recovery actions
|
// seed recovery actions
|
||||||
REVEAL_SEED_CONFIRMATION: 'REVEAL_SEED_CONFIRMATION',
|
REVEAL_SEED_CONFIRMATION: 'REVEAL_SEED_CONFIRMATION',
|
||||||
revealSeedConfirmation: revealSeedConfirmation,
|
revealSeedConfirmation: revealSeedConfirmation,
|
||||||
requestRevealSeed: requestRevealSeed,
|
requestRevealSeed: requestRevealSeed,
|
||||||
|
|
||||||
// unlock screen
|
// unlock screen
|
||||||
UNLOCK_IN_PROGRESS: 'UNLOCK_IN_PROGRESS',
|
UNLOCK_IN_PROGRESS: 'UNLOCK_IN_PROGRESS',
|
||||||
UNLOCK_FAILED: 'UNLOCK_FAILED',
|
UNLOCK_FAILED: 'UNLOCK_FAILED',
|
||||||
@ -404,6 +408,20 @@ function requestRevealSeed (password) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resetAccount () {
|
||||||
|
return (dispatch) => {
|
||||||
|
background.resetAccount((err, account) => {
|
||||||
|
dispatch(actions.hideLoadingIndication())
|
||||||
|
if (err) {
|
||||||
|
dispatch(actions.displayWarning(err.message))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info('Transaction history reset for ' + account)
|
||||||
|
dispatch(actions.showAccountsPage())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function addNewKeyring (type, opts) {
|
function addNewKeyring (type, opts) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(actions.showLoadingIndication())
|
dispatch(actions.showLoadingIndication())
|
||||||
@ -897,6 +915,28 @@ function showRestoreVault () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function markPasswordForgotten () {
|
||||||
|
return (dispatch) => {
|
||||||
|
dispatch(actions.showLoadingIndication())
|
||||||
|
return background.markPasswordForgotten(() => {
|
||||||
|
dispatch(actions.hideLoadingIndication())
|
||||||
|
dispatch(actions.forgotPassword())
|
||||||
|
forceUpdateMetamaskState(dispatch)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unMarkPasswordForgotten () {
|
||||||
|
return (dispatch) => {
|
||||||
|
dispatch(actions.showLoadingIndication())
|
||||||
|
return background.unMarkPasswordForgotten(() => {
|
||||||
|
dispatch(actions.hideLoadingIndication())
|
||||||
|
dispatch(actions.forgotPassword())
|
||||||
|
forceUpdateMetamaskState(dispatch)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function forgotPassword () {
|
function forgotPassword () {
|
||||||
return {
|
return {
|
||||||
type: actions.FORGOT_PASSWORD,
|
type: actions.FORGOT_PASSWORD,
|
||||||
|
@ -352,7 +352,6 @@ class App extends Component {
|
|||||||
const {
|
const {
|
||||||
noActiveNotices,
|
noActiveNotices,
|
||||||
lostAccounts,
|
lostAccounts,
|
||||||
isInitialized,
|
|
||||||
forgottenPassword,
|
forgottenPassword,
|
||||||
currentView,
|
currentView,
|
||||||
activeAddress,
|
activeAddress,
|
||||||
@ -373,6 +372,15 @@ class App extends Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (forgottenPassword) {
|
||||||
|
log.debug('rendering restore vault screen')
|
||||||
|
return h(Redirect, {
|
||||||
|
to: {
|
||||||
|
pathname: RESTORE_VAULT_ROUTE,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// notices
|
// notices
|
||||||
if (!noActiveNotices || (lostAccounts && lostAccounts.length > 0)) {
|
if (!noActiveNotices || (lostAccounts && lostAccounts.length > 0)) {
|
||||||
return h(Redirect, {
|
return h(Redirect, {
|
||||||
@ -422,20 +430,20 @@ class App extends Component {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// show initialize screen
|
// show initialize screen
|
||||||
if (!isInitialized || forgottenPassword) {
|
// if (!isInitialized || forgottenPassword) {
|
||||||
// show current view
|
// // show current view
|
||||||
log.debug('rendering an initialize screen')
|
// log.debug('rendering an initialize screen')
|
||||||
// switch (props.currentView.name) {
|
// // switch (props.currentView.name) {
|
||||||
|
|
||||||
// case 'restoreVault':
|
// // case 'restoreVault':
|
||||||
// log.debug('rendering restore vault screen')
|
// // log.debug('rendering restore vault screen')
|
||||||
// return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'})
|
// // return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'})
|
||||||
|
|
||||||
// default:
|
// // default:
|
||||||
// log.debug('rendering menu screen')
|
// // log.debug('rendering menu screen')
|
||||||
// return h(InitializeMenuScreen, {key: 'menuScreenInit'})
|
// // return h(InitializeMenuScreen, {key: 'menuScreenInit'})
|
||||||
// }
|
// // }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// // show unlock screen
|
// // show unlock screen
|
||||||
// if (!props.isUnlocked) {
|
// if (!props.isUnlocked) {
|
||||||
|
@ -90,7 +90,7 @@ AccountMenu.prototype.render = function () {
|
|||||||
toggleAccountMenu()
|
toggleAccountMenu()
|
||||||
history.push(NEW_ACCOUNT_ROUTE)
|
history.push(NEW_ACCOUNT_ROUTE)
|
||||||
},
|
},
|
||||||
icon: h('img', { src: 'images/plus-btn-white.svg' }),
|
icon: h('img.account-menu__item-icon', { src: 'images/plus-btn-white.svg' }),
|
||||||
text: 'Create Account',
|
text: 'Create Account',
|
||||||
}),
|
}),
|
||||||
h(Item, {
|
h(Item, {
|
||||||
@ -98,7 +98,7 @@ AccountMenu.prototype.render = function () {
|
|||||||
toggleAccountMenu()
|
toggleAccountMenu()
|
||||||
history.push(IMPORT_ACCOUNT_ROUTE)
|
history.push(IMPORT_ACCOUNT_ROUTE)
|
||||||
},
|
},
|
||||||
icon: h('img', { src: 'images/import-account.svg' }),
|
icon: h('img.account-menu__item-icon', { src: 'images/import-account.svg' }),
|
||||||
text: 'Import Account',
|
text: 'Import Account',
|
||||||
}),
|
}),
|
||||||
h(Divider),
|
h(Divider),
|
||||||
@ -107,7 +107,7 @@ AccountMenu.prototype.render = function () {
|
|||||||
toggleAccountMenu()
|
toggleAccountMenu()
|
||||||
history.push(INFO_ROUTE)
|
history.push(INFO_ROUTE)
|
||||||
},
|
},
|
||||||
icon: h('img', { src: 'images/mm-info-icon.svg' }),
|
icon: h('img.account-menu__item-icon', { src: 'images/mm-info-icon.svg' }),
|
||||||
text: 'Info & Help',
|
text: 'Info & Help',
|
||||||
}),
|
}),
|
||||||
h(Item, {
|
h(Item, {
|
||||||
@ -115,7 +115,7 @@ AccountMenu.prototype.render = function () {
|
|||||||
toggleAccountMenu()
|
toggleAccountMenu()
|
||||||
history.push(SETTINGS_ROUTE)
|
history.push(SETTINGS_ROUTE)
|
||||||
},
|
},
|
||||||
icon: h('img', { src: 'images/settings.svg' }),
|
icon: h('img.account-menu__item-icon', { src: 'images/settings.svg' }),
|
||||||
text: 'Settings',
|
text: 'Settings',
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
@ -87,6 +87,12 @@ JsonImportSubview.prototype.createKeyringOnEnter = function (event) {
|
|||||||
|
|
||||||
JsonImportSubview.prototype.createNewKeychain = function () {
|
JsonImportSubview.prototype.createNewKeychain = function () {
|
||||||
const state = this.state
|
const state = this.state
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
const message = 'You must select a valid file to import.'
|
||||||
|
return this.props.dispatch(actions.displayWarning(message))
|
||||||
|
}
|
||||||
|
|
||||||
const { fileContents } = state
|
const { fileContents } = state
|
||||||
|
|
||||||
if (!fileContents) {
|
if (!fileContents) {
|
||||||
|
@ -4,11 +4,11 @@ const { connect } = require('react-redux')
|
|||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const { withRouter } = require('react-router-dom')
|
const { withRouter } = require('react-router-dom')
|
||||||
const { compose } = require('recompose')
|
const { compose } = require('recompose')
|
||||||
const { tryUnlockMetamask, forgotPassword } = require('../../actions')
|
const { tryUnlockMetamask, forgotPassword, markPasswordForgotten } = require('../../actions')
|
||||||
const getCaretCoordinates = require('textarea-caret')
|
const getCaretCoordinates = require('textarea-caret')
|
||||||
const EventEmitter = require('events').EventEmitter
|
const EventEmitter = require('events').EventEmitter
|
||||||
const Mascot = require('../mascot')
|
const Mascot = require('../mascot')
|
||||||
const { DEFAULT_ROUTE, RESTORE_VAULT_ROUTE } = require('../../routes')
|
const { DEFAULT_ROUTE } = require('../../routes')
|
||||||
|
|
||||||
class UnlockScreen extends Component {
|
class UnlockScreen extends Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@ -77,7 +77,7 @@ class UnlockScreen extends Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { error } = this.state
|
const { error } = this.state
|
||||||
const { history } = this.props
|
const { markPasswordForgotten } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
h('.unlock-page.main-container', [
|
h('.unlock-page.main-container', [
|
||||||
@ -128,7 +128,10 @@ class UnlockScreen extends Component {
|
|||||||
|
|
||||||
h('.flex-row.flex-center.flex-grow', [
|
h('.flex-row.flex-center.flex-grow', [
|
||||||
h('p.pointer', {
|
h('p.pointer', {
|
||||||
onClick: () => history.push(RESTORE_VAULT_ROUTE),
|
onClick: () => {
|
||||||
|
markPasswordForgotten()
|
||||||
|
global.platform.openExtensionInBrowser()
|
||||||
|
},
|
||||||
style: {
|
style: {
|
||||||
fontSize: '0.8em',
|
fontSize: '0.8em',
|
||||||
color: 'rgb(247, 134, 28)',
|
color: 'rgb(247, 134, 28)',
|
||||||
@ -146,6 +149,7 @@ class UnlockScreen extends Component {
|
|||||||
UnlockScreen.propTypes = {
|
UnlockScreen.propTypes = {
|
||||||
forgotPassword: PropTypes.func,
|
forgotPassword: PropTypes.func,
|
||||||
tryUnlockMetamask: PropTypes.func,
|
tryUnlockMetamask: PropTypes.func,
|
||||||
|
markPasswordForgotten: PropTypes.func,
|
||||||
history: PropTypes.object,
|
history: PropTypes.object,
|
||||||
isUnlocked: PropTypes.bool,
|
isUnlocked: PropTypes.bool,
|
||||||
}
|
}
|
||||||
@ -161,6 +165,7 @@ const mapDispatchToProps = dispatch => {
|
|||||||
return {
|
return {
|
||||||
forgotPassword: () => dispatch(forgotPassword()),
|
forgotPassword: () => dispatch(forgotPassword()),
|
||||||
tryUnlockMetamask: password => dispatch(tryUnlockMetamask(password)),
|
tryUnlockMetamask: password => dispatch(tryUnlockMetamask(password)),
|
||||||
|
markPasswordForgotten: () => dispatch(markPasswordForgotten()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,20 +111,24 @@ TokenCell.prototype.render = function () {
|
|||||||
network,
|
network,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
h('h.token-list-item__balance-wrapper', null, [
|
h('div.token-list-item__balance-ellipsis', null, [
|
||||||
h('h3.token-list-item__token-balance', `${string || 0} ${symbol}`),
|
h('div.token-list-item__balance-wrapper', null, [
|
||||||
|
h('h3.token-list-item__token-balance', `${string || 0} ${symbol}`),
|
||||||
|
|
||||||
|
showFiat && h('div.token-list-item__fiat-amount', {
|
||||||
|
style: {},
|
||||||
|
}, formattedFiat),
|
||||||
|
]),
|
||||||
|
|
||||||
|
h('i.fa.fa-ellipsis-h.fa-lg.token-list-item__ellipsis.cursor-pointer', {
|
||||||
|
onClick: (e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
this.setState({ tokenMenuOpen: true })
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
showFiat && h('div.token-list-item__fiat-amount', {
|
|
||||||
style: {},
|
|
||||||
}, formattedFiat),
|
|
||||||
]),
|
]),
|
||||||
|
|
||||||
h('i.fa.fa-ellipsis-h.fa-lg.token-list-item__ellipsis.cursor-pointer', {
|
|
||||||
onClick: (e) => {
|
|
||||||
e.stopPropagation()
|
|
||||||
this.setState({ tokenMenuOpen: true })
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
tokenMenuOpen && h(TokenMenuDropdown, {
|
tokenMenuOpen && h(TokenMenuDropdown, {
|
||||||
onClose: () => this.setState({ tokenMenuOpen: false }),
|
onClose: () => this.setState({ tokenMenuOpen: false }),
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
&__item-icon {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,22 @@
|
|||||||
font-size: 105%;
|
font-size: 105%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media #{$sub-mid-size-breakpoint-range} {
|
||||||
|
margin-left: .4em;
|
||||||
|
margin-right: .4em;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
.token-amount {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fiat-amount {
|
||||||
|
margin-top: .25%;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-balance-buttons {
|
.hero-balance-buttons {
|
||||||
@ -91,4 +107,12 @@
|
|||||||
|
|
||||||
.hero-balance-button {
|
.hero-balance-button {
|
||||||
width: 6rem;
|
width: 6rem;
|
||||||
|
|
||||||
|
@media #{$sub-mid-size-breakpoint-range} {
|
||||||
|
padding: 0.4rem;
|
||||||
|
width: 4rem;
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
$sub-mid-size-breakpoint: 667px;
|
||||||
|
$sub-mid-size-breakpoint-range: "screen and (min-width: #{$break-large}) and (max-width: #{$sub-mid-size-breakpoint})";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NewUI Container Elements
|
NewUI Container Elements
|
||||||
*/
|
*/
|
||||||
@ -20,6 +23,12 @@ $wallet-view-bg: $alabaster;
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Account and transaction details
|
||||||
|
.account-and-transaction-details {
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
// tx view
|
// tx view
|
||||||
|
|
||||||
.tx-view {
|
.tx-view {
|
||||||
@ -60,6 +69,10 @@ $wallet-view-bg: $alabaster;
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media #{$sub-mid-size-breakpoint-range} {
|
||||||
|
min-width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
.wallet-view-account-details {
|
.wallet-view-account-details {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
@ -92,6 +105,7 @@ $wallet-view-bg: $alabaster;
|
|||||||
&__tooltip {
|
&__tooltip {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,7 +533,6 @@
|
|||||||
@media screen and (max-width: $break-small) {
|
@media screen and (max-width: $break-small) {
|
||||||
padding: 13px 0;
|
padding: 13px 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
height: 0;
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
|
|||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
|
|
||||||
@media #{$wallet-balance-breakpoint-range} {
|
@media #{$wallet-balance-breakpoint-range} {
|
||||||
font-size: 105%;
|
font-size: 95%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,17 +41,22 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
|
|||||||
&__identicon {
|
&__identicon {
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
border: '1px solid #dedede';
|
border: '1px solid #dedede';
|
||||||
|
min-width: 50px;
|
||||||
|
|
||||||
@media #{$wallet-balance-breakpoint-range} {
|
@media #{$wallet-balance-breakpoint-range} {
|
||||||
margin-right: 4%;
|
margin-right: 4%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__balance-ellipsis {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
&__ellipsis {
|
&__ellipsis {
|
||||||
// position: absolute;
|
|
||||||
// top: 20px;
|
|
||||||
// right: 24px;
|
|
||||||
line-height: 45px;
|
line-height: 45px;
|
||||||
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__balance-wrapper {
|
&__balance-wrapper {
|
||||||
@ -61,7 +66,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
|
|||||||
|
|
||||||
.token-menu-dropdown {
|
.token-menu-dropdown {
|
||||||
height: 55px;
|
height: 55px;
|
||||||
width: 191px;
|
width: 80%;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background-color: rgba(0, 0, 0, .82);
|
background-color: rgba(0, 0, 0, .82);
|
||||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .5);
|
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .5);
|
||||||
@ -70,6 +75,10 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
|
|||||||
right: 25px;
|
right: 25px;
|
||||||
z-index: 2000;
|
z-index: 2000;
|
||||||
|
|
||||||
|
@media #{$wallet-balance-breakpoint-range} {
|
||||||
|
right: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
&__close-area {
|
&__close-area {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -81,7 +90,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__container {
|
&__container {
|
||||||
padding: 16px 34px 32px;
|
padding: 16px;
|
||||||
z-index: 2200;
|
z-index: 2200;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
@ -69,3 +69,117 @@ textarea.large-input {
|
|||||||
input.large-input {
|
input.large-input {
|
||||||
height: 36px;
|
height: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-container {
|
||||||
|
width: 400px;
|
||||||
|
background-color: $white;
|
||||||
|
box-shadow: 0 0 7px 0 rgba(0, 0, 0, .08);
|
||||||
|
z-index: 25;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
border-bottom: 1px solid $geyser;
|
||||||
|
padding: 1.6rem 1rem;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row;
|
||||||
|
justify-content: center;
|
||||||
|
border-top: 1px solid $geyser;
|
||||||
|
padding: 1.6rem;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer-button {
|
||||||
|
width: 165px;
|
||||||
|
height: 60px;
|
||||||
|
font-size: 1rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin-right: 1rem;
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
color: $tundora;
|
||||||
|
font-family: Roboto;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subtitle {
|
||||||
|
padding-top: .5rem;
|
||||||
|
line-height: initial;
|
||||||
|
font-size: .9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__tabs {
|
||||||
|
padding: 0 1.3rem;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__tab {
|
||||||
|
min-width: 5rem;
|
||||||
|
padding: .2rem .8rem .9rem;
|
||||||
|
color: $dusty-gray;
|
||||||
|
font-family: Roboto;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: initial;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: none;
|
||||||
|
margin-right: 1rem;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $black;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--selected {
|
||||||
|
color: $curious-blue;
|
||||||
|
border-bottom: 3px solid $curious-blue;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $curious-blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 250px) {
|
||||||
|
.page-container {
|
||||||
|
&__footer {
|
||||||
|
flex-flow: column-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer-button {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
margin-right: 0;
|
||||||
|
|
||||||
|
&:first-of-type {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 575px) {
|
||||||
|
.page-container {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
background-color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -107,6 +107,7 @@ RestoreVaultScreen.prototype.render = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RestoreVaultScreen.prototype.showInitializeMenu = function () {
|
RestoreVaultScreen.prototype.showInitializeMenu = function () {
|
||||||
|
this.props.dispatch(actions.unMarkPasswordForgotten())
|
||||||
if (this.props.forgottenPassword) {
|
if (this.props.forgottenPassword) {
|
||||||
this.props.dispatch(actions.backToUnlockView())
|
this.props.dispatch(actions.backToUnlockView())
|
||||||
} else {
|
} else {
|
||||||
@ -149,6 +150,9 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () {
|
|||||||
this.warning = null
|
this.warning = null
|
||||||
this.props.dispatch(actions.displayWarning(this.warning))
|
this.props.dispatch(actions.displayWarning(this.warning))
|
||||||
this.props.dispatch(actions.createNewVaultAndRestore(password, seed))
|
this.props.dispatch(actions.createNewVaultAndRestore(password, seed))
|
||||||
|
.then(() => {
|
||||||
|
this.props.dispatch(actions.unMarkPasswordForgotten())
|
||||||
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
log.error(err.message)
|
log.error(err.message)
|
||||||
})
|
})
|
||||||
|
@ -2,6 +2,8 @@ const Component = require('react').Component
|
|||||||
const h = require('react-hyperscript')
|
const h = require('react-hyperscript')
|
||||||
const inherits = require('util').inherits
|
const inherits = require('util').inherits
|
||||||
const AccountAndTransactionDetails = require('./account-and-transaction-details')
|
const AccountAndTransactionDetails = require('./account-and-transaction-details')
|
||||||
|
const Settings = require('./components/pages/settings')
|
||||||
|
const UnlockScreen = require('./components/pages/unlock')
|
||||||
|
|
||||||
module.exports = MainContainer
|
module.exports = MainContainer
|
||||||
|
|
||||||
@ -23,6 +25,29 @@ MainContainer.prototype.render = function () {
|
|||||||
style: {},
|
style: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.props.isUnlocked === false) {
|
||||||
|
switch (this.props.currentViewName) {
|
||||||
|
case 'config':
|
||||||
|
log.debug('rendering config screen from unlock screen.')
|
||||||
|
return h(Settings, {key: 'config'})
|
||||||
|
default:
|
||||||
|
log.debug('rendering locked screen')
|
||||||
|
contents = {
|
||||||
|
component: UnlockScreen,
|
||||||
|
style: {
|
||||||
|
boxShadow: 'none',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
background: '#F7F7F7',
|
||||||
|
// must force 100%, because lock screen is full-width
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
key: 'locked',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return h('div.main-container', {
|
return h('div.main-container', {
|
||||||
style: contents.style,
|
style: contents.style,
|
||||||
}, [
|
}, [
|
||||||
|
@ -5,7 +5,6 @@ const h = require('react-hyperscript')
|
|||||||
const ethAbi = require('ethereumjs-abi')
|
const ethAbi = require('ethereumjs-abi')
|
||||||
const ethUtil = require('ethereumjs-util')
|
const ethUtil = require('ethereumjs-util')
|
||||||
|
|
||||||
const Identicon = require('./components/identicon')
|
|
||||||
const FromDropdown = require('./components/send/from-dropdown')
|
const FromDropdown = require('./components/send/from-dropdown')
|
||||||
const ToAutoComplete = require('./components/send/to-autocomplete')
|
const ToAutoComplete = require('./components/send/to-autocomplete')
|
||||||
const CurrencyDisplay = require('./components/send/currency-display')
|
const CurrencyDisplay = require('./components/send/currency-display')
|
||||||
@ -180,53 +179,20 @@ SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SendTransactionScreen.prototype.renderHeaderIcon = function () {
|
SendTransactionScreen.prototype.renderHeader = function () {
|
||||||
const { selectedToken } = this.props
|
const { selectedToken } = this.props
|
||||||
|
|
||||||
return h('div.send-v2__send-header-icon-container', [
|
|
||||||
selectedToken
|
|
||||||
? h(Identicon, {
|
|
||||||
diameter: 40,
|
|
||||||
address: selectedToken.address,
|
|
||||||
})
|
|
||||||
: h('img.send-v2__send-header-icon', { src: '../images/eth_logo.svg' }),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
SendTransactionScreen.prototype.renderTitle = function () {
|
|
||||||
const { selectedToken } = this.props
|
|
||||||
|
|
||||||
return h('div.send-v2__title', [selectedToken ? 'Send Tokens' : 'Send Funds'])
|
|
||||||
}
|
|
||||||
|
|
||||||
SendTransactionScreen.prototype.renderCopy = function () {
|
|
||||||
const { selectedToken } = this.props
|
|
||||||
|
|
||||||
const tokenText = selectedToken ? 'tokens' : 'ETH'
|
const tokenText = selectedToken ? 'tokens' : 'ETH'
|
||||||
|
|
||||||
return h('div.send-v2__form-header-copy', [
|
return h('div.page-container__header', [
|
||||||
|
|
||||||
h('div.send-v2__copy', `Only send ${tokenText} to an Ethereum address.`),
|
h('div.page-container__title', selectedToken ? 'Send Tokens' : 'Send ETH'),
|
||||||
|
|
||||||
h('div.send-v2__copy', 'Sending to a different crytpocurrency that is not Ethereum may result in permanent loss.'),
|
h('div.page-container__subtitle', `Only send ${tokenText} to an Ethereum address.`),
|
||||||
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
SendTransactionScreen.prototype.renderHeader = function () {
|
|
||||||
return h('div', [
|
|
||||||
h('div.send-v2__header', {}, [
|
|
||||||
|
|
||||||
this.renderHeaderIcon(),
|
|
||||||
|
|
||||||
h('div.send-v2__arrow-background', [
|
|
||||||
h('i.fa.fa-lg.fa-arrow-circle-right.send-v2__send-arrow-icon'),
|
|
||||||
]),
|
|
||||||
|
|
||||||
h('div.send-v2__header-tip'),
|
|
||||||
|
|
||||||
]),
|
|
||||||
|
|
||||||
|
h(
|
||||||
|
'div.page-container__subtitle',
|
||||||
|
'Sending to a different crytpocurrency that is not Ethereum may result in permanent loss.'
|
||||||
|
),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,14 +471,6 @@ SendTransactionScreen.prototype.renderMemoRow = function () {
|
|||||||
SendTransactionScreen.prototype.renderForm = function () {
|
SendTransactionScreen.prototype.renderForm = function () {
|
||||||
return h('div.send-v2__form', {}, [
|
return h('div.send-v2__form', {}, [
|
||||||
|
|
||||||
h('div.sendV2__form-header', [
|
|
||||||
|
|
||||||
this.renderTitle(),
|
|
||||||
|
|
||||||
this.renderCopy(),
|
|
||||||
|
|
||||||
]),
|
|
||||||
|
|
||||||
this.renderFromRow(),
|
this.renderFromRow(),
|
||||||
|
|
||||||
this.renderToRow(),
|
this.renderToRow(),
|
||||||
@ -536,14 +494,14 @@ SendTransactionScreen.prototype.renderFooter = function () {
|
|||||||
|
|
||||||
const noErrors = !amountError && toError === null
|
const noErrors = !amountError && toError === null
|
||||||
|
|
||||||
return h('div.send-v2__footer', [
|
return h('div.page-container__footer', [
|
||||||
h('button.btn-cancel.send-v2__cancel-btn', {
|
h('button.btn-cancel.page-container__footer-button', {
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
clearSend()
|
clearSend()
|
||||||
history.goBack()
|
history.goBack()
|
||||||
},
|
},
|
||||||
}, 'Cancel'),
|
}, 'Cancel'),
|
||||||
h('button.btn-clear.send-v2__next-btn', {
|
h('button.btn-clear.page-container__footer-button', {
|
||||||
disabled: !noErrors || !gasTotal,
|
disabled: !noErrors || !gasTotal,
|
||||||
onClick: event => this.onSubmit(event),
|
onClick: event => this.onSubmit(event),
|
||||||
}, 'Next'),
|
}, 'Next'),
|
||||||
@ -553,7 +511,7 @@ SendTransactionScreen.prototype.renderFooter = function () {
|
|||||||
SendTransactionScreen.prototype.render = function () {
|
SendTransactionScreen.prototype.render = function () {
|
||||||
return (
|
return (
|
||||||
|
|
||||||
h('div.send-v2__container', [
|
h('div.page-container', [
|
||||||
|
|
||||||
this.renderHeader(),
|
this.renderHeader(),
|
||||||
|
|
||||||
|
125
ui/app/unlock.js
Normal file
125
ui/app/unlock.js
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
const inherits = require('util').inherits
|
||||||
|
const Component = require('react').Component
|
||||||
|
const h = require('react-hyperscript')
|
||||||
|
const connect = require('react-redux').connect
|
||||||
|
const actions = require('./actions')
|
||||||
|
const getCaretCoordinates = require('textarea-caret')
|
||||||
|
const EventEmitter = require('events').EventEmitter
|
||||||
|
|
||||||
|
const Mascot = require('./components/mascot')
|
||||||
|
|
||||||
|
module.exports = connect(mapStateToProps)(UnlockScreen)
|
||||||
|
|
||||||
|
inherits(UnlockScreen, Component)
|
||||||
|
function UnlockScreen () {
|
||||||
|
Component.call(this)
|
||||||
|
this.animationEventEmitter = new EventEmitter()
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps (state) {
|
||||||
|
return {
|
||||||
|
warning: state.appState.warning,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnlockScreen.prototype.render = function () {
|
||||||
|
const state = this.props
|
||||||
|
const warning = state.warning
|
||||||
|
return (
|
||||||
|
h('.flex-column', {
|
||||||
|
style: {
|
||||||
|
width: 'inherit',
|
||||||
|
},
|
||||||
|
}, [
|
||||||
|
h('.unlock-screen.flex-column.flex-center.flex-grow', [
|
||||||
|
|
||||||
|
h(Mascot, {
|
||||||
|
animationEventEmitter: this.animationEventEmitter,
|
||||||
|
}),
|
||||||
|
|
||||||
|
h('h1', {
|
||||||
|
style: {
|
||||||
|
fontSize: '1.4em',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
color: '#7F8082',
|
||||||
|
},
|
||||||
|
}, 'MetaMask'),
|
||||||
|
|
||||||
|
h('input.large-input', {
|
||||||
|
type: 'password',
|
||||||
|
id: 'password-box',
|
||||||
|
placeholder: 'enter password',
|
||||||
|
style: {
|
||||||
|
background: 'white',
|
||||||
|
},
|
||||||
|
onKeyPress: this.onKeyPress.bind(this),
|
||||||
|
onInput: this.inputChanged.bind(this),
|
||||||
|
}),
|
||||||
|
|
||||||
|
h('.error', {
|
||||||
|
style: {
|
||||||
|
display: warning ? 'block' : 'none',
|
||||||
|
padding: '0 20px',
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
}, warning),
|
||||||
|
|
||||||
|
h('button.primary.cursor-pointer', {
|
||||||
|
onClick: this.onSubmit.bind(this),
|
||||||
|
style: {
|
||||||
|
margin: 10,
|
||||||
|
},
|
||||||
|
}, 'Unlock'),
|
||||||
|
]),
|
||||||
|
|
||||||
|
h('.flex-row.flex-center.flex-grow', [
|
||||||
|
h('p.pointer', {
|
||||||
|
onClick: () => {
|
||||||
|
this.props.dispatch(actions.markPasswordForgotten())
|
||||||
|
global.platform.openExtensionInBrowser()
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
fontSize: '0.8em',
|
||||||
|
color: 'rgb(247, 134, 28)',
|
||||||
|
textDecoration: 'underline',
|
||||||
|
},
|
||||||
|
}, 'Restore from seed phrase'),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
UnlockScreen.prototype.componentDidMount = function () {
|
||||||
|
document.getElementById('password-box').focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
UnlockScreen.prototype.onSubmit = function (event) {
|
||||||
|
const input = document.getElementById('password-box')
|
||||||
|
const password = input.value
|
||||||
|
this.props.dispatch(actions.tryUnlockMetamask(password))
|
||||||
|
}
|
||||||
|
|
||||||
|
UnlockScreen.prototype.onKeyPress = function (event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
this.submitPassword(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnlockScreen.prototype.submitPassword = function (event) {
|
||||||
|
var element = event.target
|
||||||
|
var password = element.value
|
||||||
|
// reset input
|
||||||
|
element.value = ''
|
||||||
|
this.props.dispatch(actions.tryUnlockMetamask(password))
|
||||||
|
}
|
||||||
|
|
||||||
|
UnlockScreen.prototype.inputChanged = function (event) {
|
||||||
|
// tell mascot to look at page action
|
||||||
|
var element = event.target
|
||||||
|
var boundingRect = element.getBoundingClientRect()
|
||||||
|
var coordinates = getCaretCoordinates(element, element.selectionEnd)
|
||||||
|
this.animationEventEmitter.emit('point', {
|
||||||
|
x: boundingRect.left + coordinates.left - element.scrollLeft,
|
||||||
|
y: boundingRect.top + coordinates.top - element.scrollTop,
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user