Skip to content

Commit 1ee4833

Browse files
committed
Add sign message capability to hardware wallets
1 parent 054d50a commit 1ee4833

File tree

3 files changed

+87
-8
lines changed

3 files changed

+87
-8
lines changed

src/modules/select/wallets/ledger.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { generateAddresses, isValidPath } from './hd-wallet'
1212
import TransportU2F from '@ledgerhq/hw-transport-u2f'
1313
import Eth from '@ledgerhq/hw-app-eth'
1414
import * as EthereumTx from 'ethereumjs-tx'
15+
import * as ethUtil from 'ethereumjs-util'
1516

1617
import buffer from 'buffer'
1718

@@ -102,6 +103,16 @@ async function ledgerProvider(options: {
102103
.then((res: string) => callback(null, res))
103104
.catch(err => callback(err, null))
104105
},
106+
signMessage: (messageData: any, callback: any) => {
107+
signMessage(messageData)
108+
.then((res: string) => callback(null, res))
109+
.catch(err => callback(err, null))
110+
},
111+
signPersonalMessage: (messageData: any, callback: any) => {
112+
signMessage(messageData)
113+
.then((res: string) => callback(null, res))
114+
.catch(err => callback(err, null))
115+
},
105116
rpcUrl
106117
})
107118

@@ -336,14 +347,25 @@ async function ledgerProvider(options: {
336347
}
337348
}
338349

339-
return provider
340-
}
350+
async function signMessage(message: { data: string }): Promise<string> {
351+
if (addressToPath.size === 0) {
352+
await enable()
353+
}
354+
355+
const path = [...addressToPath.values()][0]
341356

342-
function networkIdToDerivationPath(networkId: number) {
343-
switch (networkId) {
344-
default:
345-
return `m/44'/60'`
357+
return eth
358+
.signPersonalMessage(path, ethUtil.stripHexPrefix(message.data))
359+
.then((result: any) => {
360+
let v = (result['v'] - 27).toString(16)
361+
if (v.length < 2) {
362+
v = '0' + v
363+
}
364+
return `0x${result['r']}${result['s']}${v}`
365+
})
346366
}
367+
368+
return provider
347369
}
348370

349371
export default ledger

src/modules/select/wallets/providerEngine.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,20 @@ import SubscriptionSubprovider from 'web3-provider-engine/subproviders/subscript
55
import FilterSubprovider from 'web3-provider-engine/subproviders/filters'
66

77
function createProvider(config: any) {
8-
const { getAccounts, signTransaction, rpcUrl } = config
8+
const {
9+
getAccounts,
10+
signTransaction,
11+
rpcUrl,
12+
signMessage,
13+
signPersonalMessage
14+
} = config
915

10-
const idMgmt = new HookedWalletSubprovider({ getAccounts, signTransaction })
16+
const idMgmt = new HookedWalletSubprovider({
17+
getAccounts,
18+
signTransaction,
19+
signMessage,
20+
signPersonalMessage
21+
})
1122

1223
const rpcSubProvider = new RpcSource({
1324
rpcUrl: rpcUrl.includes('http') ? rpcUrl : `https://${rpcUrl}`

src/modules/select/wallets/trezor.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { generateAddresses, isValidPath } from './hd-wallet'
1111

1212
import * as TrezorConnectLibrary from 'trezor-connect'
1313
import * as EthereumTx from 'ethereumjs-tx'
14+
import * as ethUtil from 'ethereumjs-util'
1415

1516
const { default: TrezorConnect, DEVICE_EVENT, DEVICE } = TrezorConnectLibrary
1617

@@ -115,6 +116,16 @@ async function trezorProvider(options: {
115116
.then((res: string) => callback(null, res))
116117
.catch(err => callback(err, null))
117118
},
119+
signMessage: (messageData: any, callback: any) => {
120+
signMessage(messageData)
121+
.then((res: string) => callback(null, res))
122+
.catch(err => callback(err, null))
123+
},
124+
signPersonalMessage: (messageData: any, callback: any) => {
125+
signMessage(messageData)
126+
.then((res: string) => callback(null, res))
127+
.catch(err => callback(err, null))
128+
},
118129
rpcUrl
119130
})
120131

@@ -332,6 +343,10 @@ async function trezorProvider(options: {
332343
}
333344

334345
async function signTransaction(transactionData: any) {
346+
if (addressToPath.size === 0) {
347+
await enable()
348+
}
349+
335350
const path = [...addressToPath.values()][0]
336351

337352
const transaction = new EthereumTx.Transaction(transactionData, {
@@ -352,6 +367,37 @@ async function trezorProvider(options: {
352367
return `0x${transaction.serialize().toString('hex')}`
353368
}
354369

370+
async function signMessage(message: { data: string }): Promise<string> {
371+
if (addressToPath.size === 0) {
372+
await enable()
373+
}
374+
375+
const [address, path] = [...addressToPath.entries()][0]
376+
377+
return new Promise((resolve, reject) => {
378+
TrezorConnect.ethereumSignMessage({
379+
path,
380+
message: ethUtil.stripHexPrefix(message.data),
381+
hex: true
382+
}).then((response: any) => {
383+
if (response.success) {
384+
if (response.payload.address !== ethUtil.toChecksumAddress(address)) {
385+
reject(new Error('signature doesnt match the right address'))
386+
}
387+
const signature = `0x${response.payload.signature}`
388+
resolve(signature)
389+
} else {
390+
reject(
391+
new Error(
392+
(response.payload && response.payload.error) ||
393+
'There was an error signing a message'
394+
)
395+
)
396+
}
397+
})
398+
})
399+
}
400+
355401
return provider
356402
}
357403

0 commit comments

Comments
 (0)