Skip to content

Commit 8cbaf88

Browse files
1.29.0-0.4.1: Allow Hardware wallets to add custom network info (#457)
* Add support for EWC/Volta * Upgrade etherumjs-tx to @ethereumjs/tx * Add common object to @ethereumjs/tx config * Add networkName config for hardware wallets * Remove patch-package dep * Remove logs + useless network case * Update yarn.lock & rm instance of ethereumjs-tx * Add validation Co-authored-by: Taylor Dawson <taylorjdawson@gmail.com>
1 parent 940aaa1 commit 8cbaf88

File tree

11 files changed

+192
-44
lines changed

11 files changed

+192
-44
lines changed

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bnc-onboard",
3-
"version": "1.29.0-0.3.1",
3+
"version": "1.29.0-0.4.1",
44
"description": "Onboard users to web3 by allowing them to select a wallet, get that wallet ready to transact and have access to synced wallet state.",
55
"keywords": [
66
"ethereum",
@@ -57,6 +57,8 @@
5757
"@gnosis.pm/safe-apps-provider": "^0.5.0",
5858
"@gnosis.pm/safe-apps-sdk": "^3.0.0",
5959
"@ledgerhq/hw-app-eth": "^5.49.0",
60+
"@ethereumjs/common": "^2.0.0",
61+
"@ethereumjs/tx": "^3.0.0",
6062
"@ledgerhq/hw-transport-u2f": "^5.21.0",
6163
"@ledgerhq/hw-transport-webusb": "5.53.0",
6264
"@portis/web3": "^4.0.0",
@@ -72,7 +74,6 @@
7274
"eth-lattice-keyring": "^0.2.7",
7375
"eth-provider": "^0.6.1",
7476
"eth-sig-util": "^3.0.1",
75-
"ethereumjs-tx": "^2.1.2",
7677
"ethereumjs-util": "^7.0.3",
7778
"fortmatic": "^2.2.1",
7879
"hdkey": "^2.0.1",

rollup.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ export default {
6666
'walletlink',
6767
'regenerator-runtime/runtime',
6868
'trezor-connect',
69-
'ethereumjs-tx',
69+
'@ethereumjs/tx',
70+
'@ethereumjs/common',
7071
'ethereumjs-util',
7172
'eth-lattice-keyring',
7273
'eth-sig-util',

src/@types/index.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ declare module 'web3-provider-engine/subproviders/subscriptions'
88
declare module 'web3-provider-engine/subproviders/filters'
99
declare module 'trezor-connect'
1010
declare module 'eth-lattice-keyring'
11-
declare module 'eth-sig-util'
12-
declare module 'ethereumjs-tx'
11+
declare module '@ethereumjs/tx'
12+
declare module '@ethereumjs/common'
1313
declare module 'ethereumjs-util'
1414
declare module 'hdkey'
1515
declare module '@ledgerhq/hw-app-eth'

src/interfaces.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,20 +196,59 @@ export interface WalletConnectOptions extends CommonWalletOptions {
196196
bridge: string
197197
}
198198

199+
/*
200+
* Types taken from https://github.com/ethereumjs/ethereumjs-vm/blob/eb05651554ec23d2ba7c46af6e5f5a7bc199f217/packages/common/src/types.ts#L15
201+
* since they are not exported
202+
*/
203+
204+
export interface GenesisBlock {
205+
hash: string
206+
timestamp: string | null
207+
gasLimit: number
208+
difficulty: number
209+
nonce: string
210+
extraData: string
211+
stateRoot: string
212+
}
213+
export interface Hardfork {
214+
name: string
215+
block: number | null
216+
}
217+
218+
export interface BootstrapNode {
219+
ip: string
220+
port: number | string
221+
network?: string
222+
chainId?: number
223+
id: string
224+
location: string
225+
comment: string
226+
}
227+
228+
export interface HardwareWalletCustomNetwork {
229+
networkId: number
230+
genesis: GenesisBlock
231+
hardforks: Hardfork[]
232+
bootstrapNodes: BootstrapNode[]
233+
}
234+
199235
export interface TrezorOptions extends CommonWalletOptions {
200236
appUrl: string
201237
email: string
202238
rpcUrl: string
239+
customNetwork?: HardwareWalletCustomNetwork
203240
}
204241

205242
export interface LatticeOptions extends CommonWalletOptions {
206243
appName: string
207244
rpcUrl: string
245+
customNetwork?: HardwareWalletCustomNetwork
208246
}
209247

210248
export interface LedgerOptions extends CommonWalletOptions {
211249
rpcUrl: string
212250
LedgerTransport?: any
251+
customNetwork?: HardwareWalletCustomNetwork
213252
}
214253

215254
//#region torus

src/modules/select/wallets/cobovault.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ async function cobovaultProvider(options: {
6565
walletName: string
6666
}) => void
6767
}) {
68-
const EthereumTx = await import('ethereumjs-tx')
68+
const { Transaction } = await import('@ethereumjs/tx')
6969
const { default: createProvider } = await import('./providerEngine')
7070

7171
const BASE_PATH = "m/44'/60'/0'/0"
@@ -227,7 +227,7 @@ async function cobovaultProvider(options: {
227227
await enable()
228228
}
229229

230-
const transaction = new EthereumTx.Transaction(transactionData, {
230+
const transaction = Transaction.fromTxData(transactionData, {
231231
chain: networkName(networkId)
232232
})
233233

src/modules/select/wallets/hd-wallet.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ export function generateAddresses(
3737

3838
export function isValidPath(path: string) {
3939
const parts = path.split('/')
40-
4140
if (parts[0] !== 'm') {
4241
return false
4342
}
@@ -46,11 +45,11 @@ export function isValidPath(path: string) {
4645
return false
4746
}
4847

49-
if (parts[2] !== "60'" && parts[2] !== "1'") {
48+
if (!["60'", "1'", "73799'", "246'"].includes(parts[2])) {
5049
return false
5150
}
5251

53-
if (parts[3] === undefined) {
52+
if (parts[3] === undefined || parts[3] === "0'") {
5453
return true
5554
}
5655

src/modules/select/wallets/lattice.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
1-
import { LatticeOptions, WalletModule, Helpers } from '../../../interfaces'
1+
import {
2+
LatticeOptions,
3+
WalletModule,
4+
HardwareWalletCustomNetwork,
5+
Helpers
6+
} from '../../../interfaces'
27
import latticeIcon from '../wallet-icons/icon-lattice'
38

49
function lattice(
510
options: LatticeOptions & { networkId: number }
611
): WalletModule {
7-
const { appName, rpcUrl, networkId, preferred, label, iconSrc, svg } = options
12+
const {
13+
appName,
14+
rpcUrl,
15+
networkId,
16+
preferred,
17+
label,
18+
iconSrc,
19+
svg,
20+
customNetwork
21+
} = options
822

923
return {
1024
name: label || 'Lattice',
@@ -19,6 +33,7 @@ function lattice(
1933
networkId,
2034
BigNumber,
2135
networkName,
36+
customNetwork,
2237
resetWalletState
2338
})
2439

@@ -57,18 +72,21 @@ async function latticeProvider(options: {
5772
rpcUrl: string
5873
BigNumber: any
5974
networkName: (id: number) => string
75+
customNetwork?: HardwareWalletCustomNetwork
6076
resetWalletState: (options?: {
6177
disconnected: boolean
6278
walletName: string
6379
}) => void
6480
}) {
6581
const { default: EthLatticeKeyring } = await import('eth-lattice-keyring')
66-
const EthereumTx = await import('ethereumjs-tx')
82+
const { Transaction } = await import('@ethereumjs/tx')
83+
const { default: Common } = await import('@ethereumjs/common')
6784
const { default: createProvider } = await import('./providerEngine')
6885

6986
const BASE_PATH = "m/44'/60'/0'/0"
7087

71-
const { networkId, appName, rpcUrl, BigNumber, networkName } = options
88+
const { networkId, appName, rpcUrl, BigNumber, networkName, customNetwork } =
89+
options
7290

7391
const params = {
7492
name: appName,
@@ -228,11 +246,18 @@ async function latticeProvider(options: {
228246
if (addressList.length === 0) {
229247
await enable()
230248
}
231-
232-
const transaction = new EthereumTx.Transaction(transactionData, {
233-
chain: networkName(networkId)
249+
const common = new Common({
250+
chain: customNetwork || networkName(networkId)
234251
})
235252

253+
const transaction = Transaction.fromTxData(
254+
{
255+
...transactionData,
256+
gasLimit: transactionData.gas ?? transactionData.gasLimit
257+
},
258+
{ common, freeze: false }
259+
)
260+
236261
try {
237262
const signedTx = await Lattice.signTransaction(
238263
addressList[0],

src/modules/select/wallets/ledger.ts

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
1-
import { LedgerOptions, WalletModule, Helpers } from '../../../interfaces'
1+
import {
2+
LedgerOptions,
3+
WalletModule,
4+
HardwareWalletCustomNetwork,
5+
Helpers
6+
} from '../../../interfaces'
7+
28
import ledgerIcon from '../wallet-icons/icon-ledger'
39

410
const LEDGER_LIVE_PATH = `m/44'/60'`
511
const ACCOUNTS_TO_GET = 5
612

713
function ledger(options: LedgerOptions & { networkId: number }): WalletModule {
8-
const { rpcUrl, LedgerTransport, networkId, preferred, label, iconSrc, svg } =
9-
options
14+
const {
15+
rpcUrl,
16+
LedgerTransport,
17+
networkId,
18+
preferred,
19+
label,
20+
iconSrc,
21+
svg,
22+
customNetwork
23+
} = options
1024

1125
return {
1226
name: label || 'Ledger',
@@ -21,7 +35,8 @@ function ledger(options: LedgerOptions & { networkId: number }): WalletModule {
2135
LedgerTransport,
2236
BigNumber,
2337
networkName,
24-
resetWalletState
38+
resetWalletState,
39+
customNetwork
2540
})
2641

2742
return {
@@ -58,6 +73,7 @@ interface LedgerProviderOptions {
5873
rpcUrl: string
5974
LedgerTransport: any
6075
BigNumber: any
76+
customNetwork?: HardwareWalletCustomNetwork
6177
networkName: (id: number) => string
6278
resetWalletState: (options?: {
6379
disconnected: boolean
@@ -70,7 +86,8 @@ async function ledgerProvider(options: LedgerProviderOptions) {
7086
const { generateAddresses, isValidPath } = await import('./hd-wallet')
7187
const { default: Eth } = await import('@ledgerhq/hw-app-eth')
7288

73-
const EthereumTx = await import('ethereumjs-tx')
89+
const { Transaction } = await import('@ethereumjs/tx')
90+
const { default: Common } = await import('@ethereumjs/common')
7491
const ethUtil = await import('ethereumjs-util')
7592
const buffer = await import('buffer')
7693
const { TypedDataUtils } = await import('eth-sig-util')
@@ -98,7 +115,8 @@ async function ledgerProvider(options: LedgerProviderOptions) {
98115
LedgerTransport,
99116
BigNumber,
100117
networkName,
101-
resetWalletState
118+
resetWalletState,
119+
customNetwork
102120
} = options
103121

104122
let dPath = ''
@@ -383,24 +401,36 @@ async function ledgerProvider(options: LedgerProviderOptions) {
383401

384402
async function signTransaction(transactionData: any) {
385403
const path = [...addressToPath.values()][0]
386-
404+
const { BN, toBuffer } = ethUtil
405+
const common = new Common({
406+
chain: customNetwork || networkName(networkId)
407+
})
387408
try {
388-
const transaction = new EthereumTx.Transaction(transactionData, {
389-
chain: networkName(networkId)
390-
})
391-
392-
transaction.raw[6] = buffer.Buffer.from([networkId]) // v
393-
transaction.raw[7] = buffer.Buffer.from([]) // r
394-
transaction.raw[8] = buffer.Buffer.from([]) // s
409+
const transaction = Transaction.fromTxData(
410+
{
411+
...transactionData,
412+
gasLimit: transactionData.gas ?? transactionData.gasLimit
413+
},
414+
{ common, freeze: false }
415+
)
416+
transaction.v = new BN(toBuffer(networkId))
417+
transaction.r = transaction.s = new BN(toBuffer(0))
395418

396419
const ledgerResult = await eth.signTransaction(
397420
path,
398421
transaction.serialize().toString('hex')
399422
)
400-
401-
transaction.v = buffer.Buffer.from(ledgerResult.v, 'hex')
402-
transaction.r = buffer.Buffer.from(ledgerResult.r, 'hex')
403-
transaction.s = buffer.Buffer.from(ledgerResult.s, 'hex')
423+
let v = ledgerResult.v.toString(16)
424+
// EIP155 support. check/recalc signature v value.
425+
const rv = parseInt(v, 16)
426+
let cv = networkId * 2 + 35
427+
if (rv !== cv && (rv & cv) !== rv) {
428+
cv += 1 // add signature v bit.
429+
}
430+
v = cv.toString(16)
431+
transaction.v = new BN(toBuffer(`0x${v}`))
432+
transaction.r = new BN(toBuffer(`0x${ledgerResult.r}`))
433+
transaction.s = new BN(toBuffer(`0x${ledgerResult.s}`))
404434

405435
return `0x${transaction.serialize().toString('hex')}`
406436
} catch (error) {

0 commit comments

Comments
 (0)