mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
refactor to support multiple hw wallets
This commit is contained in:
parent
e2be22a4b7
commit
5ef80495cf
@ -48,7 +48,8 @@
|
|||||||
"https://*/*"
|
"https://*/*"
|
||||||
],
|
],
|
||||||
"js": [
|
"js": [
|
||||||
"contentscript.js"
|
"contentscript.js",
|
||||||
|
"vendor/ledger/content-script.js"
|
||||||
],
|
],
|
||||||
"run_at": "document_start",
|
"run_at": "document_start",
|
||||||
"all_frames": true
|
"all_frames": true
|
||||||
|
105
app/scripts/eth-ledger-keyring-listener.js
Normal file
105
app/scripts/eth-ledger-keyring-listener.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
const extension = require('extensionizer')
|
||||||
|
const {EventEmitter} = require('events')
|
||||||
|
|
||||||
|
|
||||||
|
// 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 type = 'Ledger Hardware Keyring'
|
||||||
|
|
||||||
|
class LedgerKeyring extends EventEmitter {
|
||||||
|
constructor (opts = {}) {
|
||||||
|
super()
|
||||||
|
this.type = type
|
||||||
|
this.deserialize(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize () {
|
||||||
|
return Promise.resolve({hdPath: this.hdPath, accounts: this.accounts})
|
||||||
|
}
|
||||||
|
|
||||||
|
deserialize (opts = {}) {
|
||||||
|
this.hdPath = opts.hdPath || hdPathString
|
||||||
|
this.accounts = opts.accounts || []
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
async addAccounts (n = 1) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
extension.runtime.sendMessage({
|
||||||
|
action: 'ledger-add-account',
|
||||||
|
n,
|
||||||
|
})
|
||||||
|
|
||||||
|
extension.runtime.onMessage.addListener(({action, success, payload}) => {
|
||||||
|
if (action === 'ledger-sign-transaction') {
|
||||||
|
if (success) {
|
||||||
|
resolve(payload)
|
||||||
|
} else {
|
||||||
|
reject(payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAccounts () {
|
||||||
|
return this.accounts.slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
// tx is an instance of the ethereumjs-transaction class.
|
||||||
|
async signTransaction (address, tx) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
extension.runtime.sendMessage({
|
||||||
|
action: 'ledger-sign-transaction',
|
||||||
|
address,
|
||||||
|
tx,
|
||||||
|
})
|
||||||
|
|
||||||
|
extension.runtime.onMessage.addListener(({action, success, payload}) => {
|
||||||
|
if (action === 'ledger-sign-transaction') {
|
||||||
|
if (success) {
|
||||||
|
resolve(payload)
|
||||||
|
} else {
|
||||||
|
reject(payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
extension.runtime.sendMessage({
|
||||||
|
action: 'ledger-sign-personal-message',
|
||||||
|
withAccount,
|
||||||
|
message,
|
||||||
|
})
|
||||||
|
|
||||||
|
extension.runtime.onMessage.addListener(({action, success, payload}) => {
|
||||||
|
if (action === 'ledger-sign-personal-message') {
|
||||||
|
if (success) {
|
||||||
|
resolve(payload)
|
||||||
|
} else {
|
||||||
|
reject(payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async signTypedData (withAccount, typedData) {
|
||||||
|
throw new Error('Not supported on this device')
|
||||||
|
}
|
||||||
|
|
||||||
|
async exportAccount (address) {
|
||||||
|
throw new Error('Not supported on this device')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LedgerKeyring.type = type
|
||||||
|
module.exports = LedgerKeyring
|
@ -49,6 +49,7 @@ const seedPhraseVerifier = require('./lib/seed-phrase-verifier')
|
|||||||
const cleanErrorStack = require('./lib/cleanErrorStack')
|
const cleanErrorStack = require('./lib/cleanErrorStack')
|
||||||
const log = require('loglevel')
|
const log = require('loglevel')
|
||||||
const TrezorKeyring = require('eth-trezor-keyring')
|
const TrezorKeyring = require('eth-trezor-keyring')
|
||||||
|
const LedgerKeyring = require('./eth-ledger-keyring-listener')
|
||||||
|
|
||||||
module.exports = class MetamaskController extends EventEmitter {
|
module.exports = class MetamaskController extends EventEmitter {
|
||||||
|
|
||||||
@ -127,7 +128,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// key mgmt
|
// key mgmt
|
||||||
const additionalKeyrings = [TrezorKeyring]
|
const additionalKeyrings = [TrezorKeyring, LedgerKeyring]
|
||||||
this.keyringController = new KeyringController({
|
this.keyringController = new KeyringController({
|
||||||
keyringTypes: additionalKeyrings,
|
keyringTypes: additionalKeyrings,
|
||||||
initState: initState.KeyringController,
|
initState: initState.KeyringController,
|
||||||
@ -377,9 +378,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
connectHardware: nodeify(this.connectHardware, this),
|
connectHardware: nodeify(this.connectHardware, this),
|
||||||
forgetDevice: nodeify(this.forgetDevice, this),
|
forgetDevice: nodeify(this.forgetDevice, this),
|
||||||
checkHardwareStatus: nodeify(this.checkHardwareStatus, this),
|
checkHardwareStatus: nodeify(this.checkHardwareStatus, this),
|
||||||
|
unlockHardwareWalletAccount: nodeify(this.unlockHardwareWalletAccount, this),
|
||||||
// TREZOR
|
|
||||||
unlockTrezorAccount: nodeify(this.unlockTrezorAccount, this),
|
|
||||||
|
|
||||||
// vault management
|
// vault management
|
||||||
submitPassword: nodeify(this.submitPassword, this),
|
submitPassword: nodeify(this.submitPassword, this),
|
||||||
@ -540,6 +539,28 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
// Hardware
|
// Hardware
|
||||||
//
|
//
|
||||||
|
|
||||||
|
async getKeyringForDevice (deviceName) {
|
||||||
|
let keyringName = null
|
||||||
|
switch (deviceName) {
|
||||||
|
case 'trezor':
|
||||||
|
keyringName = TrezorKeyring.type
|
||||||
|
break
|
||||||
|
case 'ledger':
|
||||||
|
keyringName = TrezorKeyring.type
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error('MetamaskController:connectHardware - Unknown device')
|
||||||
|
}
|
||||||
|
|
||||||
|
let keyring = await this.keyringController.getKeyringsByType(keyringName)[0]
|
||||||
|
if (!keyring) {
|
||||||
|
keyring = await this.keyringController.addNewKeyring(keyringName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return keyring
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch account list from a trezor device.
|
* Fetch account list from a trezor device.
|
||||||
*
|
*
|
||||||
@ -547,38 +568,26 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
async connectHardware (deviceName, page) {
|
async connectHardware (deviceName, page) {
|
||||||
|
|
||||||
switch (deviceName) {
|
const oldAccounts = await this.keyringController.getAccounts()
|
||||||
case 'trezor':
|
const keyring = await this.getKeyringForDevice(deviceName)
|
||||||
const keyringController = this.keyringController
|
let accounts = []
|
||||||
const oldAccounts = await keyringController.getAccounts()
|
|
||||||
let keyring = await keyringController.getKeyringsByType(
|
|
||||||
'Trezor Hardware'
|
|
||||||
)[0]
|
|
||||||
if (!keyring) {
|
|
||||||
keyring = await this.keyringController.addNewKeyring('Trezor Hardware')
|
|
||||||
}
|
|
||||||
let accounts = []
|
|
||||||
|
|
||||||
switch (page) {
|
switch (page) {
|
||||||
case -1:
|
case -1:
|
||||||
accounts = await keyring.getPreviousPage()
|
accounts = await keyring.getPreviousPage()
|
||||||
break
|
break
|
||||||
case 1:
|
case 1:
|
||||||
accounts = await keyring.getNextPage()
|
accounts = await keyring.getNextPage()
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
accounts = await keyring.getFirstPage()
|
accounts = await keyring.getFirstPage()
|
||||||
}
|
|
||||||
|
|
||||||
// Merge with existing accounts
|
|
||||||
// and make sure addresses are not repeated
|
|
||||||
const accountsToTrack = [...new Set(oldAccounts.concat(accounts.map(a => a.address.toLowerCase())))]
|
|
||||||
this.accountTracker.syncWithAddresses(accountsToTrack)
|
|
||||||
return accounts
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error('MetamaskController:connectHardware - Unknown device')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge with existing accounts
|
||||||
|
// and make sure addresses are not repeated
|
||||||
|
const accountsToTrack = [...new Set(oldAccounts.concat(accounts.map(a => a.address.toLowerCase())))]
|
||||||
|
this.accountTracker.syncWithAddresses(accountsToTrack)
|
||||||
|
return accounts
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -587,20 +596,8 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<boolean>}
|
||||||
*/
|
*/
|
||||||
async checkHardwareStatus (deviceName) {
|
async checkHardwareStatus (deviceName) {
|
||||||
|
const keyring = await this.getKeyringForDevice(deviceName)
|
||||||
switch (deviceName) {
|
return keyring.isUnlocked()
|
||||||
case 'trezor':
|
|
||||||
const keyringController = this.keyringController
|
|
||||||
const keyring = await keyringController.getKeyringsByType(
|
|
||||||
'Trezor Hardware'
|
|
||||||
)[0]
|
|
||||||
if (!keyring) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return keyring.isUnlocked()
|
|
||||||
default:
|
|
||||||
throw new Error('MetamaskController:checkHardwareStatus - Unknown device')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -610,20 +607,9 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
async forgetDevice (deviceName) {
|
async forgetDevice (deviceName) {
|
||||||
|
|
||||||
switch (deviceName) {
|
const keyring = await this.getKeyringForDevice(deviceName)
|
||||||
case 'trezor':
|
keyring.forgetDevice()
|
||||||
const keyringController = this.keyringController
|
return true
|
||||||
const keyring = await keyringController.getKeyringsByType(
|
|
||||||
'Trezor Hardware'
|
|
||||||
)[0]
|
|
||||||
if (!keyring) {
|
|
||||||
throw new Error('MetamaskController:forgetDevice - Trezor Hardware keyring not found')
|
|
||||||
}
|
|
||||||
keyring.forgetDevice()
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
throw new Error('MetamaskController:forgetDevice - Unknown device')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -631,23 +617,17 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
*
|
*
|
||||||
* @returns {} keyState
|
* @returns {} keyState
|
||||||
*/
|
*/
|
||||||
async unlockTrezorAccount (index) {
|
async unlockHardwareWalletAccount (deviceName, index) {
|
||||||
const keyringController = this.keyringController
|
const keyring = await this.getKeyringForDevice(deviceName)
|
||||||
const keyring = await keyringController.getKeyringsByType(
|
|
||||||
'Trezor Hardware'
|
|
||||||
)[0]
|
|
||||||
if (!keyring) {
|
|
||||||
throw new Error('MetamaskController - No Trezor Hardware Keyring found')
|
|
||||||
}
|
|
||||||
|
|
||||||
keyring.setAccountToUnlock(index)
|
keyring.setAccountToUnlock(index)
|
||||||
const oldAccounts = await keyringController.getAccounts()
|
const oldAccounts = await this.keyringController.getAccounts()
|
||||||
const keyState = await keyringController.addNewAccount(keyring)
|
const keyState = await this.keyringController.addNewAccount(keyring)
|
||||||
const newAccounts = await keyringController.getAccounts()
|
const newAccounts = await this.keyringController.getAccounts()
|
||||||
this.preferencesController.setAddresses(newAccounts)
|
this.preferencesController.setAddresses(newAccounts)
|
||||||
newAccounts.forEach(address => {
|
newAccounts.forEach(address => {
|
||||||
if (!oldAccounts.includes(address)) {
|
if (!oldAccounts.includes(address)) {
|
||||||
this.preferencesController.setAccountLabel(address, `TREZOR #${parseInt(index, 10) + 1}`)
|
this.preferencesController.setAccountLabel(address, `${deviceName.toUpperCase()} #${parseInt(index, 10) + 1}`)
|
||||||
this.preferencesController.setSelectedAddress(address)
|
this.preferencesController.setSelectedAddress(address)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
18
app/vendor/ledger/content-script.js
vendored
Normal file
18
app/vendor/ledger/content-script.js
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
Passing messages from background script to popup
|
||||||
|
*/
|
||||||
|
let port = chrome.runtime.connect({ name: 'ledger' });
|
||||||
|
port.onMessage.addListener(message => {
|
||||||
|
window.postMessage(message, window.location.origin);
|
||||||
|
});
|
||||||
|
port.onDisconnect.addListener(d => {
|
||||||
|
port = null;
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
Passing messages from popup to background script
|
||||||
|
*/
|
||||||
|
window.addEventListener('message', event => {
|
||||||
|
if (port && event.source === window && event.data) {
|
||||||
|
port.postMessage(event.data);
|
||||||
|
}
|
||||||
|
});
|
23
package-lock.json
generated
23
package-lock.json
generated
@ -317,6 +317,29 @@
|
|||||||
"through2": "^2.0.3"
|
"through2": "^2.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@ledgerhq/hw-app-eth": {
|
||||||
|
"version": "4.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ledgerhq/hw-app-eth/-/hw-app-eth-4.21.0.tgz",
|
||||||
|
"integrity": "sha1-LYv75fCbkujWlRrmhQNtnVrqlv8=",
|
||||||
|
"requires": {
|
||||||
|
"@ledgerhq/hw-transport": "^4.21.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ledgerhq/hw-transport": {
|
||||||
|
"version": "4.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-4.21.0.tgz",
|
||||||
|
"integrity": "sha1-UPhc/hFbo/nVv5R1XHAeknF1eU8=",
|
||||||
|
"requires": {
|
||||||
|
"events": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"events": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@material-ui/core": {
|
"@material-ui/core": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-1.0.0.tgz",
|
||||||
|
@ -74,6 +74,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ledgerhq/hw-app-eth": "^4.21.0",
|
||||||
"@material-ui/core": "1.0.0",
|
"@material-ui/core": "1.0.0",
|
||||||
"@zxing/library": "^0.7.0",
|
"@zxing/library": "^0.7.0",
|
||||||
"abi-decoder": "^1.0.9",
|
"abi-decoder": "^1.0.9",
|
||||||
|
@ -91,7 +91,7 @@ var actions = {
|
|||||||
connectHardware,
|
connectHardware,
|
||||||
checkHardwareStatus,
|
checkHardwareStatus,
|
||||||
forgetDevice,
|
forgetDevice,
|
||||||
unlockTrezorAccount,
|
unlockHardwareWalletAccount,
|
||||||
NEW_ACCOUNT_SCREEN: 'NEW_ACCOUNT_SCREEN',
|
NEW_ACCOUNT_SCREEN: 'NEW_ACCOUNT_SCREEN',
|
||||||
navigateToNewAccountScreen,
|
navigateToNewAccountScreen,
|
||||||
resetAccount,
|
resetAccount,
|
||||||
@ -702,12 +702,12 @@ function connectHardware (deviceName, page) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function unlockTrezorAccount (index) {
|
function unlockHardwareWalletAccount (index, deviceName) {
|
||||||
log.debug(`background.unlockTrezorAccount`, index)
|
log.debug(`background.unlockHardwareWalletAccount`, index, deviceName)
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(actions.showLoadingIndication())
|
dispatch(actions.showLoadingIndication())
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
background.unlockTrezorAccount(index, (err, accounts) => {
|
background.unlockHardwareWalletAccount(index, deviceName, (err, accounts) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
log.error(err)
|
log.error(err)
|
||||||
dispatch(actions.displayWarning(err.message))
|
dispatch(actions.displayWarning(err.message))
|
||||||
|
@ -61,7 +61,7 @@ class AccountList extends Component {
|
|||||||
h(
|
h(
|
||||||
'button.hw-list-pagination__button',
|
'button.hw-list-pagination__button',
|
||||||
{
|
{
|
||||||
onClick: () => this.props.getPage(-1),
|
onClick: () => this.props.getPage(-1, this.props.device),
|
||||||
},
|
},
|
||||||
`< ${this.context.t('prev')}`
|
`< ${this.context.t('prev')}`
|
||||||
),
|
),
|
||||||
@ -69,7 +69,7 @@ class AccountList extends Component {
|
|||||||
h(
|
h(
|
||||||
'button.hw-list-pagination__button',
|
'button.hw-list-pagination__button',
|
||||||
{
|
{
|
||||||
onClick: () => this.props.getPage(1),
|
onClick: () => this.props.getPage(1, this.props.device),
|
||||||
},
|
},
|
||||||
`${this.context.t('next')} >`
|
`${this.context.t('next')} >`
|
||||||
),
|
),
|
||||||
@ -95,7 +95,7 @@ class AccountList extends Component {
|
|||||||
h(
|
h(
|
||||||
`button.btn-primary.btn--large.new-account-connect-form__button.unlock ${disabled ? '.btn-primary--disabled' : ''}`,
|
`button.btn-primary.btn--large.new-account-connect-form__button.unlock ${disabled ? '.btn-primary--disabled' : ''}`,
|
||||||
{
|
{
|
||||||
onClick: this.props.onUnlockAccount.bind(this),
|
onClick: this.props.onUnlockAccount.bind(this, this.props.device),
|
||||||
...buttonProps,
|
...buttonProps,
|
||||||
},
|
},
|
||||||
[this.context.t('unlock')]
|
[this.context.t('unlock')]
|
||||||
@ -106,7 +106,7 @@ class AccountList extends Component {
|
|||||||
renderForgetDevice () {
|
renderForgetDevice () {
|
||||||
return h('div.hw-forget-device-container', {}, [
|
return h('div.hw-forget-device-container', {}, [
|
||||||
h('a', {
|
h('a', {
|
||||||
onClick: this.props.onForgetDevice.bind(this),
|
onClick: this.props.onForgetDevice.bind(this, this.props.device),
|
||||||
}, this.context.t('forgetDevice')),
|
}, this.context.t('forgetDevice')),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
@ -125,6 +125,7 @@ class AccountList extends Component {
|
|||||||
|
|
||||||
|
|
||||||
AccountList.propTypes = {
|
AccountList.propTypes = {
|
||||||
|
device: PropTypes.string.isRequired,
|
||||||
accounts: PropTypes.array.isRequired,
|
accounts: PropTypes.array.isRequired,
|
||||||
onAccountChange: PropTypes.func.isRequired,
|
onAccountChange: PropTypes.func.isRequired,
|
||||||
onForgetDevice: PropTypes.func.isRequired,
|
onForgetDevice: PropTypes.func.isRequired,
|
||||||
|
@ -49,11 +49,19 @@ class ConnectScreen extends Component {
|
|||||||
renderConnectToTrezorButton () {
|
renderConnectToTrezorButton () {
|
||||||
return h(
|
return h(
|
||||||
'button.btn-primary.btn--large',
|
'button.btn-primary.btn--large',
|
||||||
{ onClick: this.props.connectToTrezor.bind(this) },
|
{ onClick: this.props.connectToHardwareWallet.bind(this, 'trezor') },
|
||||||
this.props.btnText
|
this.props.btnText
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderConnectToLedgerButton () {
|
||||||
|
return h(
|
||||||
|
'button.btn-primary.btn--large',
|
||||||
|
{ onClick: this.props.connectToHardwareWallet.bind(this, 'ledger') },
|
||||||
|
this.props.btnText.replace('Trezor', 'Ledger')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
scrollToTutorial = (e) => {
|
scrollToTutorial = (e) => {
|
||||||
if (this.referenceNode) this.referenceNode.scrollIntoView({behavior: 'smooth'})
|
if (this.referenceNode) this.referenceNode.scrollIntoView({behavior: 'smooth'})
|
||||||
}
|
}
|
||||||
@ -103,6 +111,7 @@ class ConnectScreen extends Component {
|
|||||||
h('div.hw-connect__footer', {}, [
|
h('div.hw-connect__footer', {}, [
|
||||||
h('h3.hw-connect__footer__title', {}, this.context.t(`readyToConnect`)),
|
h('h3.hw-connect__footer__title', {}, this.context.t(`readyToConnect`)),
|
||||||
this.renderConnectToTrezorButton(),
|
this.renderConnectToTrezorButton(),
|
||||||
|
this.renderConnectToLedgerButton(),
|
||||||
h('p.hw-connect__footer__msg', {}, [
|
h('p.hw-connect__footer__msg', {}, [
|
||||||
this.context.t(`havingTroubleConnecting`),
|
this.context.t(`havingTroubleConnecting`),
|
||||||
h('a.hw-connect__footer__link', {
|
h('a.hw-connect__footer__link', {
|
||||||
@ -120,6 +129,7 @@ class ConnectScreen extends Component {
|
|||||||
this.renderHeader(),
|
this.renderHeader(),
|
||||||
this.renderTrezorAffiliateLink(),
|
this.renderTrezorAffiliateLink(),
|
||||||
this.renderConnectToTrezorButton(),
|
this.renderConnectToTrezorButton(),
|
||||||
|
this.renderConnectToLedgerButton(),
|
||||||
this.renderLearnMore(),
|
this.renderLearnMore(),
|
||||||
this.renderTutorialSteps(),
|
this.renderTutorialSteps(),
|
||||||
this.renderFooter(),
|
this.renderFooter(),
|
||||||
@ -136,7 +146,7 @@ class ConnectScreen extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConnectScreen.propTypes = {
|
ConnectScreen.propTypes = {
|
||||||
connectToTrezor: PropTypes.func.isRequired,
|
connectToHardwareWallet: PropTypes.func.isRequired,
|
||||||
btnText: PropTypes.string.isRequired,
|
btnText: PropTypes.string.isRequired,
|
||||||
browserSupported: PropTypes.bool.isRequired,
|
browserSupported: PropTypes.bool.isRequired,
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ class ConnectHardwareForm extends Component {
|
|||||||
accounts: [],
|
accounts: [],
|
||||||
browserSupported: true,
|
browserSupported: true,
|
||||||
unlocked: false,
|
unlocked: false,
|
||||||
|
device: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,19 +39,22 @@ class ConnectHardwareForm extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async checkIfUnlocked () {
|
async checkIfUnlocked () {
|
||||||
const unlocked = await this.props.checkHardwareStatus('trezor')
|
['trezor', 'ledger'].forEach(async device => {
|
||||||
if (unlocked) {
|
const unlocked = await this.props.checkHardwareStatus(device)
|
||||||
this.setState({unlocked: true})
|
if (unlocked) {
|
||||||
this.getPage(0)
|
this.setState({unlocked: true})
|
||||||
}
|
this.getPage(0, device)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
connectToTrezor = () => {
|
connectToHardwareWallet = (device) => {
|
||||||
|
debugger
|
||||||
if (this.state.accounts.length) {
|
if (this.state.accounts.length) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
this.setState({ btnText: this.context.t('connecting')})
|
this.setState({ btnText: this.context.t('connecting')})
|
||||||
this.getPage(0)
|
this.getPage(0, device)
|
||||||
}
|
}
|
||||||
|
|
||||||
onAccountChange = (account) => {
|
onAccountChange = (account) => {
|
||||||
@ -65,9 +69,9 @@ class ConnectHardwareForm extends Component {
|
|||||||
}, 5000)
|
}, 5000)
|
||||||
}
|
}
|
||||||
|
|
||||||
getPage = (page) => {
|
getPage = (page, device) => {
|
||||||
this.props
|
this.props
|
||||||
.connectHardware('trezor', page)
|
.connectHardware(device, page)
|
||||||
.then(accounts => {
|
.then(accounts => {
|
||||||
if (accounts.length) {
|
if (accounts.length) {
|
||||||
|
|
||||||
@ -77,7 +81,7 @@ class ConnectHardwareForm extends Component {
|
|||||||
this.showTemporaryAlert()
|
this.showTemporaryAlert()
|
||||||
}
|
}
|
||||||
|
|
||||||
const newState = { unlocked: true }
|
const newState = { unlocked: true, device }
|
||||||
// Default to the first account
|
// Default to the first account
|
||||||
if (this.state.selectedAccount === null) {
|
if (this.state.selectedAccount === null) {
|
||||||
accounts.forEach((a, i) => {
|
accounts.forEach((a, i) => {
|
||||||
@ -110,8 +114,8 @@ class ConnectHardwareForm extends Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onForgetDevice = () => {
|
onForgetDevice = (device) => {
|
||||||
this.props.forgetDevice('trezor')
|
this.props.forgetDevice(device)
|
||||||
.then(_ => {
|
.then(_ => {
|
||||||
this.setState({
|
this.setState({
|
||||||
error: null,
|
error: null,
|
||||||
@ -131,7 +135,7 @@ class ConnectHardwareForm extends Component {
|
|||||||
this.setState({ error: this.context.t('accountSelectionRequired') })
|
this.setState({ error: this.context.t('accountSelectionRequired') })
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.unlockTrezorAccount(this.state.selectedAccount)
|
this.props.unlockHardwareWalletAccount(this.state.selectedAccount, this.state.device)
|
||||||
.then(_ => {
|
.then(_ => {
|
||||||
this.props.history.push(DEFAULT_ROUTE)
|
this.props.history.push(DEFAULT_ROUTE)
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
@ -152,13 +156,14 @@ class ConnectHardwareForm extends Component {
|
|||||||
renderContent () {
|
renderContent () {
|
||||||
if (!this.state.accounts.length) {
|
if (!this.state.accounts.length) {
|
||||||
return h(ConnectScreen, {
|
return h(ConnectScreen, {
|
||||||
connectToTrezor: this.connectToTrezor,
|
connectToHardwareWallet: this.connectToHardwareWallet,
|
||||||
btnText: this.state.btnText,
|
btnText: this.state.btnText,
|
||||||
browserSupported: this.state.browserSupported,
|
browserSupported: this.state.browserSupported,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return h(AccountList, {
|
return h(AccountList, {
|
||||||
|
device: this.state.device,
|
||||||
accounts: this.state.accounts,
|
accounts: this.state.accounts,
|
||||||
selectedAccount: this.state.selectedAccount,
|
selectedAccount: this.state.selectedAccount,
|
||||||
onAccountChange: this.onAccountChange,
|
onAccountChange: this.onAccountChange,
|
||||||
@ -188,7 +193,7 @@ ConnectHardwareForm.propTypes = {
|
|||||||
forgetDevice: PropTypes.func,
|
forgetDevice: PropTypes.func,
|
||||||
showAlert: PropTypes.func,
|
showAlert: PropTypes.func,
|
||||||
hideAlert: PropTypes.func,
|
hideAlert: PropTypes.func,
|
||||||
unlockTrezorAccount: PropTypes.func,
|
unlockHardwareWalletAccount: PropTypes.func,
|
||||||
numberOfExistingAccounts: PropTypes.number,
|
numberOfExistingAccounts: PropTypes.number,
|
||||||
history: PropTypes.object,
|
history: PropTypes.object,
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
@ -222,8 +227,8 @@ const mapDispatchToProps = dispatch => {
|
|||||||
forgetDevice: (deviceName) => {
|
forgetDevice: (deviceName) => {
|
||||||
return dispatch(actions.forgetDevice(deviceName))
|
return dispatch(actions.forgetDevice(deviceName))
|
||||||
},
|
},
|
||||||
unlockTrezorAccount: index => {
|
unlockHardwareWalletAccount: (index, deviceName) => {
|
||||||
return dispatch(actions.unlockTrezorAccount(index))
|
return dispatch(actions.unlockHardwareWalletAccount(index, deviceName))
|
||||||
},
|
},
|
||||||
showImportPage: () => dispatch(actions.showImportPage()),
|
showImportPage: () => dispatch(actions.showImportPage()),
|
||||||
showConnectPage: () => dispatch(actions.showConnectPage()),
|
showConnectPage: () => dispatch(actions.showConnectPage()),
|
||||||
|
Loading…
Reference in New Issue
Block a user