able to add accounts

feature/default_network_editable
brunobar79 6 years ago
parent 78a1cd3314
commit 8e842a8947
  1. 137
      app/scripts/eth-ledger-keyring-listener.js
  2. 2
      app/scripts/metamask-controller.js
  3. 2
      ui/app/components/pages/create-account/connect-hardware/account-list.js
  4. 4
      ui/app/components/pages/create-account/connect-hardware/index.js

@ -1,11 +1,16 @@
const extension = require('extensionizer') const extension = require('extensionizer')
const {EventEmitter} = require('events') const {EventEmitter} = require('events')
const HDKey = require('hdkey')
const ethUtil = require('ethereumjs-util')
const sigUtil = require('eth-sig-util')
const Transaction = require('ethereumjs-tx')
// HD path differs from eth-hd-keyring - MEW, Parity, Geth and Official Ledger clients use same unusual derivation for Ledger // HD path differs from eth-hd-keyring - MEW, Parity, Geth and Official Ledger clients use same unusual derivation for Ledger
const hdPathString = `m/44'/60'/0'` const hdPathString = `m/44'/60'/0'`
const type = 'Ledger Hardware Keyring' const type = 'Ledger Hardware Keyring'
const ORIGIN = 'http://localhost:9000' const ORIGIN = 'https://localhost:3000'
const pathBase = 'm'
class LedgerKeyring extends EventEmitter { class LedgerKeyring extends EventEmitter {
constructor (opts = {}) { constructor (opts = {}) {
@ -14,6 +19,7 @@ class LedgerKeyring extends EventEmitter {
this.page = 0 this.page = 0
this.perPage = 5 this.perPage = 5
this.unlockedAccount = 0 this.unlockedAccount = 0
this.hdk = new HDKey()
this.paths = {} this.paths = {}
this.iframe = null this.iframe = null
this.setupIframe() this.setupIframe()
@ -26,10 +32,6 @@ class LedgerKeyring extends EventEmitter {
console.log('Injecting ledger iframe') console.log('Injecting ledger iframe')
document.head.appendChild(this.iframe) document.head.appendChild(this.iframe)
/*
Passing messages from iframe to background script
*/
console.log('[LEDGER]: LEDGER FROM-IFRAME LISTENER READY') console.log('[LEDGER]: LEDGER FROM-IFRAME LISTENER READY')
} }
@ -78,32 +80,39 @@ class LedgerKeyring extends EventEmitter {
}, },
({action, success, payload}) => { ({action, success, payload}) => {
if (success) { if (success) {
resolve(payload) this.hdk.publicKey = new Buffer(payload.publicKey, 'hex')
this.hdk.chainCode = new Buffer(payload.chainCode, 'hex')
resolve('just unlocked')
} else { } else {
reject(payload) reject(payload.error || 'Unknown error')
} }
}) })
}) })
} }
async addAccounts (n = 1) { setAccountToUnlock (index) {
this.unlockedAccount = parseInt(index, 10)
}
addAccounts (n = 1) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.unlock() this.unlock()
.then(_ => { .then(_ => {
this.sendMessage({ const from = this.unlockedAccount
action: 'ledger-add-account', const to = from + n
params: { this.accounts = []
n,
}, for (let i = from; i < to; i++) {
}, const address = this._addressFromIndex(pathBase, i)
({action, success, payload}) => { this.accounts.push(address)
if (success) { this.page = 0
resolve(payload)
} else {
reject(payload)
} }
resolve(this.accounts)
})
.catch(e => {
reject(e)
}) })
})
}) })
} }
@ -129,20 +138,27 @@ class LedgerKeyring extends EventEmitter {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.unlock() this.unlock()
.then(_ => { .then(_ => {
this.sendMessage({
action: 'ledger-get-page', const from = (this.page - 1) * this.perPage
params: { const to = from + this.perPage
page: this.page,
}, const accounts = []
},
({action, success, payload}) => { for (let i = from; i < to; i++) {
if (success) { const address = this._addressFromIndex(pathBase, i)
resolve(payload) accounts.push({
} else { address: address,
reject(payload) balance: null,
} index: i,
}) })
}) this.paths[ethUtil.toChecksumAddress(address)] = i
}
resolve(accounts)
})
.catch(e => {
reject(e)
})
}) })
} }
@ -157,6 +173,7 @@ class LedgerKeyring extends EventEmitter {
this.accounts = this.accounts.filter(a => a.toLowerCase() !== address.toLowerCase()) this.accounts = this.accounts.filter(a => a.toLowerCase() !== address.toLowerCase())
} }
// tx is an instance of the ethereumjs-transaction class. // tx is an instance of the ethereumjs-transaction class.
async signTransaction (address, tx) { async signTransaction (address, tx) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -224,6 +241,56 @@ class LedgerKeyring extends EventEmitter {
this.unlockedAccount = 0 this.unlockedAccount = 0
this.paths = {} this.paths = {}
} }
/* PRIVATE METHODS */
_padLeftEven (hex) {
return hex.length % 2 !== 0 ? `0${hex}` : hex
}
_normalize (buf) {
return this._padLeftEven(ethUtil.bufferToHex(buf).substring(2).toLowerCase())
}
_addressFromIndex (pathBase, i) {
const dkey = this.hdk.derive(`${pathBase}/${i}`)
const address = ethUtil
.publicToAddress(dkey.publicKey, true)
.toString('hex')
return ethUtil.toChecksumAddress(address)
}
_pathFromAddress (address) {
const checksummedAddress = ethUtil.toChecksumAddress(address)
let index = this.paths[checksummedAddress]
if (typeof index === 'undefined') {
for (let i = 0; i < MAX_INDEX; i++) {
if (checksummedAddress === this._addressFromIndex(pathBase, i)) {
index = i
break
}
}
}
if (typeof index === 'undefined') {
throw new Error('Unknown address')
}
return `${this.hdPath}/${index}`
}
_toAscii (hex) {
let str = ''
let i = 0; const l = hex.length
if (hex.substring(0, 2) === '0x') {
i = 2
}
for (; i < l; i += 2) {
const code = parseInt(hex.substr(i, 2), 16)
str += String.fromCharCode(code)
}
return str
}
} }
LedgerKeyring.type = type LedgerKeyring.type = type

