1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Merge branch 'dev' into i843-MoveSaltIntoEncryptor

This commit is contained in:
Dan Finlay 2016-11-22 15:36:50 -08:00
commit 2966d46fa2
48 changed files with 239 additions and 143 deletions

View File

@ -5,6 +5,8 @@
- Add support for the new, default Ropsten Test Network.
- Fix bug that would cause MetaMask to occasionally lose its StreamProvider connection and drop requests.
- Fix bug that would cause the Custom RPC menu item to not appear when Localhost 8545 was selected.
- Point ropsten faucet button to actual faucet.
- Phase out ethereumjs-util from our encryptor module.
## 2.13.8 2016-11-16

View File

@ -18,6 +18,12 @@ If you're a web dapp developer, we've got two types of guides for you:
Uncompressed builds can be found in `/dist`, compressed builds can be found in `/builds` once they're built.
## Installing Local Builds on Chrome
To install your locally built extension on Chrome, [follow this guide](http://stackoverflow.com/a/24577660/272576).
The built extension is stored in `./dist/chrome/`.
## Architecture
[![Architecture Diagram](./docs/architecture.png)][1]

View File

@ -50,7 +50,7 @@ endOfStream(pingStream, triggerReload)
// set web3 defaultAcount
inpageProvider.publicConfigStore.subscribe(function (state) {
web3.eth.defaultAccount = state.selectedAddress
web3.eth.defaultAccount = state.selectedAccount
})
//

View File

@ -1,4 +1,5 @@
const async = require('async')
const bind = require('ap').partial
const ethUtil = require('ethereumjs-util')
const ethBinToOps = require('eth-bin-to-ops')
const EthQuery = require('eth-query')
@ -9,7 +10,6 @@ const EventEmitter = require('events').EventEmitter
const normalize = require('./lib/sig-util').normalize
const encryptor = require('./lib/encryptor')
const messageManager = require('./lib/message-manager')
const autoFaucet = require('./lib/auto-faucet')
const IdStoreMigrator = require('./lib/idStore-migrator')
const BN = ethUtil.BN
@ -61,13 +61,12 @@ module.exports = class KeyringController extends EventEmitter {
transactions: this.configManager.getTxList(),
unconfMsgs: messageManager.unconfirmedMsgs(),
messages: messageManager.getMsgList(),
selectedAddress: address,
selectedAccount: address,
shapeShiftTxList: this.configManager.getShapeShiftTxList(),
currentFiat: this.configManager.getCurrentFiat(),
conversionRate: this.configManager.getConversionRate(),
conversionDate: this.configManager.getConversionDate(),
keyringTypes: this.keyringTypes.map((krt) => krt.type()),
keyringTypes: this.keyringTypes.map(krt => krt.type),
identities: this.identities,
}
}
@ -76,8 +75,8 @@ module.exports = class KeyringController extends EventEmitter {
this.ethStore = ethStore
}
createNewVaultAndKeychain (password, entropy, cb) {
this.createNewVault(password, entropy, (err) => {
createNewVaultAndKeychain (password, cb) {
this.createNewVault(password, (err) => {
if (err) return cb(err)
this.createFirstKeyTree(password, cb)
})
@ -94,7 +93,7 @@ module.exports = class KeyringController extends EventEmitter {
this.clearKeyrings()
this.createNewVault(password, '', (err) => {
this.createNewVault(password, (err) => {
if (err) return cb(err)
this.addNewKeyring('HD Key Tree', {
mnemonic: seed,
@ -121,7 +120,7 @@ module.exports = class KeyringController extends EventEmitter {
.then((derivedKey) => {
key = derivedKey
this.key = key
return this.idStoreMigrator.oldSeedForPassword(password)
return this.idStoreMigrator.migratedVaultForPassword(password)
})
.then((serialized) => {
if (serialized && shouldMigrate) {
@ -135,7 +134,7 @@ module.exports = class KeyringController extends EventEmitter {
})
}
createNewVault (password, entropy, cb) {
createNewVault (password, cb) {
const configManager = this.configManager
const salt = this.getSalt()
configManager.setSalt(salt)
@ -161,7 +160,7 @@ module.exports = class KeyringController extends EventEmitter {
this.configManager.setSelectedAccount(firstAccount)
this.placeSeedWords()
autoFaucet(hexAccount)
this.emit('newAccount', hexAccount)
this.setupAccounts(accounts)
this.persistAllKeyrings()
.then(() => {
@ -173,10 +172,15 @@ module.exports = class KeyringController extends EventEmitter {
})
}
placeSeedWords () {
placeSeedWords (cb) {
const firstKeyring = this.keyrings[0]
const seedWords = firstKeyring.serialize().mnemonic
this.configManager.setSeedWords(seedWords)
if (cb) {
cb()
}
this.emit('update')
}
submitPassword (password, cb) {
@ -317,7 +321,7 @@ module.exports = class KeyringController extends EventEmitter {
getKeyringClassForType (type) {
const Keyring = this.keyringTypes.reduce((res, kr) => {
if (kr.type() === type) {
if (kr.type === type) {
return kr
} else {
return res
@ -334,7 +338,7 @@ module.exports = class KeyringController extends EventEmitter {
}, [])
}
setSelectedAddress (address, cb) {
setSelectedAccount (address, cb) {
var addr = normalize(address)
this.configManager.setSelectedAccount(addr)
cb(null, addr)
@ -369,7 +373,7 @@ module.exports = class KeyringController extends EventEmitter {
// calculate metadata for tx
async.parallel([
analyzeForDelegateCall,
estimateGas,
analyzeGasUsage,
], didComplete)
// perform static analyis on the target contract code
@ -392,14 +396,69 @@ module.exports = class KeyringController extends EventEmitter {
}
}
function estimateGas (cb) {
query.estimateGas(txParams, function (err, result) {
function analyzeGasUsage (cb) {
query.getBlockByNumber('latest', true, function (err, block) {
if (err) return cb(err)
txData.estimatedGas = self.addGasBuffer(result)
cb()
async.waterfall([
bind(estimateGas, txData, block.gasLimit),
bind(checkForGasError, txData),
bind(setTxGas, txData, block.gasLimit),
], cb)
})
}
function estimateGas(txData, blockGasLimitHex, cb) {
const txParams = txData.txParams
// check if gasLimit is already specified
txData.gasLimitSpecified = Boolean(txParams.gas)
// if not, fallback to block gasLimit
if (!txData.gasLimitSpecified) {
txParams.gas = blockGasLimitHex
}
// run tx, see if it will OOG
query.estimateGas(txParams, cb)
}
function checkForGasError(txData, estimatedGasHex) {
txData.estimatedGas = estimatedGasHex
// all gas used - must be an error
if (estimatedGasHex === txData.txParams.gas) {
txData.simulationFails = true
}
cb()
}
function setTxGas(txData, blockGasLimitHex) {
const txParams = txData.txParams
// if OOG, nothing more to do
if (txData.simulationFails) {
cb()
return
}
// if gasLimit was specified and doesnt OOG,
// use original specified amount
if (txData.gasLimitSpecified) {
txData.estimatedGas = txParams.gas
cb()
return
}
// if gasLimit not originally specified,
// try adding an additional gas buffer to our estimation for safety
const estimatedGasBn = new BN(ethUtil.stripHexPrefix(txData.estimatedGas), 16)
const blockGasLimitBn = new BN(ethUtil.stripHexPrefix(blockGasLimitHex), 16)
const estimationWithBuffer = self.addGasBuffer(estimatedGasBn)
// added gas buffer is too high
if (estimationWithBuffer.gt(blockGasLimitBn)) {
txParams.gas = txData.estimatedGas
// added gas buffer is safe
} else {
const gasWithBufferHex = ethUtil.intToHex(estimationWithBuffer)
txParams.gas = gasWithBufferHex
}
cb()
return
}
function didComplete (err) {
if (err) return cb(err)
configManager.addTx(txData)

View File

@ -2,17 +2,17 @@ const EventEmitter = require('events').EventEmitter
const hdkey = require('ethereumjs-wallet/hdkey')
const bip39 = require('bip39')
const ethUtil = require('ethereumjs-util')
// *Internal Deps
const sigUtil = require('../lib/sig-util')
// Options:
const hdPathString = `m/44'/60'/0'/0`
const type = 'HD Key Tree'
const hdPathString = `m/44'/60'/0'/0`
class HdKeyring extends EventEmitter {
module.exports = class HdKeyring extends EventEmitter {
static type () {
return type
}
/* PUBLIC METHODS */
constructor (opts = {}) {
super()
@ -20,28 +20,6 @@ module.exports = class HdKeyring extends EventEmitter {
this.deserialize(opts)
}
deserialize (opts = {}) {
this.opts = opts || {}
this.wallets = []
this.mnemonic = null
this.root = null
if ('mnemonic' in opts) {
this.initFromMnemonic(opts.mnemonic)
}
if ('numberOfAccounts' in opts) {
this.addAccounts(opts.numberOfAccounts)
}
}
initFromMnemonic (mnemonic) {
this.mnemonic = mnemonic
const seed = bip39.mnemonicToSeed(mnemonic)
this.hdWallet = hdkey.fromMasterSeed(seed)
this.root = this.hdWallet.derivePath(hdPathString)
}
serialize () {
return {
mnemonic: this.mnemonic,
@ -49,14 +27,24 @@ module.exports = class HdKeyring extends EventEmitter {
}
}
exportAccount (address) {
const wallet = this.getWalletForAccount(address)
return wallet.getPrivateKey().toString('hex')
deserialize (opts = {}) {
this.opts = opts || {}
this.wallets = []
this.mnemonic = null
this.root = null
if ('mnemonic' in opts) {
this._initFromMnemonic(opts.mnemonic)
}
if ('numberOfAccounts' in opts) {
this.addAccounts(opts.numberOfAccounts)
}
}
addAccounts (numberOfAccounts = 1) {
if (!this.root) {
this.initFromMnemonic(bip39.generateMnemonic())
this._initFromMnemonic(bip39.generateMnemonic())
}
const oldLen = this.wallets.length
@ -76,7 +64,7 @@ module.exports = class HdKeyring extends EventEmitter {
// tx is an instance of the ethereumjs-transaction class.
signTransaction (address, tx) {
const wallet = this.getWalletForAccount(address)
const wallet = this._getWalletForAccount(address)
var privKey = wallet.getPrivateKey()
tx.sign(privKey)
return tx
@ -84,7 +72,7 @@ module.exports = class HdKeyring extends EventEmitter {
// For eth_sign, we need to sign transactions:
signMessage (withAccount, data) {
const wallet = this.getWalletForAccount(withAccount)
const wallet = this._getWalletForAccount(withAccount)
const message = ethUtil.removeHexPrefix(data)
var privKey = wallet.getPrivateKey()
var msgSig = ethUtil.ecsign(new Buffer(message, 'hex'), privKey)
@ -92,10 +80,29 @@ module.exports = class HdKeyring extends EventEmitter {
return rawMsgSig
}
getWalletForAccount (account) {
exportAccount (address) {
const wallet = this._getWalletForAccount(address)
return wallet.getPrivateKey().toString('hex')
}
/* PRIVATE METHODS */
_initFromMnemonic (mnemonic) {
this.mnemonic = mnemonic
const seed = bip39.mnemonicToSeed(mnemonic)
this.hdWallet = hdkey.fromMasterSeed(seed)
this.root = this.hdWallet.derivePath(hdPathString)
}
_getWalletForAccount (account) {
return this.wallets.find((w) => {
const address = w.getAddress().toString('hex')
return ((address === account) || (sigUtil.normalize(address) === account))
})
}
}
HdKeyring.type = type
module.exports = HdKeyring

View File

@ -4,7 +4,9 @@ const ethUtil = require('ethereumjs-util')
const type = 'Simple Key Pair'
const sigUtil = require('../lib/sig-util')
module.exports = class SimpleKeyring extends EventEmitter {
class SimpleKeyring extends EventEmitter {
/* PUBLIC METHODS */
static type () {
return type
@ -44,7 +46,7 @@ module.exports = class SimpleKeyring extends EventEmitter {
// tx is an instance of the ethereumjs-transaction class.
signTransaction (address, tx) {
const wallet = this.getWalletForAccount(address)
const wallet = this._getWalletForAccount(address)
var privKey = wallet.getPrivateKey()
tx.sign(privKey)
return tx
@ -52,7 +54,7 @@ module.exports = class SimpleKeyring extends EventEmitter {
// For eth_sign, we need to sign transactions:
signMessage (withAccount, data) {
const wallet = this.getWalletForAccount(withAccount)
const wallet = this._getWalletForAccount(withAccount)
const message = ethUtil.removeHexPrefix(data)
var privKey = wallet.getPrivateKey()
var msgSig = ethUtil.ecsign(new Buffer(message, 'hex'), privKey)
@ -60,8 +62,19 @@ module.exports = class SimpleKeyring extends EventEmitter {
return rawMsgSig
}
getWalletForAccount (account) {
exportAccount (address) {
const wallet = this._getWalletForAccount(address)
return wallet.getPrivateKey().toString('hex')
}
/* PRIVATE METHODS */
_getWalletForAccount (account) {
return this.wallets.find(w => w.getAddress().toString('hex') === account)
}
}
SimpleKeyring.type = type
module.exports = SimpleKeyring

View File

@ -1,5 +1,3 @@
var ethUtil = require('ethereumjs-util')
module.exports = {
// Simple encryption methods:
@ -101,10 +99,10 @@ function keyFromPassword (password) {
}
function serializeBufferFromStorage (str) {
str = ethUtil.stripHexPrefix(str)
var buf = new Uint8Array(str.length / 2)
for (var i = 0; i < str.length; i += 2) {
var seg = str.substr(i, 2)
var stripStr = (str.slice(0, 2) === '0x') ? str.slice(2) : str
var buf = new Uint8Array(stripStr.length / 2)
for (var i = 0; i < stripStr.length; i += 2) {
var seg = stripStr.substr(i, 2)
buf[i / 2] = parseInt(seg, 16)
}
return buf

View File

@ -11,7 +11,7 @@ module.exports = class IdentityStoreMigrator {
}
}
oldSeedForPassword (password) {
migratedVaultForPassword (password) {
const hasOldVault = this.hasOldVault()
const configManager = this.configManager

View File

@ -44,7 +44,7 @@ function IdentityStore (opts = {}) {
// public
//
IdentityStore.prototype.createNewVault = function (password, entropy, cb) {
IdentityStore.prototype.createNewVault = function (password, cb) {
delete this._keyStore
var serializedKeystore = this.configManager.getWallet()
@ -53,7 +53,7 @@ IdentityStore.prototype.createNewVault = function (password, entropy, cb) {
}
this.purgeCache()
this._createVault(password, null, entropy, (err) => {
this._createVault(password, null, (err) => {
if (err) return cb(err)
this._autoFaucet()
@ -77,7 +77,7 @@ IdentityStore.prototype.recoverSeed = function (cb) {
IdentityStore.prototype.recoverFromSeed = function (password, seed, cb) {
this.purgeCache()
this._createVault(password, seed, null, (err) => {
this._createVault(password, seed, (err) => {
if (err) return cb(err)
this._loadIdentities()
@ -497,7 +497,7 @@ IdentityStore.prototype.tryPassword = function (password, cb) {
})
}
IdentityStore.prototype._createVault = function (password, seedPhrase, entropy, cb) {
IdentityStore.prototype._createVault = function (password, seedPhrase, cb) {
const opts = {
password,
hdPathString: this.hdPathString,

View File

@ -66,20 +66,20 @@ function MetamaskInpageProvider (connectionStream) {
MetamaskInpageProvider.prototype.send = function (payload) {
const self = this
let selectedAddress
let selectedAccount
let result = null
switch (payload.method) {
case 'eth_accounts':
// read from localStorage
selectedAddress = self.publicConfigStore.get('selectedAddress')
result = selectedAddress ? [selectedAddress] : []
selectedAccount = self.publicConfigStore.get('selectedAddress')
result = selectedAccount ? [selectedAccount] : []
break
case 'eth_coinbase':
// read from localStorage
selectedAddress = self.publicConfigStore.get('selectedAddress')
result = selectedAddress || '0x0000000000000000000000000000000000000000'
selectedAccount = self.publicConfigStore.get('selectedAddress')
result = selectedAccount || '0x0000000000000000000000000000000000000000'
break
// throw not-supported Error

View File

@ -7,6 +7,8 @@ const HostStore = require('./lib/remote-store.js').HostStore
const Web3 = require('web3')
const ConfigManager = require('./lib/config-manager')
const extension = require('./lib/extension')
const autoFaucet = require('./lib/auto-faucet')
module.exports = class MetamaskController {
@ -67,7 +69,7 @@ module.exports = class MetamaskController {
addNewKeyring: keyringController.addNewKeyring.bind(keyringController),
addNewAccount: keyringController.addNewAccount.bind(keyringController),
submitPassword: keyringController.submitPassword.bind(keyringController),
setSelectedAddress: keyringController.setSelectedAddress.bind(keyringController),
setSelectedAccount: keyringController.setSelectedAccount.bind(keyringController),
approveTransaction: keyringController.approveTransaction.bind(keyringController),
cancelTransaction: keyringController.cancelTransaction.bind(keyringController),
signMessage: keyringController.signMessage.bind(keyringController),
@ -125,8 +127,8 @@ module.exports = class MetamaskController {
rpcUrl: this.configManager.getCurrentRpcAddress(),
// account mgmt
getAccounts: (cb) => {
var selectedAddress = this.configManager.getSelectedAccount()
var result = selectedAddress ? [selectedAddress] : []
var selectedAccount = this.configManager.getSelectedAccount()
var result = selectedAccount ? [selectedAccount] : []
cb(null, result)
},
// tx signing
@ -174,17 +176,21 @@ module.exports = class MetamaskController {
this.sendUpdate()
})
this.keyringController.on('newAccount', (account) => {
autoFaucet(account)
})
// keyringController substate
function keyringControllerToPublic (state) {
return {
selectedAddress: state.selectedAddress,
selectedAccount: state.selectedAccount,
}
}
// config substate
function configToPublic (state) {
return {
provider: state.provider,
selectedAddress: state.selectedAccount,
selectedAccount: state.selectedAccount,
}
}
// dump obj into store
@ -341,7 +347,7 @@ module.exports = class MetamaskController {
var network = this.state.network
var url = `https://buy.coinbase.com/?code=9ec56d01-7e81-5017-930c-513daa27bb6a&amount=${amount}&address=${address}&crypto_currency=ETH`
if (network === '2') {
if (network === '3') {
url = 'https://faucet.metamask.io/'
}

File diff suppressed because one or more lines are too long

View File

@ -133,7 +133,7 @@
"address": "0x704107d04affddd9b66ab9de3dd7b095852e9b69"
}
},
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"selectedAccount": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"network": "1",
"seedWords": null,
"isDisclaimerConfirmed": true,

View File

@ -99,7 +99,7 @@
"status": "confirmed",
"containsDelegateCall": false
}],
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"selectedAccount": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"network": "2",
"seedWords": null,
"isDisclaimerConfirmed": true,

View File

@ -57,7 +57,7 @@
}
},
"transactions": [],
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"selectedAccount": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"network": "2",
"seedWords": null,
"isDisclaimerConfirmed": true,

View File

@ -89,7 +89,7 @@
}
},
"transactions": [],
"selectedAddress": "0x0abdd95cafcabec9b3e99dcd09fc4b441037cb80",
"selectedAccount": "0x0abdd95cafcabec9b3e99dcd09fc4b441037cb80",
"network": "2",
"isDisclaimerConfirmed": true,
"unconfMsgs": {},

View File

@ -57,7 +57,7 @@
}
},
"transactions": [],
"selectedAddress": "0x843963b837841dad3b0f5969ff271108776616df",
"selectedAccount": "0x843963b837841dad3b0f5969ff271108776616df",
"network": "2",
"isDisclaimerConfirmed": true,
"unconfMsgs": {},

View File

@ -157,7 +157,7 @@
"estimatedGas": "0x5208"
}
],
"selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"selectedAccount": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"network": "166",
"seedWords": null,
"isDisclaimerConfirmed": true,

View File

@ -54,7 +54,7 @@
}
},
"transactions": [],
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"selectedAccount": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"network": "2",
"seedWords": null,
"isDisclaimerConfirmed": true,

View File

@ -62,7 +62,7 @@
"type": "testnet"
},
"selectedAccount": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"selectedAccount": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"seedWords": null
},
"appState": {

View File

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

File diff suppressed because one or more lines are too long

View File

@ -351,7 +351,7 @@
"hash": "0xb6e6ff57e7b5f6bd7f2e6dc44c39f4e858a227c9509586634ca547179345a13e"
}
],
"selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"selectedAccount": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"network": "1471904489432",
"seedWords": null,
"isDisclaimerConfirmed": true,

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"metamask":{"isInitialized":true,"isUnlocked":true,"currentDomain":"example.com","rpcTarget":"https://rawtestrpc.metamask.io/","identities":{"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825":{"name":"Wallet 1","address":"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825","mayBeFauceting":false},"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb":{"name":"Wallet 2","address":"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb","mayBeFauceting":false},"0x2f8d4a878cfa04a6e60d46362f5644deab66572d":{"name":"Wallet 3","address":"0x2f8d4a878cfa04a6e60d46362f5644deab66572d","mayBeFauceting":false}},"unconfTxs":{"1467868023090690":{"id":1467868023090690,"txParams":{"data":"0xa9059cbb0000000000000000000000008deb4d106090c3eb8f1950f727e87c4f884fb06f0000000000000000000000000000000000000000000000000000000000000064","from":"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825","value":"0x16345785d8a0000","to":"0xbeb0ed3034c4155f3d16a64a5c5e7c8d4ea9e9c9","origin":"MetaMask","metamaskId":1467868023090690,"metamaskNetworkId":"2"},"time":1467868023090,"status":"unconfirmed","containsDelegateCall":false}},"accounts":{"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825":{"code":"0x","balance":"0x38326dc32cf80800","nonce":"0x10000c","address":"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"},"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb":{"code":"0x","balance":"0x15e578bd8e9c8000","nonce":"0x100000","address":"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb"},"0x2f8d4a878cfa04a6e60d46362f5644deab66572d":{"code":"0x","nonce":"0x100000","balance":"0x2386f26fc10000","address":"0x2f8d4a878cfa04a6e60d46362f5644deab66572d"}},"transactions":[],"selectedAddress":"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825","network":"2","seedWords":null,"isDisclaimerConfirmed":true,"unconfMsgs":{},"messages":[],"provider":{"type":"testnet"},"selectedAccount":"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"},"appState":{"menuOpen":false,"currentView":{"name":"confTx","context":0},"accountDetail":{"subview":"transactions"},"currentDomain":"extensions","transForward":true,"isLoading":false,"warning":null},"identities":{}}
{"metamask":{"isInitialized":true,"isUnlocked":true,"currentDomain":"example.com","rpcTarget":"https://rawtestrpc.metamask.io/","identities":{"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825":{"name":"Wallet 1","address":"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825","mayBeFauceting":false},"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb":{"name":"Wallet 2","address":"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb","mayBeFauceting":false},"0x2f8d4a878cfa04a6e60d46362f5644deab66572d":{"name":"Wallet 3","address":"0x2f8d4a878cfa04a6e60d46362f5644deab66572d","mayBeFauceting":false}},"unconfTxs":{"1467868023090690":{"id":1467868023090690,"txParams":{"data":"0xa9059cbb0000000000000000000000008deb4d106090c3eb8f1950f727e87c4f884fb06f0000000000000000000000000000000000000000000000000000000000000064","from":"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825","value":"0x16345785d8a0000","to":"0xbeb0ed3034c4155f3d16a64a5c5e7c8d4ea9e9c9","origin":"MetaMask","metamaskId":1467868023090690,"metamaskNetworkId":"2"},"time":1467868023090,"status":"unconfirmed","containsDelegateCall":false}},"accounts":{"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825":{"code":"0x","balance":"0x38326dc32cf80800","nonce":"0x10000c","address":"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"},"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb":{"code":"0x","balance":"0x15e578bd8e9c8000","nonce":"0x100000","address":"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb"},"0x2f8d4a878cfa04a6e60d46362f5644deab66572d":{"code":"0x","nonce":"0x100000","balance":"0x2386f26fc10000","address":"0x2f8d4a878cfa04a6e60d46362f5644deab66572d"}},"transactions":[],"selectedAccount":"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825","network":"2","seedWords":null,"isDisclaimerConfirmed":true,"unconfMsgs":{},"messages":[],"provider":{"type":"testnet"},"selectedAccount":"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"},"appState":{"menuOpen":false,"currentView":{"name":"confTx","context":0},"accountDetail":{"subview":"transactions"},"currentDomain":"extensions","transForward":true,"isLoading":false,"warning":null},"identities":{}}

File diff suppressed because one or more lines are too long

View File

@ -52,7 +52,7 @@
"hash": "0xad609a6931f54a575ad71222ffc27cd6746017106d5b89f4ad300b37b273f8ac"
}
],
"selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"selectedAccount": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"network": "1479753732793",
"isConfirmed": true,
"isEthConfirmed": true,

View File

@ -46,7 +46,7 @@
}
},
"transactions": [],
"selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"selectedAccount": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"network": "1",
"seedWords": null,
"isDisclaimerConfirmed": true,

View File

@ -33,6 +33,7 @@
]
},
"dependencies": {
"ap": "^0.2.0",
"async": "^1.5.2",
"bip39": "^2.2.0",
"browserify-derequire": "^0.9.4",

View File

@ -3,9 +3,15 @@ var linkGen = require('../../ui/lib/account-link')
describe('account-link', function() {
it('adds testnet prefix to morden test network', function() {
it('adds morden prefix to morden test network', function() {
var result = linkGen('account', '2')
assert.notEqual(result.indexOf('testnet'), -1, 'testnet injected')
assert.notEqual(result.indexOf('morden'), -1, 'testnet included')
assert.notEqual(result.indexOf('account'), -1, 'account included')
})
it('adds testnet prefix to ropsten test network', function() {
var result = linkGen('account', '3')
assert.notEqual(result.indexOf('testnet'), -1, 'testnet included')
assert.notEqual(result.indexOf('account'), -1, 'account included')
})

View File

@ -44,6 +44,5 @@ describe('SHOW_ACCOUNT_DETAIL', function() {
var resultingState = reducers(initialState, action)
assert.equal(resultingState.metamask.selectedAccount, action.value)
assert.equal(resultingState.metamask.selectedAddress, action.value)
})
})

View File

@ -52,7 +52,7 @@ describe('IdentityStore to KeyringController migration', function() {
},
})
idStore._createVault(password, mockVault.seed, null, (err) => {
idStore._createVault(password, mockVault.seed, (err) => {
assert.ifError(err, 'createNewVault threw error')
originalKeystore = idStore._idmgmt.keyStore

View File

@ -11,7 +11,6 @@ describe('IdentityStore', function() {
describe('#createNewVault', function () {
let idStore
let password = 'password123'
let entropy = 'entripppppyy duuude'
let seedWords
let accounts = []
let originalKeystore
@ -26,7 +25,7 @@ describe('IdentityStore', function() {
},
})
idStore.createNewVault(password, entropy, (err, seeds) => {
idStore.createNewVault(password, (err, seeds) => {
assert.ifError(err, 'createNewVault threw error')
seedWords = seeds
originalKeystore = idStore._idmgmt.keyStore

View File

@ -12,7 +12,6 @@ describe('KeyringController', function() {
let keyringController, state
let password = 'password123'
let entropy = 'entripppppyy duuude'
let seedWords = 'puzzle seed penalty soldier say clay field arctic metal hen cage runway'
let addresses = ['eF35cA8EbB9669A35c31b5F6f249A9941a812AC1'.toLowerCase()]
let accounts = []
@ -33,7 +32,7 @@ describe('KeyringController', function() {
// Browser crypto is tested in the integration test suite.
keyringController.encryptor = mockEncryptor
keyringController.createNewVaultAndKeychain(password, null, function (err, newState) {
keyringController.createNewVaultAndKeychain(password, function (err, newState) {
assert.ifError(err)
state = newState
done()
@ -51,7 +50,7 @@ describe('KeyringController', function() {
it('should set a vault on the configManager', function(done) {
keyringController.configManager.setVault(null)
assert(!keyringController.configManager.getVault(), 'no previous vault')
keyringController.createNewVaultAndKeychain(password, null, (err, state) => {
keyringController.createNewVaultAndKeychain(password, (err, state) => {
assert.ifError(err)
const vault = keyringController.configManager.getVault()
assert(vault, 'vault created')

View File

@ -27,9 +27,9 @@ describe('hd-keyring', function() {
assert.equal(accounts[1], secondAcct)
})
describe('Keyring.type()', function() {
it('is a class method that returns the type string.', function() {
const type = HdKeyring.type()
describe('Keyring.type', function() {
it('is a class property that returns the type string.', function() {
const type = HdKeyring.type
assert.equal(typeof type, 'string')
})
})
@ -37,7 +37,7 @@ describe('hd-keyring', function() {
describe('#type', function() {
it('returns the correct value', function() {
const type = keyring.type
const correct = HdKeyring.type()
const correct = HdKeyring.type
assert.equal(type, correct)
})
})

View File

@ -13,9 +13,9 @@ describe('simple-keyring', function() {
keyring = new SimpleKeyring()
})
describe('Keyring.type()', function() {
it('is a class method that returns the type string.', function() {
const type = SimpleKeyring.type()
describe('Keyring.type', function() {
it('is a class property that returns the type string.', function() {
const type = SimpleKeyring.type
assert.equal(type, TYPE_STR)
})
})

View File

@ -16,7 +16,7 @@ function AccountListItem () {
AccountListItem.prototype.render = function () {
const identity = this.props.identity
var isSelected = this.props.selectedAddress === identity.address
var isSelected = this.props.selectedAccount === identity.address
var account = this.props.accounts[identity.address]
const selectedClass = isSelected ? '.selected' : ''

View File

@ -19,7 +19,7 @@ function mapStateToProps (state) {
accounts: state.metamask.accounts,
identities: state.metamask.identities,
unconfTxs: state.metamask.unconfTxs,
selectedAddress: state.metamask.selectedAddress,
selectedAccount: state.metamask.selectedAccount,
scrollToBottom: state.appState.scrollToBottom,
pending,
}
@ -72,7 +72,7 @@ AccountsScreen.prototype.render = function () {
return h(AccountListItem, {
key: `acct-panel-${identity.address}`,
identity,
selectedAddress: this.props.selectedAddress,
selectedAccount: this.props.selectedAccount,
accounts: this.props.accounts,
onShowDetail: this.onShowDetail.bind(this),
pending,
@ -133,8 +133,8 @@ AccountsScreen.prototype.navigateToConfTx = function () {
AccountsScreen.prototype.onSelect = function (address, event) {
event.stopPropagation()
// if already selected, deselect
if (this.props.selectedAddress === address) address = null
this.props.dispatch(actions.setSelectedAddress(address))
if (this.props.selectedAccount === address) address = null
this.props.dispatch(actions.setSelectedAccount(address))
}
AccountsScreen.prototype.onShowDetail = function (address, event) {

View File

@ -71,7 +71,7 @@ var actions = {
TRANSACTION_ERROR: 'TRANSACTION_ERROR',
NEXT_TX: 'NEXT_TX',
PREVIOUS_TX: 'PREV_TX',
setSelectedAddress: setSelectedAddress,
setSelectedAccount: setSelectedAccount,
signMsg: signMsg,
cancelMsg: cancelMsg,
sendTx: sendTx,
@ -201,9 +201,9 @@ function createNewVaultAndRestore (password, seed) {
}
}
function createNewVaultAndKeychain (password, entropy) {
function createNewVaultAndKeychain (password) {
return (dispatch) => {
background.createNewVaultAndKeychain(password, entropy, (err) => {
background.createNewVaultAndKeychain(password, (err) => {
if (err) {
return dispatch(actions.showWarning(err.message))
}
@ -221,9 +221,11 @@ function requestRevealSeed (password) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
background.submitPassword(password, (err) => {
dispatch(actions.hideLoadingIndication())
if (err) return dispatch(actions.displayWarning(err.message))
background.placeSeedWords()
background.placeSeedWords((err) => {
if (err) return dispatch(actions.displayWarning(err.message))
dispatch(actions.hideLoadingIndication())
})
})
}
}
@ -259,9 +261,9 @@ function showInfoPage () {
}
}
function setSelectedAddress (address) {
function setSelectedAccount (address) {
return (dispatch) => {
background.setSelectedAddress(address)
background.setSelectedAccount(address)
}
}
@ -455,7 +457,7 @@ function lockMetamask () {
function showAccountDetail (address) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
background.setSelectedAddress(address, (err, address) => {
background.setSelectedAccount(address, (err, address) => {
dispatch(actions.hideLoadingIndication())
if (err) {
return dispatch(actions.displayWarning(err.message))

View File

@ -114,8 +114,8 @@ BuyButtonSubview.prototype.formVersionSubview = function () {
width: '225px',
},
}, 'In order to access this feature please switch to the Main Network'),
h('h3.text-transform-uppercase', 'or:'),
this.props.network === '2' ? h('button.text-transform-uppercase', {
this.props.network === '3' ? h('h3.text-transform-uppercase', 'or:') : null,
this.props.network === '3' ? h('button.text-transform-uppercase', {
onClick: () => this.props.dispatch(actions.buyEth()),
style: {
marginTop: '15px',

View File

@ -16,7 +16,7 @@ PendingMsgDetails.prototype.render = function () {
var msgData = state.txData
var msgParams = msgData.msgParams || {}
var address = msgParams.from || state.selectedAddress
var address = msgParams.from || state.selectedAccount
var identity = state.identities[address] || { address: address }
var account = state.accounts[address] || { address: address }

View File

@ -24,7 +24,7 @@ PTXP.render = function () {
var txData = props.txData
var txParams = txData.txParams || {}
var address = txParams.from || props.selectedAddress
var address = txParams.from || props.selectedAccount
var identity = props.identities[address] || { address: address }
var account = props.accounts[address]
var balance = account ? account.balance : '0x0'

View File

@ -18,7 +18,7 @@ function mapStateToProps (state) {
return {
identities: state.metamask.identities,
accounts: state.metamask.accounts,
selectedAddress: state.metamask.selectedAddress,
selectedAccount: state.metamask.selectedAccount,
unconfTxs: state.metamask.unconfTxs,
unconfMsgs: state.metamask.unconfMsgs,
index: state.appState.currentView.context,
@ -90,12 +90,12 @@ ConfirmTxScreen.prototype.render = function () {
// Properties
txData: txData,
key: txData.id,
selectedAddress: state.selectedAddress,
selectedAccount: state.selectedAccount,
accounts: state.accounts,
identities: state.identities,
insufficientBalance: this.checkBalnceAgainstTx(txData),
// Actions
buyEth: this.buyEth.bind(this, txParams.from || state.selectedAddress),
buyEth: this.buyEth.bind(this, txParams.from || state.selectedAccount),
sendTransaction: this.sendTransaction.bind(this, txData),
cancelTransaction: this.cancelTransaction.bind(this, txData),
signMessage: this.signMessage.bind(this, txData),
@ -120,7 +120,7 @@ ConfirmTxScreen.prototype.checkBalnceAgainstTx = function (txData) {
var state = this.props
var txParams = txData.txParams || {}
var address = txParams.from || state.selectedAddress
var address = txParams.from || state.selectedAccount
var account = state.accounts[address]
var balance = account ? account.balance : '0x0'

View File

@ -165,7 +165,7 @@ InitializeMenuScreen.prototype.createNewVaultAndKeychain = function () {
return
}
this.props.dispatch(actions.createNewVaultAndKeychain(password, ''/* entropy*/))
this.props.dispatch(actions.createNewVaultAndKeychain(password))
}
InitializeMenuScreen.prototype.inputChanged = function (event) {

View File

@ -285,7 +285,7 @@ function reduceApp (state, action) {
warning: null,
currentView: {
name: 'accountDetail',
context: state.metamask.selectedAddress,
context: state.metamask.selectedAccount,
},
accountDetail: {
subview: 'transactions',

View File

@ -98,7 +98,6 @@ function reduceMetamask (state, action) {
isUnlocked: true,
isInitialized: true,
selectedAccount: action.value,
selectedAddress: action.value,
})
delete newState.seedWords
return newState

View File

@ -53,14 +53,14 @@ function addUnconfTx (txParams) {
}
var isUnlocked = false
var selectedAddress = null
var selectedAccount = null
function getState () {
return {
isUnlocked: isUnlocked,
identities: isUnlocked ? identities : {},
unconfTxs: isUnlocked ? unconfTxs : {},
selectedAddress: selectedAddress,
selectedAccount: selectedAccount,
}
}
@ -85,8 +85,8 @@ accountManager.submitPassword = function (password, cb) {
}
}
accountManager.setSelectedAddress = function (address, cb) {
selectedAddress = address
accountManager.setSelectedAccount = function (address, cb) {
selectedAccount = address
cb(null, getState())
this._didUpdate()
}

View File

@ -1,4 +1,4 @@
module.exports = function (address, network) {
module.exports = function(address, network) {
const net = parseInt(network)
let link
@ -7,10 +7,10 @@ module.exports = function (address, network) {
link = `http://etherscan.io/address/${address}`
break
case 2: // morden test net
link = `http://testnet.etherscan.io/address/${address}`
link = `http://morden.etherscan.io/address/${address}`
break
case 3: // ropsten test net
link = ''
link = `http://testnet.etherscan.io/address/${address}`
break
default:
link = ''