mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge pull request #4034 from whymarrh/account-nicknames
Move account names out of KeyringController
This commit is contained in:
commit
08d95bbafa
@ -13,19 +13,17 @@ class AddressBookController {
|
|||||||
* @param {object} opts Overrides the defaults for the initial state of this.store
|
* @param {object} opts Overrides the defaults for the initial state of this.store
|
||||||
* @property {array} opts.initState initializes the the state of the AddressBookController. Can contain an
|
* @property {array} opts.initState initializes the the state of the AddressBookController. Can contain an
|
||||||
* addressBook property to initialize the addressBook array
|
* addressBook property to initialize the addressBook array
|
||||||
* @param {KeyringController} keyringController (Soon to be deprecated) The keyringController used in the current
|
* @property {object} opts.preferencesStore the {@code PreferencesController} store
|
||||||
* MetamaskController. Contains the identities used in this AddressBookController.
|
|
||||||
* @property {object} store The the store of the current users address book
|
* @property {object} store The the store of the current users address book
|
||||||
* @property {array} store.addressBook An array of addresses and nicknames. These are set by the user when sending
|
* @property {array} store.addressBook An array of addresses and nicknames. These are set by the user when sending
|
||||||
* to a new address.
|
* to a new address.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
constructor (opts = {}, keyringController) {
|
constructor ({initState, preferencesStore}) {
|
||||||
const initState = extend({
|
this.store = new ObservableStore(extend({
|
||||||
addressBook: [],
|
addressBook: [],
|
||||||
}, opts.initState)
|
}, initState))
|
||||||
this.store = new ObservableStore(initState)
|
this._preferencesStore = preferencesStore
|
||||||
this.keyringController = keyringController
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -62,7 +60,7 @@ class AddressBookController {
|
|||||||
*/
|
*/
|
||||||
_addToAddressBook (address, name) {
|
_addToAddressBook (address, name) {
|
||||||
const addressBook = this._getAddressBook()
|
const addressBook = this._getAddressBook()
|
||||||
const identities = this._getIdentities()
|
const {identities} = this._preferencesStore.getState()
|
||||||
|
|
||||||
const addressBookIndex = addressBook.findIndex((element) => { return element.address.toLowerCase() === address.toLowerCase() || element.name === name })
|
const addressBookIndex = addressBook.findIndex((element) => { return element.address.toLowerCase() === address.toLowerCase() || element.name === name })
|
||||||
const identitiesIndex = Object.keys(identities).findIndex((element) => { return element.toLowerCase() === address.toLowerCase() })
|
const identitiesIndex = Object.keys(identities).findIndex((element) => { return element.toLowerCase() === address.toLowerCase() })
|
||||||
@ -95,19 +93,6 @@ class AddressBookController {
|
|||||||
_getAddressBook () {
|
_getAddressBook () {
|
||||||
return this.store.getState().addressBook
|
return this.store.getState().addressBook
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves identities from the keyring controller in order to avoid
|
|
||||||
* duplication
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
* @returns {array} Returns the identies array from the keyringContoller's state
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
_getIdentities () {
|
|
||||||
return this.keyringController.memStore.getState().identities
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = AddressBookController
|
module.exports = AddressBookController
|
||||||
|
@ -27,6 +27,7 @@ class PreferencesController {
|
|||||||
useBlockie: false,
|
useBlockie: false,
|
||||||
featureFlags: {},
|
featureFlags: {},
|
||||||
currentLocale: opts.initLangCode,
|
currentLocale: opts.initLangCode,
|
||||||
|
identities: {},
|
||||||
}, opts.initState)
|
}, opts.initState)
|
||||||
this.store = new ObservableStore(initState)
|
this.store = new ObservableStore(initState)
|
||||||
}
|
}
|
||||||
@ -62,6 +63,16 @@ class PreferencesController {
|
|||||||
this.store.updateState({ currentLocale: key })
|
this.store.updateState({ currentLocale: key })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAddresses (addresses) {
|
||||||
|
const oldIdentities = this.store.getState().identities
|
||||||
|
const identities = addresses.reduce((ids, address, index) => {
|
||||||
|
const oldId = oldIdentities[address] || {}
|
||||||
|
ids[address] = {name: `Account ${index + 1}`, address, ...oldId}
|
||||||
|
return ids
|
||||||
|
}, {})
|
||||||
|
this.store.updateState({ identities })
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setter for the `selectedAddress` property
|
* Setter for the `selectedAddress` property
|
||||||
*
|
*
|
||||||
@ -155,6 +166,21 @@ class PreferencesController {
|
|||||||
return this.store.getState().tokens
|
return this.store.getState().tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a custom label for an account
|
||||||
|
* @param {string} account the account to set a label for
|
||||||
|
* @param {string} label the custom label for the account
|
||||||
|
* @return {Promise<string>}
|
||||||
|
*/
|
||||||
|
setAccountLabel (account, label) {
|
||||||
|
const address = normalizeAddress(account)
|
||||||
|
const {identities} = this.store.getState()
|
||||||
|
identities[address] = identities[address] || {}
|
||||||
|
identities[address].name = label
|
||||||
|
this.store.updateState({ identities })
|
||||||
|
return Promise.resolve(label)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an updated rpc list from this.addToFrequentRpcList() and sets the `frequentRpcList` to this update list.
|
* Gets an updated rpc list from this.addToFrequentRpcList() and sets the `frequentRpcList` to this update list.
|
||||||
*
|
*
|
||||||
@ -189,8 +215,8 @@ class PreferencesController {
|
|||||||
* The returned list will have a max length of 2. If the _url currently exists it the list, it will be moved to the
|
* The returned list will have a max length of 2. If the _url currently exists it the list, it will be moved to the
|
||||||
* end of the list. The current list is modified and returned as a promise.
|
* end of the list. The current list is modified and returned as a promise.
|
||||||
*
|
*
|
||||||
* @param {string} _url The rpc url to add to the frequentRpcList.
|
* @param {string} _url The rpc url to add to the frequentRpcList.
|
||||||
* @returns {Promise<array>} The updated frequentRpcList.
|
* @returns {Promise<array>} The updated frequentRpcList.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
addToFrequentRpcList (_url) {
|
addToFrequentRpcList (_url) {
|
||||||
|
@ -144,7 +144,8 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
// address book controller
|
// address book controller
|
||||||
this.addressBookController = new AddressBookController({
|
this.addressBookController = new AddressBookController({
|
||||||
initState: initState.AddressBookController,
|
initState: initState.AddressBookController,
|
||||||
}, this.keyringController)
|
preferencesStore: this.preferencesController.store,
|
||||||
|
})
|
||||||
|
|
||||||
// tx mgmt
|
// tx mgmt
|
||||||
this.txController = new TransactionController({
|
this.txController = new TransactionController({
|
||||||
@ -363,6 +364,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
addToken: nodeify(preferencesController.addToken, preferencesController),
|
addToken: nodeify(preferencesController.addToken, preferencesController),
|
||||||
removeToken: nodeify(preferencesController.removeToken, preferencesController),
|
removeToken: nodeify(preferencesController.removeToken, preferencesController),
|
||||||
setCurrentAccountTab: nodeify(preferencesController.setCurrentAccountTab, preferencesController),
|
setCurrentAccountTab: nodeify(preferencesController.setCurrentAccountTab, preferencesController),
|
||||||
|
setAccountLabel: nodeify(preferencesController.setAccountLabel, preferencesController),
|
||||||
setFeatureFlag: nodeify(preferencesController.setFeatureFlag, preferencesController),
|
setFeatureFlag: nodeify(preferencesController.setFeatureFlag, preferencesController),
|
||||||
|
|
||||||
// AddressController
|
// AddressController
|
||||||
@ -373,7 +375,6 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
createNewVaultAndKeychain: nodeify(this.createNewVaultAndKeychain, this),
|
createNewVaultAndKeychain: nodeify(this.createNewVaultAndKeychain, this),
|
||||||
createNewVaultAndRestore: nodeify(this.createNewVaultAndRestore, this),
|
createNewVaultAndRestore: nodeify(this.createNewVaultAndRestore, this),
|
||||||
addNewKeyring: nodeify(keyringController.addNewKeyring, keyringController),
|
addNewKeyring: nodeify(keyringController.addNewKeyring, keyringController),
|
||||||
saveAccountLabel: nodeify(keyringController.saveAccountLabel, keyringController),
|
|
||||||
exportAccount: nodeify(keyringController.exportAccount, keyringController),
|
exportAccount: nodeify(keyringController.exportAccount, keyringController),
|
||||||
|
|
||||||
// txController
|
// txController
|
||||||
@ -433,7 +434,9 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
vault = await this.keyringController.createNewVaultAndKeychain(password)
|
vault = await this.keyringController.createNewVaultAndKeychain(password)
|
||||||
this.selectFirstIdentity(vault)
|
const accounts = await this.keyringController.getAccounts()
|
||||||
|
this.preferencesController.setAddresses(accounts)
|
||||||
|
this.selectFirstIdentity()
|
||||||
}
|
}
|
||||||
release()
|
release()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -453,7 +456,9 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
const release = await this.createVaultMutex.acquire()
|
const release = await this.createVaultMutex.acquire()
|
||||||
try {
|
try {
|
||||||
const vault = await this.keyringController.createNewVaultAndRestore(password, seed)
|
const vault = await this.keyringController.createNewVaultAndRestore(password, seed)
|
||||||
this.selectFirstIdentity(vault)
|
const accounts = await this.keyringController.getAccounts()
|
||||||
|
this.preferencesController.setAddresses(accounts)
|
||||||
|
this.selectFirstIdentity()
|
||||||
release()
|
release()
|
||||||
return vault
|
return vault
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -471,12 +476,10 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the first Identiy from the passed Vault and selects the related address
|
* Sets the first address in the state to the selected address
|
||||||
*
|
|
||||||
* @param {} vault
|
|
||||||
*/
|
*/
|
||||||
selectFirstIdentity (vault) {
|
selectFirstIdentity () {
|
||||||
const { identities } = vault
|
const { identities } = this.preferencesController.store.getState()
|
||||||
const address = Object.keys(identities)[0]
|
const address = Object.keys(identities)[0]
|
||||||
this.preferencesController.setSelectedAddress(address)
|
this.preferencesController.setSelectedAddress(address)
|
||||||
}
|
}
|
||||||
@ -502,13 +505,15 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
|
|
||||||
await this.verifySeedPhrase()
|
await this.verifySeedPhrase()
|
||||||
|
|
||||||
|
this.preferencesController.setAddresses(newAccounts)
|
||||||
newAccounts.forEach((address) => {
|
newAccounts.forEach((address) => {
|
||||||
if (!oldAccounts.includes(address)) {
|
if (!oldAccounts.includes(address)) {
|
||||||
this.preferencesController.setSelectedAddress(address)
|
this.preferencesController.setSelectedAddress(address)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return keyState
|
const {identities} = this.preferencesController.store.getState()
|
||||||
|
return {...keyState, identities}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
47
app/scripts/migrations/026.js
Normal file
47
app/scripts/migrations/026.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
const version = 26
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
This migration moves the identities stored in the KeyringController
|
||||||
|
into the PreferencesController
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
const clone = require('clone')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
version,
|
||||||
|
migrate (originalVersionedData) {
|
||||||
|
const versionedData = clone(originalVersionedData)
|
||||||
|
versionedData.meta.version = version
|
||||||
|
try {
|
||||||
|
const state = versionedData.data
|
||||||
|
versionedData.data = transformState(state)
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`MetaMask Migration #${version}` + err.stack)
|
||||||
|
return Promise.reject(err)
|
||||||
|
}
|
||||||
|
return Promise.resolve(versionedData)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformState (state) {
|
||||||
|
if (!state.KeyringController || !state.PreferencesController) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state.KeyringController.walletNicknames) {
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
state.PreferencesController.identities = Object.keys(state.KeyringController.walletNicknames)
|
||||||
|
.reduce((identities, address) => {
|
||||||
|
identities[address] = {
|
||||||
|
name: state.KeyringController.walletNicknames[address],
|
||||||
|
address,
|
||||||
|
}
|
||||||
|
return identities
|
||||||
|
}, {})
|
||||||
|
delete state.KeyringController.walletNicknames
|
||||||
|
return state
|
||||||
|
}
|
@ -36,4 +36,5 @@ module.exports = [
|
|||||||
require('./023'),
|
require('./023'),
|
||||||
require('./024'),
|
require('./024'),
|
||||||
require('./025'),
|
require('./025'),
|
||||||
|
require('./026'),
|
||||||
]
|
]
|
||||||
|
@ -91,7 +91,7 @@ AccountDetailScreen.prototype.render = function () {
|
|||||||
isEditingLabel: false,
|
isEditingLabel: false,
|
||||||
},
|
},
|
||||||
saveText: (text) => {
|
saveText: (text) => {
|
||||||
props.dispatch(actions.saveAccountLabel(selected, text))
|
props.dispatch(actions.setAccountLabel(selected, text))
|
||||||
},
|
},
|
||||||
}, [
|
}, [
|
||||||
|
|
||||||
|
22
package-lock.json
generated
22
package-lock.json
generated
@ -8054,9 +8054,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"eth-keyring-controller": {
|
"eth-keyring-controller": {
|
||||||
"version": "2.2.0",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/eth-keyring-controller/-/eth-keyring-controller-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eth-keyring-controller/-/eth-keyring-controller-3.1.1.tgz",
|
||||||
"integrity": "sha512-f/g1ZrxciWJs2aHgpfvYmZ3ImP48GA+pobTU0EFNF/y5Yylf1zQyDw671W5opGpIt5TgV4F9sYXcvyjlgbL0Pg==",
|
"integrity": "sha512-Z9HTzrop/V4Ld8Wq7uwetKecfWIyx25/uL8aFoZxV3kegZGoXaWoRmNy+4oW0WNLp4BcJ1lk6QfsGEdlymGjmA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bip39": "2.4.0",
|
"bip39": "2.4.0",
|
||||||
"bluebird": "3.5.1",
|
"bluebird": "3.5.1",
|
||||||
@ -8064,7 +8064,7 @@
|
|||||||
"eth-hd-keyring": "1.2.2",
|
"eth-hd-keyring": "1.2.2",
|
||||||
"eth-sig-util": "1.4.2",
|
"eth-sig-util": "1.4.2",
|
||||||
"eth-simple-keyring": "1.2.1",
|
"eth-simple-keyring": "1.2.1",
|
||||||
"ethereumjs-util": "5.1.5",
|
"ethereumjs-util": "5.2.0",
|
||||||
"loglevel": "1.6.0",
|
"loglevel": "1.6.0",
|
||||||
"obs-store": "2.4.1",
|
"obs-store": "2.4.1",
|
||||||
"promise-filter": "1.1.0"
|
"promise-filter": "1.1.0"
|
||||||
@ -8080,9 +8080,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ethereumjs-util": {
|
"ethereumjs-util": {
|
||||||
"version": "5.1.5",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz",
|
||||||
"integrity": "sha512-xPaSEATYJpMTCGowIt0oMZwFP4R1bxd6QsWgkcDvFL0JtXsr39p32WEcD14RscCjfP41YXZPCVWA4yAg0nrJmw==",
|
"integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bn.js": "4.11.8",
|
"bn.js": "4.11.8",
|
||||||
"create-hash": "1.1.3",
|
"create-hash": "1.1.3",
|
||||||
@ -8176,16 +8176,16 @@
|
|||||||
"integrity": "sha1-bXs1LcWppQINYfafryHvsvY2P0U=",
|
"integrity": "sha1-bXs1LcWppQINYfafryHvsvY2P0U=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"eth-sig-util": "1.4.2",
|
"eth-sig-util": "1.4.2",
|
||||||
"ethereumjs-util": "5.1.5",
|
"ethereumjs-util": "5.2.0",
|
||||||
"ethereumjs-wallet": "0.6.0",
|
"ethereumjs-wallet": "0.6.0",
|
||||||
"events": "1.1.1",
|
"events": "1.1.1",
|
||||||
"xtend": "4.0.1"
|
"xtend": "4.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ethereumjs-util": {
|
"ethereumjs-util": {
|
||||||
"version": "5.1.5",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz",
|
||||||
"integrity": "sha512-xPaSEATYJpMTCGowIt0oMZwFP4R1bxd6QsWgkcDvFL0JtXsr39p32WEcD14RscCjfP41YXZPCVWA4yAg0nrJmw==",
|
"integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bn.js": "4.11.8",
|
"bn.js": "4.11.8",
|
||||||
"create-hash": "1.1.3",
|
"create-hash": "1.1.3",
|
||||||
|
@ -95,7 +95,7 @@
|
|||||||
"eth-hd-keyring": "^1.2.1",
|
"eth-hd-keyring": "^1.2.1",
|
||||||
"eth-json-rpc-filters": "^1.2.6",
|
"eth-json-rpc-filters": "^1.2.6",
|
||||||
"eth-json-rpc-infura": "^3.0.0",
|
"eth-json-rpc-infura": "^3.0.0",
|
||||||
"eth-keyring-controller": "^2.2.0",
|
"eth-keyring-controller": "^3.1.1",
|
||||||
"eth-phishing-detect": "^1.1.4",
|
"eth-phishing-detect": "^1.1.4",
|
||||||
"eth-query": "^2.1.2",
|
"eth-query": "^2.1.2",
|
||||||
"eth-sig-util": "^1.4.2",
|
"eth-sig-util": "^1.4.2",
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
// var jsdom = require('mocha-jsdom')
|
|
||||||
var assert = require('assert')
|
|
||||||
var freeze = require('deep-freeze-strict')
|
|
||||||
var path = require('path')
|
|
||||||
|
|
||||||
var actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'actions.js'))
|
|
||||||
var reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'reducers.js'))
|
|
||||||
|
|
||||||
describe('SAVE_ACCOUNT_LABEL', function () {
|
|
||||||
it('updates the state.metamask.identities[:i].name property of the state to the action.value.label', function () {
|
|
||||||
var initialState = {
|
|
||||||
metamask: {
|
|
||||||
identities: {
|
|
||||||
foo: {
|
|
||||||
name: 'bar',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
freeze(initialState)
|
|
||||||
|
|
||||||
const action = {
|
|
||||||
type: actions.SAVE_ACCOUNT_LABEL,
|
|
||||||
value: {
|
|
||||||
account: 'foo',
|
|
||||||
label: 'baz',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
freeze(action)
|
|
||||||
|
|
||||||
var resultingState = reducers(initialState, action)
|
|
||||||
assert.equal(resultingState.metamask.identities.foo.name, action.value.label)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
34
test/unit/actions/set_account_label_test.js
Normal file
34
test/unit/actions/set_account_label_test.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const assert = require('assert')
|
||||||
|
const freeze = require('deep-freeze-strict')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
const actions = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'actions.js'))
|
||||||
|
const reducers = require(path.join(__dirname, '..', '..', '..', 'ui', 'app', 'reducers.js'))
|
||||||
|
|
||||||
|
describe('SET_ACCOUNT_LABEL', function () {
|
||||||
|
it('updates the state.metamask.identities[:i].name property of the state to the action.value.label', function () {
|
||||||
|
const initialState = {
|
||||||
|
metamask: {
|
||||||
|
identities: {
|
||||||
|
foo: {
|
||||||
|
name: 'bar',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
freeze(initialState)
|
||||||
|
|
||||||
|
const action = {
|
||||||
|
type: actions.SET_ACCOUNT_LABEL,
|
||||||
|
value: {
|
||||||
|
account: 'foo',
|
||||||
|
label: 'baz',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
freeze(action)
|
||||||
|
|
||||||
|
const resultingState = reducers(initialState, action)
|
||||||
|
assert.equal(resultingState.metamask.identities.foo.name, action.value.label)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -1,26 +1,26 @@
|
|||||||
const assert = require('assert')
|
const assert = require('assert')
|
||||||
const AddressBookController = require('../../app/scripts/controllers/address-book')
|
const AddressBookController = require('../../app/scripts/controllers/address-book')
|
||||||
|
|
||||||
const mockKeyringController = {
|
const stubPreferencesStore = {
|
||||||
memStore: {
|
getState: function () {
|
||||||
getState: function () {
|
return {
|
||||||
return {
|
identities: {
|
||||||
identities: {
|
'0x0aaa': {
|
||||||
'0x0aaa': {
|
address: '0x0aaa',
|
||||||
address: '0x0aaa',
|
name: 'owned',
|
||||||
name: 'owned',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
describe('address-book-controller', function () {
|
describe('address-book-controller', function () {
|
||||||
var addressBookController
|
var addressBookController
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
addressBookController = new AddressBookController({}, mockKeyringController)
|
addressBookController = new AddressBookController({
|
||||||
|
preferencesStore: stubPreferencesStore,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('addres book management', function () {
|
describe('addres book management', function () {
|
||||||
|
@ -106,7 +106,7 @@ describe('MetaMaskController', function () {
|
|||||||
[TEST_ADDRESS]: { address: TEST_ADDRESS, name: DEFAULT_LABEL },
|
[TEST_ADDRESS]: { address: TEST_ADDRESS, name: DEFAULT_LABEL },
|
||||||
})
|
})
|
||||||
|
|
||||||
await metamaskController.keyringController.saveAccountLabel(TEST_ADDRESS, 'Account Foo')
|
await metamaskController.preferencesController.setAccountLabel(TEST_ADDRESS, 'Account Foo')
|
||||||
assert.deepEqual(metamaskController.getState().identities, {
|
assert.deepEqual(metamaskController.getState().identities, {
|
||||||
[TEST_ADDRESS]: { address: TEST_ADDRESS, name: 'Account Foo' },
|
[TEST_ADDRESS]: { address: TEST_ADDRESS, name: 'Account Foo' },
|
||||||
})
|
})
|
||||||
|
41
test/unit/migrations/026-test.js
Normal file
41
test/unit/migrations/026-test.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
const assert = require('assert')
|
||||||
|
const migration26 = require('../../../app/scripts/migrations/026')
|
||||||
|
const oldStorage = {
|
||||||
|
'meta': {'version': 25},
|
||||||
|
'data': {
|
||||||
|
'PreferencesController': {},
|
||||||
|
'KeyringController': {
|
||||||
|
'walletNicknames': {
|
||||||
|
'0x1e77e2': 'Test Account 1',
|
||||||
|
'0x7e57e2': 'Test Account 2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('migration #26', () => {
|
||||||
|
it('should move the identities from KeyringController', (done) => {
|
||||||
|
migration26.migrate(oldStorage)
|
||||||
|
.then((newStorage) => {
|
||||||
|
const identities = newStorage.data.PreferencesController.identities
|
||||||
|
assert.deepEqual(identities, {
|
||||||
|
'0x1e77e2': {name: 'Test Account 1', address: '0x1e77e2'},
|
||||||
|
'0x7e57e2': {name: 'Test Account 2', address: '0x7e57e2'},
|
||||||
|
})
|
||||||
|
assert.strictEqual(newStorage.data.KeyringController.walletNicknames, undefined)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
.catch(done)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should successfully migrate first time state', (done) => {
|
||||||
|
migration26.migrate({
|
||||||
|
meta: {},
|
||||||
|
data: require('../../../app/scripts/first-time-state'),
|
||||||
|
})
|
||||||
|
.then((migratedData) => {
|
||||||
|
assert.equal(migratedData.meta.version, migration26.version)
|
||||||
|
done()
|
||||||
|
}).catch(done)
|
||||||
|
})
|
||||||
|
})
|
@ -4,16 +4,91 @@ const PreferencesController = require('../../app/scripts/controllers/preferences
|
|||||||
describe('preferences controller', function () {
|
describe('preferences controller', function () {
|
||||||
let preferencesController
|
let preferencesController
|
||||||
|
|
||||||
before(() => {
|
beforeEach(() => {
|
||||||
preferencesController = new PreferencesController()
|
preferencesController = new PreferencesController()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('setAddresses', function () {
|
||||||
|
it('should keep a map of addresses to names and addresses in the store', function () {
|
||||||
|
preferencesController.setAddresses([
|
||||||
|
'0xda22le',
|
||||||
|
'0x7e57e2',
|
||||||
|
])
|
||||||
|
|
||||||
|
const {identities} = preferencesController.store.getState()
|
||||||
|
assert.deepEqual(identities, {
|
||||||
|
'0xda22le': {
|
||||||
|
name: 'Account 1',
|
||||||
|
address: '0xda22le',
|
||||||
|
},
|
||||||
|
'0x7e57e2': {
|
||||||
|
name: 'Account 2',
|
||||||
|
address: '0x7e57e2',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should replace its list of addresses', function () {
|
||||||
|
preferencesController.setAddresses([
|
||||||
|
'0xda22le',
|
||||||
|
'0x7e57e2',
|
||||||
|
])
|
||||||
|
preferencesController.setAddresses([
|
||||||
|
'0xda22le77',
|
||||||
|
'0x7e57e277',
|
||||||
|
])
|
||||||
|
|
||||||
|
const {identities} = preferencesController.store.getState()
|
||||||
|
assert.deepEqual(identities, {
|
||||||
|
'0xda22le77': {
|
||||||
|
name: 'Account 1',
|
||||||
|
address: '0xda22le77',
|
||||||
|
},
|
||||||
|
'0x7e57e277': {
|
||||||
|
name: 'Account 2',
|
||||||
|
address: '0x7e57e277',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('setAccountLabel', function () {
|
||||||
|
it('should update a label for the given account', function () {
|
||||||
|
preferencesController.setAddresses([
|
||||||
|
'0xda22le',
|
||||||
|
'0x7e57e2',
|
||||||
|
])
|
||||||
|
|
||||||
|
assert.deepEqual(preferencesController.store.getState().identities['0xda22le'], {
|
||||||
|
name: 'Account 1',
|
||||||
|
address: '0xda22le',
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
preferencesController.setAccountLabel('0xda22le', 'Dazzle')
|
||||||
|
assert.deepEqual(preferencesController.store.getState().identities['0xda22le'], {
|
||||||
|
name: 'Dazzle',
|
||||||
|
address: '0xda22le',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('getTokens', function () {
|
||||||
|
it('should return an empty list initially', async function () {
|
||||||
|
await preferencesController.setSelectedAddress('0x7e57e2')
|
||||||
|
|
||||||
|
const tokens = preferencesController.getTokens()
|
||||||
|
assert.equal(tokens.length, 0, 'empty list of tokens')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('addToken', function () {
|
describe('addToken', function () {
|
||||||
it('should add that token to its state', async function () {
|
it('should add that token to its state', async function () {
|
||||||
const address = '0xabcdef1234567'
|
const address = '0xabcdef1234567'
|
||||||
const symbol = 'ABBR'
|
const symbol = 'ABBR'
|
||||||
const decimals = 5
|
const decimals = 5
|
||||||
|
|
||||||
|
await preferencesController.setSelectedAddress('0x7e57e2')
|
||||||
await preferencesController.addToken(address, symbol, decimals)
|
await preferencesController.addToken(address, symbol, decimals)
|
||||||
|
|
||||||
const tokens = preferencesController.getTokens()
|
const tokens = preferencesController.getTokens()
|
||||||
@ -30,6 +105,7 @@ describe('preferences controller', function () {
|
|||||||
const symbol = 'ABBR'
|
const symbol = 'ABBR'
|
||||||
const decimals = 5
|
const decimals = 5
|
||||||
|
|
||||||
|
await preferencesController.setSelectedAddress('0x7e57e2')
|
||||||
await preferencesController.addToken(address, symbol, decimals)
|
await preferencesController.addToken(address, symbol, decimals)
|
||||||
|
|
||||||
const newDecimals = 6
|
const newDecimals = 6
|
||||||
@ -43,6 +119,44 @@ describe('preferences controller', function () {
|
|||||||
assert.equal(added.symbol, symbol, 'set symbol correctly')
|
assert.equal(added.symbol, symbol, 'set symbol correctly')
|
||||||
assert.equal(added.decimals, newDecimals, 'updated decimals correctly')
|
assert.equal(added.decimals, newDecimals, 'updated decimals correctly')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should allow adding tokens to two separate addresses', async function () {
|
||||||
|
const address = '0xabcdef1234567'
|
||||||
|
const symbol = 'ABBR'
|
||||||
|
const decimals = 5
|
||||||
|
|
||||||
|
await preferencesController.setSelectedAddress('0x7e57e2')
|
||||||
|
await preferencesController.addToken(address, symbol, decimals)
|
||||||
|
assert.equal(preferencesController.getTokens().length, 1, 'one token added for 1st address')
|
||||||
|
|
||||||
|
await preferencesController.setSelectedAddress('0xda22le')
|
||||||
|
await preferencesController.addToken(address, symbol, decimals)
|
||||||
|
assert.equal(preferencesController.getTokens().length, 1, 'one token added for 2nd address')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('removeToken', function () {
|
||||||
|
it('should remove the only token from its state', async function () {
|
||||||
|
await preferencesController.setSelectedAddress('0x7e57e2')
|
||||||
|
await preferencesController.addToken('0xa', 'A', 5)
|
||||||
|
await preferencesController.removeToken('0xa')
|
||||||
|
|
||||||
|
const tokens = preferencesController.getTokens()
|
||||||
|
assert.equal(tokens.length, 0, 'one token removed')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should remove a token from its state', async function () {
|
||||||
|
await preferencesController.setSelectedAddress('0x7e57e2')
|
||||||
|
await preferencesController.addToken('0xa', 'A', 4)
|
||||||
|
await preferencesController.addToken('0xb', 'B', 5)
|
||||||
|
await preferencesController.removeToken('0xa')
|
||||||
|
|
||||||
|
const tokens = preferencesController.getTokens()
|
||||||
|
assert.equal(tokens.length, 1, 'one token removed')
|
||||||
|
|
||||||
|
const [token1] = tokens
|
||||||
|
assert.deepEqual(token1, {address: '0xb', symbol: 'B', decimals: 5})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ function mapDispatchToProps (dispatch) {
|
|||||||
dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' }))
|
dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' }))
|
||||||
},
|
},
|
||||||
hideModal: () => dispatch(actions.hideModal()),
|
hideModal: () => dispatch(actions.hideModal()),
|
||||||
saveAccountLabel: (address, label) => dispatch(actions.saveAccountLabel(address, label)),
|
setAccountLabel: (address, label) => dispatch(actions.setAccountLabel(address, label)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,8 +124,8 @@ var actions = {
|
|||||||
SHOW_PRIVATE_KEY: 'SHOW_PRIVATE_KEY',
|
SHOW_PRIVATE_KEY: 'SHOW_PRIVATE_KEY',
|
||||||
showPrivateKey: showPrivateKey,
|
showPrivateKey: showPrivateKey,
|
||||||
exportAccountComplete,
|
exportAccountComplete,
|
||||||
SAVE_ACCOUNT_LABEL: 'SAVE_ACCOUNT_LABEL',
|
SET_ACCOUNT_LABEL: 'SET_ACCOUNT_LABEL',
|
||||||
saveAccountLabel: saveAccountLabel,
|
setAccountLabel,
|
||||||
// tx conf screen
|
// tx conf screen
|
||||||
COMPLETED_TX: 'COMPLETED_TX',
|
COMPLETED_TX: 'COMPLETED_TX',
|
||||||
TRANSACTION_ERROR: 'TRANSACTION_ERROR',
|
TRANSACTION_ERROR: 'TRANSACTION_ERROR',
|
||||||
@ -1598,13 +1598,13 @@ function showPrivateKey (key) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveAccountLabel (account, label) {
|
function setAccountLabel (account, label) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(actions.showLoadingIndication())
|
dispatch(actions.showLoadingIndication())
|
||||||
log.debug(`background.saveAccountLabel`)
|
log.debug(`background.setAccountLabel`)
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
background.saveAccountLabel(account, label, (err) => {
|
background.setAccountLabel(account, label, (err) => {
|
||||||
dispatch(actions.hideLoadingIndication())
|
dispatch(actions.hideLoadingIndication())
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -1613,7 +1613,7 @@ function saveAccountLabel (account, label) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: actions.SAVE_ACCOUNT_LABEL,
|
type: actions.SET_ACCOUNT_LABEL,
|
||||||
value: { account, label },
|
value: { account, label },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ function mapDispatchToProps (dispatch) {
|
|||||||
dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' }))
|
dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' }))
|
||||||
},
|
},
|
||||||
hideModal: () => dispatch(actions.hideModal()),
|
hideModal: () => dispatch(actions.hideModal()),
|
||||||
saveAccountLabel: (address, label) => dispatch(actions.saveAccountLabel(address, label)),
|
setAccountLabel: (address, label) => dispatch(actions.setAccountLabel(address, label)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ AccountDetailsModal.prototype.render = function () {
|
|||||||
selectedIdentity,
|
selectedIdentity,
|
||||||
network,
|
network,
|
||||||
showExportPrivateKeyModal,
|
showExportPrivateKeyModal,
|
||||||
saveAccountLabel,
|
setAccountLabel,
|
||||||
} = this.props
|
} = this.props
|
||||||
const { name, address } = selectedIdentity
|
const { name, address } = selectedIdentity
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ AccountDetailsModal.prototype.render = function () {
|
|||||||
h(EditableLabel, {
|
h(EditableLabel, {
|
||||||
className: 'account-modal__name',
|
className: 'account-modal__name',
|
||||||
defaultValue: name,
|
defaultValue: name,
|
||||||
onSubmit: label => saveAccountLabel(address, label),
|
onSubmit: label => setAccountLabel(address, label),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
h(QrView, {
|
h(QrView, {
|
||||||
|
@ -18,8 +18,8 @@ function mapDispatchToProps (dispatch) {
|
|||||||
hideModal: () => {
|
hideModal: () => {
|
||||||
dispatch(actions.hideModal())
|
dispatch(actions.hideModal())
|
||||||
},
|
},
|
||||||
saveAccountLabel: (account, label) => {
|
setAccountLabel: (account, label) => {
|
||||||
dispatch(actions.saveAccountLabel(account, label))
|
dispatch(actions.setAccountLabel(account, label))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ module.exports = connect(mapStateToProps, mapDispatchToProps)(EditAccountNameMod
|
|||||||
|
|
||||||
|
|
||||||
EditAccountNameModal.prototype.render = function () {
|
EditAccountNameModal.prototype.render = function () {
|
||||||
const { hideModal, saveAccountLabel, identity } = this.props
|
const { hideModal, setAccountLabel, identity } = this.props
|
||||||
|
|
||||||
return h('div', {}, [
|
return h('div', {}, [
|
||||||
h('div.flex-column.edit-account-name-modal-content', {
|
h('div.flex-column.edit-account-name-modal-content', {
|
||||||
@ -69,7 +69,7 @@ EditAccountNameModal.prototype.render = function () {
|
|||||||
h('button.btn-clear.edit-account-name-modal-save-button.allcaps', {
|
h('button.btn-clear.edit-account-name-modal-save-button.allcaps', {
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
if (this.state.inputText.length !== 0) {
|
if (this.state.inputText.length !== 0) {
|
||||||
saveAccountLabel(identity.address, this.state.inputText)
|
setAccountLabel(identity.address, this.state.inputText)
|
||||||
hideModal()
|
hideModal()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -95,7 +95,7 @@ const mapDispatchToProps = dispatch => {
|
|||||||
dispatch(actions.addNewAccount())
|
dispatch(actions.addNewAccount())
|
||||||
.then((newAccountAddress) => {
|
.then((newAccountAddress) => {
|
||||||
if (newAccountName) {
|
if (newAccountName) {
|
||||||
dispatch(actions.saveAccountLabel(newAccountAddress, newAccountName))
|
dispatch(actions.setAccountLabel(newAccountAddress, newAccountName))
|
||||||
}
|
}
|
||||||
dispatch(actions.hideModal())
|
dispatch(actions.hideModal())
|
||||||
})
|
})
|
||||||
|
@ -75,7 +75,7 @@ const mapDispatchToProps = dispatch => ({
|
|||||||
dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' }))
|
dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' }))
|
||||||
},
|
},
|
||||||
hideModal: () => dispatch(actions.hideModal()),
|
hideModal: () => dispatch(actions.hideModal()),
|
||||||
saveAccountLabel: (address, label) => dispatch(actions.saveAccountLabel(address, label)),
|
setAccountLabel: (address, label) => dispatch(actions.setAccountLabel(address, label)),
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(CreateAccountPage)
|
module.exports = connect(mapStateToProps, mapDispatchToProps)(CreateAccountPage)
|
||||||
|
@ -87,7 +87,7 @@ const mapDispatchToProps = dispatch => {
|
|||||||
return dispatch(actions.addNewAccount())
|
return dispatch(actions.addNewAccount())
|
||||||
.then(newAccountAddress => {
|
.then(newAccountAddress => {
|
||||||
if (newAccountName) {
|
if (newAccountName) {
|
||||||
dispatch(actions.saveAccountLabel(newAccountAddress, newAccountName))
|
dispatch(actions.setAccountLabel(newAccountAddress, newAccountName))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -163,7 +163,7 @@ function reduceMetamask (state, action) {
|
|||||||
selectedTokenAddress: action.value,
|
selectedTokenAddress: action.value,
|
||||||
})
|
})
|
||||||
|
|
||||||
case actions.SAVE_ACCOUNT_LABEL:
|
case actions.SET_ACCOUNT_LABEL:
|
||||||
const account = action.value.account
|
const account = action.value.account
|
||||||
const name = action.value.label
|
const name = action.value.label
|
||||||
const id = {}
|
const id = {}
|
||||||
|
Loading…
Reference in New Issue
Block a user