@ -615,7 +615,7 @@ module.exports = class MetamaskController extends EventEmitter {
* *
* @returns {} keyState * @returns {} keyState
*/ */
async unlockHardwareWalletAccount (deviceName, index) { async unlockHardwareWalletAccount (index, deviceName) {
const keyring = await this.getKeyringForDevice(deviceName) const keyring = await this.getKeyringForDevice(deviceName)
keyring.setAccountToUnlock(index) keyring.setAccountToUnlock(index)

@ -11,7 +11,7 @@ class AccountList extends Component {
renderHeader () { renderHeader () {
return ( return (
h('div.hw-connect', [ h('div.hw-connect', [
h('h3.hw-connect__title', {}, this.context.t('selectAnAccount')), h('h3.hw-connect__title', {}, `${this.props.device.toUpperCase()} - ${this.context.t('selectAnAccount')}`),
h('p.hw-connect__msg', {}, this.context.t('selectAnAccountHelp')), h('p.hw-connect__msg', {}, this.context.t('selectAnAccountHelp')),
]) ])
) )

@ -128,13 +128,13 @@ class ConnectHardwareForm extends Component {
}) })
} }
onUnlockAccount = () => { onUnlockAccount = (device) => {
if (this.state.selectedAccount === null) { if (this.state.selectedAccount === null) {
this.setState({ error: this.context.t('accountSelectionRequired') }) this.setState({ error: this.context.t('accountSelectionRequired') })
} }
this.props.unlockHardwareWalletAccount(this.state.selectedAccount, this.state.device) this.props.unlockHardwareWalletAccount(this.state.selectedAccount, device)
.then(_ => { .then(_ => {
this.props.history.push(DEFAULT_ROUTE) this.props.history.push(DEFAULT_ROUTE)
}).catch(e => { }).catch(e => {

Loading…
Cancel
Save