mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
move TrezorKeyring to its own package
This commit is contained in:
parent
d4201ae1cc
commit
8763ea898e
File diff suppressed because it is too large
Load Diff
@ -1,239 +0,0 @@
|
|||||||
const { EventEmitter } = require('events')
|
|
||||||
const ethUtil = require('ethereumjs-util')
|
|
||||||
const sigUtil = require('eth-sig-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_MIN_FIRMWARE_VERSION = '1.5.2'
|
|
||||||
const log = require('loglevel')
|
|
||||||
|
|
||||||
class TrezorKeyring extends EventEmitter {
|
|
||||||
constructor (opts = {}) {
|
|
||||||
super()
|
|
||||||
this.type = keyringType
|
|
||||||
this.accounts = []
|
|
||||||
this.hdk = new HDKey()
|
|
||||||
this.deserialize(opts)
|
|
||||||
this.page = 0
|
|
||||||
this.perPage = 5
|
|
||||||
this.unlockedAccount = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
serialize () {
|
|
||||||
return Promise.resolve({
|
|
||||||
hdPath: this.hdPath,
|
|
||||||
accounts: this.accounts,
|
|
||||||
page: this.page,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
deserialize (opts = {}) {
|
|
||||||
this.hdPath = opts.hdPath || hdPathString
|
|
||||||
this.accounts = opts.accounts || []
|
|
||||||
this.page = opts.page || 0
|
|
||||||
return Promise.resolve()
|
|
||||||
}
|
|
||||||
|
|
||||||
unlock () {
|
|
||||||
|
|
||||||
if (this.hdk.publicKey) return Promise.resolve()
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
TrezorConnect.getXPubKey(
|
|
||||||
this.hdPath,
|
|
||||||
response => {
|
|
||||||
if (response.success) {
|
|
||||||
this.hdk.publicKey = new Buffer(response.publicKey, 'hex')
|
|
||||||
this.hdk.chainCode = new Buffer(response.chainCode, 'hex')
|
|
||||||
resolve()
|
|
||||||
} else {
|
|
||||||
reject(response.error || 'Unknown error')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TREZOR_MIN_FIRMWARE_VERSION
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
setAccountToUnlock (index) {
|
|
||||||
this.unlockedAccount = parseInt(index, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
addAccounts (n = 1) {
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
return this.unlock()
|
|
||||||
.then(_ => {
|
|
||||||
const from = this.unlockedAccount
|
|
||||||
const to = from + 1
|
|
||||||
this.accounts = []
|
|
||||||
|
|
||||||
for (let i = from; i < to; i++) {
|
|
||||||
|
|
||||||
this.accounts.push(this._addressFromId(pathBase, i))
|
|
||||||
this.page = 0
|
|
||||||
}
|
|
||||||
resolve(this.accounts)
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
reject(e)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
getPage () {
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
return this.unlock()
|
|
||||||
.then(_ => {
|
|
||||||
|
|
||||||
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++) {
|
|
||||||
|
|
||||||
accounts.push({
|
|
||||||
address: this._addressFromId(pathBase, i),
|
|
||||||
balance: 0,
|
|
||||||
index: i,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
log.debug(accounts)
|
|
||||||
resolve(accounts)
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
reject(e)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPrevAccountSet () {
|
|
||||||
this.page--
|
|
||||||
return await this.getPage()
|
|
||||||
}
|
|
||||||
|
|
||||||
async getNextAccountSet () {
|
|
||||||
this.page++
|
|
||||||
return await this.getPage()
|
|
||||||
}
|
|
||||||
|
|
||||||
getAccounts () {
|
|
||||||
return Promise.resolve(this.accounts.slice())
|
|
||||||
}
|
|
||||||
|
|
||||||
// tx is an instance of the ethereumjs-transaction class.
|
|
||||||
async signTransaction (address, tx) {
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
|
|
||||||
log.debug('sign transaction ', address, tx)
|
|
||||||
|
|
||||||
TrezorConnect.ethereumSignTx(
|
|
||||||
this._getUnlockedAccount(),
|
|
||||||
this._normalize(tx.nonce),
|
|
||||||
this._normalize(tx.gasPrice),
|
|
||||||
this._normalize(tx.gasLimit),
|
|
||||||
this._normalize(tx.to),
|
|
||||||
this._normalize(tx.value),
|
|
||||||
this._normalize(tx.data),
|
|
||||||
tx._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)
|
|
||||||
|
|
||||||
const addressSignedWith = ethUtil.toChecksumAddress(`0x${signedTx.from.toString('hex')}`)
|
|
||||||
const correctAddress = ethUtil.toChecksumAddress(address)
|
|
||||||
if (addressSignedWith !== correctAddress) {
|
|
||||||
log.error('signature doesnt match the right address', addressSignedWith, correctAddress)
|
|
||||||
throw new Error('signature doesnt match the right address')
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(signedTx)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new Error(response.error || 'Unknown error')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TREZOR_MIN_FIRMWARE_VERSION)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async signMessage (withAccount, data) {
|
|
||||||
throw new Error('Not supported on this device')
|
|
||||||
}
|
|
||||||
|
|
||||||
// For personal_sign, we need to prefix the message:
|
|
||||||
async signPersonalMessage (withAccount, message) {
|
|
||||||
|
|
||||||
TrezorConnect.ethereumSignMessage(this._getUnlockedAccount(), message, response => {
|
|
||||||
if (response.success) {
|
|
||||||
|
|
||||||
const signature = this._personalToRawSig(response.signature)
|
|
||||||
const addressSignedWith = sigUtil.recoverPersonalSignature({data: message, sig: signature})
|
|
||||||
const correctAddress = ethUtil.toChecksumAddress(withAccount)
|
|
||||||
if (addressSignedWith !== correctAddress) {
|
|
||||||
log.error('signature doesnt match the right address', addressSignedWith, correctAddress)
|
|
||||||
throw new Error('signature doesnt match the right address')
|
|
||||||
}
|
|
||||||
return signature
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new Error(response.error || 'Unknown error')
|
|
||||||
}
|
|
||||||
|
|
||||||
}, TREZOR_MIN_FIRMWARE_VERSION)
|
|
||||||
}
|
|
||||||
|
|
||||||
async signTypedData (withAccount, typedData) {
|
|
||||||
// Waiting on trezor to enable this
|
|
||||||
throw new Error('Not supported on this device')
|
|
||||||
}
|
|
||||||
|
|
||||||
async exportAccount (address) {
|
|
||||||
throw new Error('Not supported on this device')
|
|
||||||
}
|
|
||||||
|
|
||||||
_padLeftEven (hex) {
|
|
||||||
return hex.length % 2 !== 0 ? `0${hex}` : hex
|
|
||||||
}
|
|
||||||
|
|
||||||
_normalize (buf) {
|
|
||||||
return this._padLeftEven(ethUtil.bufferToHex(buf).substring(2).toLowerCase())
|
|
||||||
}
|
|
||||||
|
|
||||||
_addressFromId (pathBase, i) {
|
|
||||||
const dkey = this.hdk.derive(`${pathBase}/${i}`)
|
|
||||||
const address = ethUtil
|
|
||||||
.publicToAddress(dkey.publicKey, true)
|
|
||||||
.toString('hex')
|
|
||||||
return ethUtil.toChecksumAddress(address)
|
|
||||||
}
|
|
||||||
|
|
||||||
_getUnlockedAccount () {
|
|
||||||
return `${this.hdPath}/${this.unlockedAccount}`
|
|
||||||
}
|
|
||||||
|
|
||||||
_personalToRawSig (signature) {
|
|
||||||
var v = signature['v'] - 27
|
|
||||||
v = v.toString(16)
|
|
||||||
if (v.length < 2) {
|
|
||||||
v = '0' + v
|
|
||||||
}
|
|
||||||
return '0x' + signature['r'] + signature['s'] + v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TrezorKeyring.type = keyringType
|
|
||||||
module.exports = TrezorKeyring
|
|
@ -48,7 +48,7 @@ const seedPhraseVerifier = require('./lib/seed-phrase-verifier')
|
|||||||
const cleanErrorStack = require('./lib/cleanErrorStack')
|
const cleanErrorStack = require('./lib/cleanErrorStack')
|
||||||
const DiagnosticsReporter = require('./lib/diagnostics-reporter')
|
const DiagnosticsReporter = require('./lib/diagnostics-reporter')
|
||||||
const log = require('loglevel')
|
const log = require('loglevel')
|
||||||
const TrezorKeyring = require('./lib/trezorKeyring')
|
const TrezorKeyring = require('eth-trezor-keyring')
|
||||||
|
|
||||||
module.exports = class MetamaskController extends EventEmitter {
|
module.exports = class MetamaskController extends EventEmitter {
|
||||||
|
|
||||||
@ -549,7 +549,8 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
throw new Error('MetamaskController - No Trezor Hardware Keyring found')
|
throw new Error('MetamaskController - No Trezor Hardware Keyring found')
|
||||||
}
|
}
|
||||||
|
|
||||||
const accounts = page === -1 ? await keyring.getPrevAccountSet(this.provider) : await keyring.getNextAccountSet(this.provider)
|
const accounts = await keyring.getPage(page)
|
||||||
|
|
||||||
this.accountTracker.syncWithAddresses(accounts.map(a => a.address))
|
this.accountTracker.syncWithAddresses(accounts.map(a => a.address))
|
||||||
|
|
||||||
return accounts
|
return accounts
|
||||||
|
46
package-lock.json
generated
46
package-lock.json
generated
@ -8488,6 +8488,52 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"eth-trezor-keyring": {
|
||||||
|
"version": "github:brunobar79/eth-trezor-keyring#c138d26c36a01f15be5e12a81e4fcbf56b044fa4",
|
||||||
|
"from": "github:brunobar79/eth-trezor-keyring#c138d26c36a01f15be5e12a81e4fcbf56b044fa4",
|
||||||
|
"requires": {
|
||||||
|
"eth-sig-util": "^1.4.2",
|
||||||
|
"ethereumjs-tx": "^1.3.4",
|
||||||
|
"ethereumjs-util": "^5.1.5",
|
||||||
|
"events": "^2.0.0",
|
||||||
|
"hdkey": "0.8.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ethereum-common": {
|
||||||
|
"version": "0.0.18",
|
||||||
|
"resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.18.tgz",
|
||||||
|
"integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8="
|
||||||
|
},
|
||||||
|
"ethereumjs-tx": {
|
||||||
|
"version": "1.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.4.tgz",
|
||||||
|
"integrity": "sha512-kOgUd5jC+0tgV7t52UDECMMz9Uf+Lro+6fSpCvzWemtXfMEcwI3EOxf5mVPMRbTFkMMhuERokNNVF3jItAjidg==",
|
||||||
|
"requires": {
|
||||||
|
"ethereum-common": "^0.0.18",
|
||||||
|
"ethereumjs-util": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ethereumjs-util": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==",
|
||||||
|
"requires": {
|
||||||
|
"bn.js": "^4.11.0",
|
||||||
|
"create-hash": "^1.1.2",
|
||||||
|
"ethjs-util": "^0.1.3",
|
||||||
|
"keccak": "^1.0.2",
|
||||||
|
"rlp": "^2.0.0",
|
||||||
|
"safe-buffer": "^5.1.1",
|
||||||
|
"secp256k1": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"events": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"eth-tx-summary": {
|
"eth-tx-summary": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/eth-tx-summary/-/eth-tx-summary-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/eth-tx-summary/-/eth-tx-summary-3.2.1.tgz",
|
||||||
|
@ -102,6 +102,7 @@
|
|||||||
"eth-query": "^2.1.2",
|
"eth-query": "^2.1.2",
|
||||||
"eth-sig-util": "^1.4.2",
|
"eth-sig-util": "^1.4.2",
|
||||||
"eth-token-tracker": "^1.1.4",
|
"eth-token-tracker": "^1.1.4",
|
||||||
|
"eth-trezor-keyring": "github:brunobar79/eth-trezor-keyring#c138d26c36a01f15be5e12a81e4fcbf56b044fa4",
|
||||||
"ethereumjs-abi": "^0.6.4",
|
"ethereumjs-abi": "^0.6.4",
|
||||||
"ethereumjs-tx": "^1.3.0",
|
"ethereumjs-tx": "^1.3.0",
|
||||||
"ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
|
"ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
|
||||||
@ -124,7 +125,6 @@
|
|||||||
"gulp-eslint": "^4.0.0",
|
"gulp-eslint": "^4.0.0",
|
||||||
"gulp-sass": "^4.0.0",
|
"gulp-sass": "^4.0.0",
|
||||||
"hat": "0.0.3",
|
"hat": "0.0.3",
|
||||||
"hdkey": "0.8.0",
|
|
||||||
"human-standard-token-abi": "^1.0.2",
|
"human-standard-token-abi": "^1.0.2",
|
||||||
"idb-global": "^2.1.0",
|
"idb-global": "^2.1.0",
|
||||||
"identicon.js": "^2.3.1",
|
"identicon.js": "^2.3.1",
|
||||||
|
@ -25,10 +25,10 @@ class ConnectHardwareForm extends Component {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
this.setState({ btnText: 'Connecting...' })
|
this.setState({ btnText: 'Connecting...' })
|
||||||
this.getPage()
|
this.getPage(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
getPage (page = 1) {
|
getPage (page) {
|
||||||
this.props
|
this.props
|
||||||
.connectHardware('trezor', page)
|
.connectHardware('trezor', page)
|
||||||
.then(accounts => {
|
.then(accounts => {
|
||||||
@ -133,7 +133,7 @@ class ConnectHardwareForm extends Component {
|
|||||||
h(
|
h(
|
||||||
'button.btn-primary.hw-list-pagination__button',
|
'button.btn-primary.hw-list-pagination__button',
|
||||||
{
|
{
|
||||||
onClick: () => this.getPage(),
|
onClick: () => this.getPage(1),
|
||||||
},
|
},
|
||||||
'Next >'
|
'Next >'
|
||||||
),
|
),
|
||||||
|
Loading…
Reference in New Issue
Block a user