1+ /* eslint-disable prefer-template */
12import TransportHID from '@ledgerhq/hw-transport-node-hid' ;
23import Eth from '@ledgerhq/hw-app-eth' ;
34import { ethers } from 'ethers' ;
45import Web3 from 'web3' ;
6+ import { TypedDataUtils } from 'eth-sig-util' ;
57
68export class LedgerEthSigner {
7- public app : any ;
9+ public app : Eth | undefined ;
10+
811 public transport : TransportHID | null ;
12+
913 constructor ( ) {
1014 this . transport = null ;
1115 }
@@ -22,15 +26,15 @@ export class LedgerEthSigner {
2226 if ( this . transport != null ) {
2327 this . transport . close ( ) ;
2428 this . transport = null ;
25- this . app = null ;
29+ this . app = undefined ;
2630 }
2731 }
2832
2933 async getAddress ( index : number = 0 , display : boolean ) : Promise < string > {
3034 try {
3135 const path : string = `44'/60'/0'/0/${ index } ` ;
3236 await this . createTransport ( ) ;
33- const retAddress = await this . app . getAddress ( path , display , false ) ;
37+ const retAddress = await this . app ! . getAddress ( path , display , false ) ;
3438 return retAddress . address ;
3539 } finally {
3640 await this . closeTransport ( ) ;
@@ -81,7 +85,7 @@ export class LedgerEthSigner {
8185 } ;
8286
8387 const unsignedTx = ethers . utils . serializeTransaction ( baseTx ) . substring ( 2 ) ;
84- const sig = await this . app . signTransaction ( path , unsignedTx ) ;
88+ const sig = await this . app ! . signTransaction ( path , unsignedTx ) ;
8589 // to prevent possible padding issue
8690 const sigR = LedgerEthSigner . padZeroString ( sig . r , 32 ) ;
8791 const sigS = LedgerEthSigner . padZeroString ( sig . s , 32 ) ;
@@ -138,7 +142,7 @@ export class LedgerEthSigner {
138142 await this . createTransport ( ) ;
139143 const path : string = `44'/60'/0'/0/${ index } ` ;
140144 const web3 = new Web3 ( url ) ;
141- const from_addr = ( await this . app . getAddress ( path ) ) . address ;
145+ const from_addr = ( await this . app ! . getAddress ( path ) ) . address ;
142146 const nonce = await web3 . eth . getTransactionCount ( from_addr ) ;
143147 const signedTx = await this . doSignTx (
144148 path ,
@@ -157,4 +161,48 @@ export class LedgerEthSigner {
157161 await this . closeTransport ( ) ;
158162 }
159163 }
164+
165+ async signPersonalMessage ( msg : string , index = 0 ) {
166+ try {
167+ await this . createTransport ( ) ;
168+ const path : string = `44'/60'/0'/0/${ index } ` ;
169+ const sig = await this . app ! . signPersonalMessage ( path , Buffer . from ( msg ) . toString ( 'hex' ) ) ;
170+ return LedgerEthSigner . getHexlifySignature ( sig ) ;
171+ } finally {
172+ await this . closeTransport ( ) ;
173+ }
174+ }
175+
176+ static getHexlifySignature ( sig : { v : number ; r : string ; s : string } ) {
177+ const v = sig . v - 27 ;
178+ let vStr = v . toString ( 16 ) ;
179+ if ( vStr . length < 2 ) {
180+ vStr = '0' + v ;
181+ }
182+
183+ return '0x' + sig . r + sig . s + vStr ;
184+ }
185+
186+ async signTypedDataV4 ( typedData : any , index = 0 ) {
187+ try {
188+ await this . createTransport ( ) ;
189+ const path : string = `44'/60'/0'/0/${ index } ` ;
190+
191+ const data = JSON . parse ( typedData ) ;
192+
193+ const domainSeparator = TypedDataUtils . hashStruct ( 'EIP712Domain' , data . domain , data . types ) ;
194+
195+ const hashedMessage = TypedDataUtils . hashStruct ( data . primaryType , data . message , data . types ) ;
196+
197+ const sig = await this . app ! . signEIP712HashedMessage (
198+ path ,
199+ ethers . utils . hexlify ( domainSeparator ) ,
200+ ethers . utils . hexlify ( hashedMessage ) ,
201+ ) ;
202+
203+ return LedgerEthSigner . getHexlifySignature ( sig ) ;
204+ } finally {
205+ await this . closeTransport ( ) ;
206+ }
207+ }
160208}
0 commit comments