diff options
Diffstat (limited to 'app/scripts')
-rw-r--r-- | app/scripts/lib/trezorKeyring.js | 126 |
1 files changed, 77 insertions, 49 deletions
diff --git a/app/scripts/lib/trezorKeyring.js b/app/scripts/lib/trezorKeyring.js index fb029f82a..fa5d6070c 100644 --- a/app/scripts/lib/trezorKeyring.js +++ b/app/scripts/lib/trezorKeyring.js @@ -4,10 +4,11 @@ const ethUtil = require('ethereumjs-util') const hdPathString = `m/44'/60'/0'/0` const keyringType = 'Trezor Hardware' - +const Transaction = require('ethereumjs-tx') +const pathBase = 'm' const TrezorConnect = require('./trezor-connect.js') const HDKey = require('hdkey') -const TREZOR_FIRMWARE_VERSION = '1.4.0' +const TREZOR_MIN_FIRMWARE_VERSION = '1.5.2' const log = require('loglevel') class TrezorKeyring extends EventEmitter { @@ -19,7 +20,7 @@ class TrezorKeyring extends EventEmitter { this.deserialize(opts) this.page = 0 this.perPage = 5 - this.accountToUnlock = 0 + this.unlockedAccount = 0 } serialize () { @@ -53,13 +54,13 @@ class TrezorKeyring extends EventEmitter { reject(response.error || 'Unknown error') } }, - TREZOR_FIRMWARE_VERSION + TREZOR_MIN_FIRMWARE_VERSION ) }) } setAccountToUnlock (index) { - this.accountToUnlock = parseInt(index, 10) + this.unlockedAccount = parseInt(index, 10) } addAccounts (n = 1) { @@ -67,18 +68,13 @@ class TrezorKeyring extends EventEmitter { return new Promise((resolve, reject) => { return this.unlock() .then(_ => { - const pathBase = 'm' - const from = this.accountToUnlock + const from = this.unlockedAccount const to = from + 1 - this.accounts = [] for (let i = from; i < to; i++) { - const dkey = this.hdk.derive(`${pathBase}/${i}`) - const address = ethUtil - .publicToAddress(dkey.publicKey, true) - .toString('hex') - this.accounts.push(ethUtil.toChecksumAddress(address)) + + this.accounts.push(this.getEthAddress(pathBase, i)) this.page = 0 } resolve(this.accounts) @@ -94,19 +90,16 @@ class TrezorKeyring extends EventEmitter { return new Promise((resolve, reject) => { return this.unlock() .then(_ => { - const pathBase = 'm' + const from = this.page === 0 ? 0 : (this.page - 1) * this.perPage const to = from + this.perPage const accounts = [] for (let i = from; i < to; i++) { - const dkey = this.hdk.derive(`${pathBase}/${i}`) - const address = ethUtil - .publicToAddress(dkey.publicKey, true) - .toString('hex') + accounts.push({ - address: ethUtil.toChecksumAddress(address), + address: this.getEthAddress(pathBase, i), balance: 0, index: i, }) @@ -134,40 +127,75 @@ class TrezorKeyring extends EventEmitter { return Promise.resolve(this.accounts.slice()) } - // tx is an instance of the ethereumjs-transaction class. - async signTransaction (address, tx) { - throw new Error('Not supported on this device') - /* - await this.lock.acquire() - try { - - // Look before we leap - await this._checkCorrectTrezorAttached() + padLeftEven (hex) { + return hex.length % 2 !== 0 ? `0${hex}` : hex + } - let accountId = await this._findAddressId(address) - let eth = await this._getEth() - tx.v = tx._chainId - let TrezorSig = await eth.signTransaction( - this._derivePath(accountId), - tx.serialize().toString('hex') - ) - tx.v = parseInt(TrezorSig.v, 16) - tx.r = '0x' + TrezorSig.r - tx.s = '0x' + TrezorSig.s + cleanData (buf) { + return this.padLeftEven(ethUtil.bufferToHex(buf).substring(2).toLowerCase()) + } - // Since look before we leap check is racy, also check that signature is for account expected - let addressSignedWith = ethUtil.bufferToHex(tx.getSenderAddress()) - if (addressSignedWith.toLowerCase() !== address.toLowerCase()) { - throw new Error( - `Signature is for ${addressSignedWith} but expected ${address} - is the correct Trezor device attached?` - ) - } + getEthAddress (pathBase, i) { + const dkey = this.hdk.derive(`${pathBase}/${i}`) + const address = ethUtil + .publicToAddress(dkey.publicKey, true) + .toString('hex') + return ethUtil.toChecksumAddress(address) + } - return tx + // tx is an instance of the ethereumjs-transaction class. + async signTransaction (address, tx) { - } finally { - await this.lock.release() - }*/ + return new Promise((resolve, reject) => { + log.debug('sign transaction ', address, tx) + const account = `m/44'/60'/0'/${this.unlockedAccount}` + + const txData = { + account, + nonce: this.cleanData(tx.nonce), + gasPrice: this.cleanData(tx.gasPrice), + gasLimit: this.cleanData(tx.gasLimit), + to: this.cleanData(tx.to), + value: this.cleanData(tx.value), + data: this.cleanData(tx.data), + chainId: tx._chainId, + } + + TrezorConnect.ethereumSignTx( + txData.account, + txData.nonce, + txData.gasPrice, + txData.gasLimit, + txData.to, + txData.value, + txData.data === '' ? null : txData.data, + txData.chainId, + response => { + if (response.success) { + tx.v = `0x${response.v.toString(16)}` + tx.r = `0x${response.r}` + tx.s = `0x${response.s}` + log.debug('about to create new tx with data', tx) + + const signedTx = new Transaction(tx) + + log.debug('signature is valid?', signedTx.verifySignature()) + + const addressSignedWith = ethUtil.toChecksumAddress(`0x${signedTx.from.toString('hex')}`) + const correctAddress = ethUtil.toChecksumAddress(address) + if (addressSignedWith !== correctAddress) { + // throw new Error('signature doesnt match the right address') + log.error('signature doesnt match the right address', addressSignedWith, correctAddress) + } + + resolve(signedTx) + + } else { + throw new Error(response.error || 'Unknown error') + } + }, + TREZOR_MIN_FIRMWARE_VERSION) + }) } async signMessage (withAccount, data) { |