Skip to content

Commit 31ddf0b

Browse files
authored
Merge pull request #424 from blocknative/enhancement/ledger-transport
Enhancement: Ledger Transport Closes #415
2 parents 17291ae + 8325468 commit 31ddf0b

File tree

9 files changed

+131
-28
lines changed

9 files changed

+131
-28
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"dependencies": {
4848
"@ledgerhq/hw-app-eth": "^5.21.0",
4949
"@ledgerhq/hw-transport-u2f": "^5.21.0",
50+
"@ledgerhq/hw-transport-webusb": "^5.22.0",
5051
"@portis/web3": "^2.0.0-beta.57",
5152
"@toruslabs/torus-embed": "^1.8.2",
5253
"@unilogin/provider": "^0.6.1",

rollup.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export default {
7272
'ethereumjs-util',
7373
'hdkey',
7474
'@ledgerhq/hw-transport-u2f',
75+
'@ledgerhq/hw-transport-webusb',
7576
'@ledgerhq/hw-app-eth',
7677
'util',
7778
'assert',

src/@types/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ declare module 'ethereumjs-util'
1212
declare module 'hdkey'
1313
declare module '@ledgerhq/hw-app-eth'
1414
declare module '@ledgerhq/hw-transport-u2f'
15+
declare module '@ledgerhq/hw-transport-webusb'
1516

1617
declare module '*.png'
1718
declare module '*.svg'

src/interfaces.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ export interface Helpers {
135135
disconnected: boolean
136136
walletName: string
137137
}) => void
138+
browser: Browser
139+
os: OS
138140
}
139141

140142
export interface WalletInterface {
@@ -429,12 +431,24 @@ export interface BalanceStore {
429431
get: () => any
430432
}
431433

434+
export type Browser = {
435+
name: string
436+
version: string
437+
}
438+
439+
export type OS = {
440+
name: string
441+
version: string
442+
versionName: string
443+
}
444+
432445
export interface AppState {
433446
dappId: string
434447
networkId: number
435448
version: string
436449
mobileDevice: boolean
437-
os: string
450+
os: OS
451+
browser: Browser
438452
darkMode: boolean
439453
autoSelectWallet: string
440454
walletSelectInProgress: boolean

src/modules/select/wallets/ledger.ts

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { LedgerOptions, WalletModule, Helpers } from '../../../interfaces'
1+
import {
2+
LedgerOptions,
3+
WalletModule,
4+
Helpers,
5+
Browser,
6+
OS
7+
} from '../../../interfaces'
28

39
import ledgerIcon from '../wallet-icons/icon-ledger'
410

@@ -21,15 +27,17 @@ function ledger(options: LedgerOptions & { networkId: number }): WalletModule {
2127
svg: svg || ledgerIcon,
2228
iconSrc,
2329
wallet: async (helpers: Helpers) => {
24-
const { BigNumber, networkName, resetWalletState } = helpers
30+
const { BigNumber, networkName, resetWalletState, browser, os } = helpers
2531

2632
const provider = await ledgerProvider({
2733
rpcUrl,
2834
networkId,
29-
LedgerTransport,
35+
CustomLedgerTransport: LedgerTransport,
3036
BigNumber,
3137
networkName,
32-
resetWalletState
38+
resetWalletState,
39+
browser,
40+
os
3341
})
3442

3543
return {
@@ -64,17 +72,18 @@ function ledger(options: LedgerOptions & { networkId: number }): WalletModule {
6472
async function ledgerProvider(options: {
6573
networkId: number
6674
rpcUrl: string
67-
LedgerTransport: any
75+
CustomLedgerTransport: any
6876
BigNumber: any
6977
networkName: (id: number) => string
7078
resetWalletState: (options?: {
7179
disconnected: boolean
7280
walletName: string
7381
}) => void
82+
browser: Browser
83+
os: OS
7484
}) {
7585
const { default: createProvider } = await import('./providerEngine')
7686
const { generateAddresses, isValidPath } = await import('./hd-wallet')
77-
const { default: TransportU2F } = await import('@ledgerhq/hw-transport-u2f')
7887
const { default: Eth } = await import('@ledgerhq/hw-app-eth')
7988

8089
const EthereumTx = await import('ethereumjs-tx')
@@ -84,10 +93,12 @@ async function ledgerProvider(options: {
8493
const {
8594
networkId,
8695
rpcUrl,
87-
LedgerTransport,
96+
CustomLedgerTransport,
8897
BigNumber,
8998
networkName,
90-
resetWalletState
99+
resetWalletState,
100+
browser,
101+
os
91102
} = options
92103

93104
let dPath = ''
@@ -147,10 +158,14 @@ async function ledgerProvider(options: {
147158
provider.isCustomPath = isCustomPath
148159

149160
let transport: any
161+
let transportSubscription: any
150162
let eth: any
151163

152164
function disconnect() {
153165
transport && transport.close()
166+
transportSubscription &&
167+
transportSubscription.unsubscribe &&
168+
transportSubscription.unsubscribe()
154169
provider.stop()
155170
resetWalletState({ disconnected: true, walletName: 'Ledger' })
156171
}
@@ -185,27 +200,54 @@ async function ledgerProvider(options: {
185200

186201
async function createTransport() {
187202
try {
188-
transport = LedgerTransport
189-
? await LedgerTransport.create()
190-
: await TransportU2F.create()
191-
192-
eth = new Eth(transport)
193-
194203
const observer = {
195204
next: (event: any) => {
196205
if (event.type === 'remove') {
197206
disconnect()
198207
}
199208
},
200-
error: () => {},
209+
error: (error: any) => {
210+
throw new Error(error)
211+
},
201212
complete: () => {}
202213
}
203214

204-
LedgerTransport
205-
? LedgerTransport.listen(observer)
206-
: TransportU2F.listen(observer)
215+
if (CustomLedgerTransport) {
216+
transport = await CustomLedgerTransport.create()
217+
transportSubscription = CustomLedgerTransport.listen(observer)
218+
} else {
219+
if (
220+
os.name === 'Windows' &&
221+
parseInt(os.versionName) >= 11 &&
222+
(browser.name === 'Internet Explorer' || browser.name === 'Firefox')
223+
) {
224+
throw new Error(
225+
`OS: ${os.name} ${os.versionName} and Browser: ${browser.name} are not compatible with Ledger wallets, please switch to Chrome browser to continue.`
226+
)
227+
} else if (
228+
(os.name === 'macOS' || os.name === 'Linux') &&
229+
(browser.name === 'Firefox' || browser.name === 'Safari')
230+
) {
231+
const { default: TransportU2F } = await import(
232+
'@ledgerhq/hw-transport-u2f'
233+
)
234+
235+
transport = await TransportU2F.create()
236+
} else {
237+
const { default: TransportWebUsb } = await import(
238+
'@ledgerhq/hw-transport-webusb'
239+
)
240+
241+
transport = await TransportWebUsb.create()
242+
transportSubscription = TransportWebUsb.listen(observer)
243+
}
244+
}
245+
246+
eth = new Eth(transport)
207247
} catch (error) {
208-
throw new Error('Error connecting to Ledger wallet')
248+
throw new Error(
249+
'An error occurred when trying to connect to your Ledger wallet'
250+
)
209251
}
210252
}
211253

src/onboard.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ function init(initialization: Initialization): API {
5252
hideBranding
5353
} = initialization
5454

55-
const { os, isMobile } = getDeviceInfo()
55+
const { os, browser, isMobile } = getDeviceInfo()
5656

5757
const initializedModules = initializeModules(
5858
networkId,
@@ -83,6 +83,7 @@ function init(initialization: Initialization): API {
8383
version,
8484
mobileDevice: isMobile,
8585
os,
86+
browser,
8687
darkMode,
8788
displayBranding,
8889
checkModules: initializedModules.walletCheck

src/utilities.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,13 +226,15 @@ export function getProviderName(provider: any): string | undefined {
226226
}
227227

228228
export function getDeviceInfo() {
229-
const browser = bowser.getParser(window.navigator.userAgent)
230-
const { name } = browser.getOS()
231-
const { type } = browser.getPlatform()
229+
const parsed = bowser.getParser(window.navigator.userAgent)
230+
const os = parsed.getOS()
231+
const browser = parsed.getBrowser()
232+
const { type } = parsed.getPlatform()
232233

233234
return {
234235
isMobile: type ? type !== 'desktop' : window.innerWidth < 600,
235-
os: name
236+
os,
237+
browser
236238
}
237239
}
238240

src/views/WalletSelect.svelte

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
.filter(wallet => wallet[mobileDevice ? 'mobile' : 'desktop'])
8585
.filter(wallet => {
8686
const { osExclusions = [] } = wallet
87-
return !osExclusions.includes(os)
87+
return !osExclusions.includes(os.name)
8888
})
8989
9090
if (deviceWallets.find(wallet => wallet.preferred)) {
@@ -127,6 +127,7 @@
127127
autoSelected?: boolean
128128
) {
129129
const currentWalletInterface = get(walletInterface)
130+
const { browser, os } = get(app)
130131
131132
if (currentWalletInterface && currentWalletInterface.name === module.name) {
132133
finish({ completed: true })
@@ -148,7 +149,9 @@
148149
getAddress,
149150
getBalance,
150151
resetWalletState,
151-
networkName
152+
networkName,
153+
browser,
154+
os
152155
})
153156
154157
loadingWallet = undefined

yarn.lock

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1004,11 +1004,25 @@
10041004
"@ledgerhq/logs" "^5.21.0"
10051005
rxjs "^6.6.0"
10061006

1007+
"@ledgerhq/devices@^5.22.0":
1008+
version "5.22.0"
1009+
resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-5.22.0.tgz#18595f3545b57cf60e50d6e9d83095dda21f575f"
1010+
integrity sha512-oJxhee/zlHmIx66zvQQTSpIsHOiiLjALemTX9oUtB4xQwFvoiptPnBCeTDTM9teode7wzk7oE9qdUAZuat+nCg==
1011+
dependencies:
1012+
"@ledgerhq/errors" "^5.22.0"
1013+
"@ledgerhq/logs" "^5.22.0"
1014+
rxjs "^6.6.2"
1015+
10071016
"@ledgerhq/errors@^5.21.0":
10081017
version "5.21.0"
10091018
resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-5.21.0.tgz#2a7bdea62fe7e0bd9ccc3b786d2c179f8f65bc02"
10101019
integrity sha512-sGfXoaVGfzrhnexu2TEdgL2FAjM7PUeobWdDBx3DJKE+ARje1y+i5+qg7gyvQL+9k4FV7mW2xMOcnUI3T2Zw0Q==
10111020

1021+
"@ledgerhq/errors@^5.22.0":
1022+
version "5.22.0"
1023+
resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-5.22.0.tgz#7327fc152d4896ddc26aada0943065db21c14880"
1024+
integrity sha512-XDT0meBn39+q+JWzUFXmiFbVYLTy+uHRFMb9napcxyZ0Q/MdKkle9/vkgtvRHjPIkGobklXpyefsgH3BZQHukA==
1025+
10121026
"@ledgerhq/hw-app-eth@^5.21.0":
10131027
version "5.21.0"
10141028
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-eth/-/hw-app-eth-5.21.0.tgz#a6857df45cddf29b5e7623237171d7ffba42a44c"
@@ -1029,6 +1043,16 @@
10291043
"@ledgerhq/logs" "^5.21.0"
10301044
u2f-api "0.2.7"
10311045

1046+
"@ledgerhq/hw-transport-webusb@^5.22.0":
1047+
version "5.22.0"
1048+
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-webusb/-/hw-transport-webusb-5.22.0.tgz#f433b4ad8175e1b47b091766b85071c35175a27d"
1049+
integrity sha512-fPj9x+Ce48g1t7vv2RvT29KonDMUPhLMPGcsX7Kr+IRsheBnaJUhgUVzKXHevaNF1xWhkJEW/Sd8Wo5wyK1pOw==
1050+
dependencies:
1051+
"@ledgerhq/devices" "^5.22.0"
1052+
"@ledgerhq/errors" "^5.22.0"
1053+
"@ledgerhq/hw-transport" "^5.22.0"
1054+
"@ledgerhq/logs" "^5.22.0"
1055+
10321056
"@ledgerhq/hw-transport@^5.21.0":
10331057
version "5.21.0"
10341058
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-5.21.0.tgz#c94d13397a26e0755824e05613e2257a3d2b450b"
@@ -1038,11 +1062,25 @@
10381062
"@ledgerhq/errors" "^5.21.0"
10391063
events "^3.2.0"
10401064

1065+
"@ledgerhq/hw-transport@^5.22.0":
1066+
version "5.22.0"
1067+
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-5.22.0.tgz#d627948b43005ec9e7dfe85adf9aa01e130de280"
1068+
integrity sha512-MFfkVGYMYnr6fI4XGnJQNLd36JIrRpvd5WBmVSDhCO3UKUER2fJ9koVBGc97o7yXtE5IAlJKF+nR9HZJIa0lRQ==
1069+
dependencies:
1070+
"@ledgerhq/devices" "^5.22.0"
1071+
"@ledgerhq/errors" "^5.22.0"
1072+
events "^3.2.0"
1073+
10411074
"@ledgerhq/logs@^5.21.0":
10421075
version "5.21.0"
10431076
resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-5.21.0.tgz#19629222e44b4d312e232c2dfbe0d067ecc12830"
10441077
integrity sha512-eyPXrKfQ+HSLcITB5MdSWhXlImE2qKWTLT2u6l+a9wiCZl5yimSqn0uC5evxaP0McKOW0wSntgfj+gOoKv+Paw==
10451078

1079+
"@ledgerhq/logs@^5.22.0":
1080+
version "5.22.0"
1081+
resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-5.22.0.tgz#a54d6b5b391cdb4c2eacc9500feb04b90475c361"
1082+
integrity sha512-jV4mJxD1aieORm+sK9bYakQd9GMLd7KAxgt2IaxhrTU+QD5Ne47mxQOTys9p7f5w25ujs3R+Px2t3KiMRASHtg==
1083+
10461084
"@portis/eth-json-rpc-middleware@^4.1.2":
10471085
version "4.1.2"
10481086
resolved "https://registry.yarnpkg.com/@portis/eth-json-rpc-middleware/-/eth-json-rpc-middleware-4.1.2.tgz#391e392da03dea348c8111a8111ce4550aa24a02"
@@ -5990,7 +6028,7 @@ rustbn.js@~0.2.0:
59906028
resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca"
59916029
integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==
59926030

5993-
rxjs@^6.5.4, rxjs@^6.6.0:
6031+
rxjs@^6.5.4, rxjs@^6.6.0, rxjs@^6.6.2:
59946032
version "6.6.2"
59956033
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2"
59966034
integrity sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==

0 commit comments

Comments
 (0)