Skip to content

Commit 7330e43

Browse files
authored
Merge pull request #440 from blocknative/develop
Release 1.14.0
2 parents e8ea4fc + 06f104e commit 7330e43

File tree

8 files changed

+400
-10
lines changed

8 files changed

+400
-10
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bnc-onboard",
3-
"version": "1.13.2",
3+
"version": "1.14.0",
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",
@@ -55,6 +55,7 @@
5555
"bignumber.js": "^9.0.0",
5656
"bnc-sdk": "^2.1.4",
5757
"bowser": "^2.10.0",
58+
"eth-lattice-keyring": "^0.2.4",
5859
"ethereumjs-tx": "^2.1.2",
5960
"ethereumjs-util": "^7.0.3",
6061
"fortmatic": "^2.2.1",

src/@types/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ declare module 'web3-provider-engine/subproviders/hooked-wallet'
77
declare module 'web3-provider-engine/subproviders/subscriptions'
88
declare module 'web3-provider-engine/subproviders/filters'
99
declare module 'trezor-connect'
10+
declare module 'eth-lattice-keyring'
1011
declare module 'ethereumjs-tx'
1112
declare module 'ethereumjs-util'
1213
declare module 'hdkey'

src/interfaces.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,11 @@ export interface TrezorOptions extends CommonWalletOptions {
189189
rpcUrl: string
190190
}
191191

192+
export interface LatticeOptions extends CommonWalletOptions {
193+
appName: string
194+
rpcUrl: string
195+
}
196+
192197
export interface LedgerOptions extends CommonWalletOptions {
193198
rpcUrl: string
194199
LedgerTransport?: any
@@ -333,6 +338,7 @@ export type WalletInitOptions =
333338
| WalletConnectOptions
334339
| TorusOptions
335340
| TrezorOptions
341+
| LatticeOptions
336342
| AuthereumOptions
337343
| LedgerOptions
338344
| InjectedWithBalanceOptions
@@ -342,6 +348,7 @@ export type AllWalletInitOptions = CommonWalletOptions &
342348
WalletConnectOptions &
343349
TorusOptions &
344350
TrezorOptions &
351+
LatticeOptions &
345352
AuthereumOptions &
346353
LedgerOptions &
347354
WalletLinkOptions &

src/modules/check/derivation-path.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ const derivationPaths: DerivationPaths = {
1010
{ path: `m/44'/60'/0'`, label: 'Ethereum' },
1111
{ path: `m/44'/60'`, label: 'Ethereum Ledger Live' }
1212
],
13-
Trezor: [{ path: `m/44'/60'/0'/0`, label: 'Ethereum' }]
13+
Trezor: [{ path: `m/44'/60'/0'/0`, label: 'Ethereum' }],
14+
Lattice: [{ path: `m/44'/60'/0'/0`, label: 'Ethereum' }]
1415
}
1516

1617
const styles = `

src/modules/select/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ function getModule(name: string): Promise<any> | undefined {
8585
return import('./wallets/status')
8686
case 'trezor':
8787
return import('./wallets/trezor')
88+
case 'lattice':
89+
return import('./wallets/lattice')
8890
case 'ledger':
8991
return import('./wallets/ledger')
9092
case 'walletLink':
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const latticeIcon = `
2+
<svg width="41px" height="41px" viewBox="0 0 41 41" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
3+
<!-- Generated by Pixelmator Pro 1.8 -->
4+
<defs>
5+
<image id="image" width="41px" height="41px" xlink:href="data:image/png;base64,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"/>
6+
</defs>
7+
<use id="image-1" xlink:href="#image" x="0px" y="0px" width="41px" height="41px"/>
8+
</svg>
9+
`
10+
11+
export default latticeIcon

src/modules/select/wallets/lattice.ts

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
import { LatticeOptions, WalletModule, Helpers } from '../../../interfaces'
2+
import latticeIcon from '../wallet-icons/icon-lattice'
3+
4+
function lattice(
5+
options: LatticeOptions & { networkId: number }
6+
): WalletModule {
7+
const { appName, rpcUrl, networkId, preferred, label, iconSrc, svg } = options
8+
9+
return {
10+
name: label || 'Lattice',
11+
svg: svg || latticeIcon,
12+
iconSrc,
13+
wallet: async (helpers: Helpers) => {
14+
const { BigNumber, networkName, resetWalletState } = helpers
15+
16+
const provider = await latticeProvider({
17+
appName,
18+
rpcUrl,
19+
networkId,
20+
BigNumber,
21+
networkName,
22+
resetWalletState
23+
})
24+
25+
return {
26+
provider,
27+
interface: {
28+
name: 'Lattice',
29+
connect: provider.enable,
30+
disconnect: provider.disconnect,
31+
address: {
32+
get: async () => provider.getPrimaryAddress()
33+
},
34+
network: {
35+
get: async () => networkId
36+
},
37+
balance: {
38+
get: async () => {
39+
const address = provider.getPrimaryAddress()
40+
return address && provider.getBalance(address)
41+
}
42+
}
43+
}
44+
}
45+
},
46+
type: 'hardware',
47+
desktop: true,
48+
mobile: true,
49+
osExclusions: ['iOS'],
50+
preferred
51+
}
52+
}
53+
54+
async function latticeProvider(options: {
55+
appName: string
56+
networkId: number
57+
rpcUrl: string
58+
BigNumber: any
59+
networkName: (id: number) => string
60+
resetWalletState: (options?: {
61+
disconnected: boolean
62+
walletName: string
63+
}) => void
64+
}) {
65+
const { default: EthLatticeKeyring } = await import('eth-lattice-keyring')
66+
const EthereumTx = await import('ethereumjs-tx')
67+
const { default: createProvider } = await import('./providerEngine')
68+
69+
const BASE_PATH = "m/44'/60'/0'/0"
70+
71+
const { networkId, appName, rpcUrl, BigNumber, networkName } = options
72+
73+
const params = {
74+
name: appName,
75+
network: networkName(networkId)
76+
}
77+
const Lattice = new EthLatticeKeyring(params)
78+
79+
let dPath = ''
80+
81+
let addressList = Array.from([])
82+
let enabled = false
83+
let customPath = false
84+
85+
const provider = createProvider({
86+
getAccounts: (callback: any) => {
87+
getAccounts()
88+
.then((res: Array<string | undefined>) => callback(null, res))
89+
.catch((err: any) => callback(err, null))
90+
},
91+
signTransaction: (transactionData: any, callback: any) => {
92+
signTransaction(transactionData)
93+
.then((res: string) => callback(null, res))
94+
.catch(err => callback(err, null))
95+
},
96+
processMessage: (messageData: any, callback: any) => {
97+
signMessage(messageData)
98+
.then((res: string) => callback(null, res))
99+
.catch(err => callback(err, null))
100+
},
101+
processPersonalMessage: (messageData: any, callback: any) => {
102+
signMessage(messageData)
103+
.then((res: string) => callback(null, res))
104+
.catch(err => callback(err, null))
105+
},
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+
},
116+
rpcUrl
117+
})
118+
119+
provider.setPath = setPath
120+
provider.dPath = dPath
121+
provider.enable = enable
122+
provider.setPrimaryAccount = setPrimaryAccount
123+
provider.getPrimaryAddress = getPrimaryAddress
124+
provider.getAccounts = getAccounts
125+
provider.getMoreAccounts = getMoreAccounts
126+
provider.getBalance = getBalance
127+
provider.getBalances = getBalances
128+
provider.send = provider.sendAsync
129+
provider.disconnect = disconnect
130+
provider.isCustomPath = isCustomPath
131+
132+
function disconnect() {
133+
dPath = ''
134+
enabled = false
135+
provider.stop()
136+
}
137+
138+
async function setPath(path: string) {
139+
if (path !== BASE_PATH)
140+
throw new Error("Lattice only supports standard path: m/44'/0'/0'/0/x")
141+
customPath = false
142+
dPath = path
143+
return true
144+
}
145+
146+
function isCustomPath() {
147+
return customPath
148+
}
149+
150+
function enable() {
151+
enabled = true
152+
return getAccounts()
153+
}
154+
155+
function addresses() {
156+
return addressList
157+
}
158+
159+
function setPrimaryAccount(address: string) {
160+
return
161+
}
162+
163+
function getPrimaryAddress() {
164+
return enabled ? addresses()[0] : undefined
165+
}
166+
167+
async function getMoreAccounts() {
168+
const m = `Lattice only supports one exported account per wallet. Checking for new wallet.`
169+
console.warn(m)
170+
const accounts = await getAccounts(true)
171+
return accounts && getBalances(accounts)
172+
}
173+
174+
async function getAccounts(getMore?: boolean) {
175+
if (!enabled) {
176+
return []
177+
}
178+
179+
if (addressList.length > 0 && !getMore) {
180+
return addressList
181+
}
182+
183+
try {
184+
addressList = await Lattice.addAccounts()
185+
} catch (error) {
186+
throw error
187+
}
188+
189+
return addressList
190+
}
191+
192+
function getBalances(addresses: Array<string>) {
193+
return Promise.all(
194+
addresses.map(
195+
address =>
196+
new Promise(async resolve => {
197+
const balance = await getBalance(address)
198+
resolve({ address, balance })
199+
})
200+
)
201+
)
202+
}
203+
204+
function getBalance(address: string) {
205+
return new Promise((resolve, reject) => {
206+
provider.sendAsync(
207+
{
208+
jsonrpc: '2.0',
209+
method: 'eth_getBalance',
210+
params: [address, 'latest'],
211+
id: 42
212+
},
213+
(e: any, res: any) => {
214+
e && reject(e)
215+
const result = res && res.result
216+
217+
if (result != null) {
218+
resolve(new BigNumber(result).toString(10))
219+
} else {
220+
resolve(null)
221+
}
222+
}
223+
)
224+
})
225+
}
226+
227+
async function signTransaction(transactionData: any) {
228+
if (addressList.length === 0) {
229+
await enable()
230+
}
231+
232+
const transaction = new EthereumTx.Transaction(transactionData, {
233+
chain: networkName(networkId)
234+
})
235+
236+
try {
237+
const signedTx = await Lattice.signTransaction(
238+
addressList[0],
239+
transaction
240+
)
241+
return `0x${signedTx.serialize().toString('hex')}`
242+
} catch (err) {
243+
throw err
244+
}
245+
}
246+
247+
async function signMessage(message: { data: string }): Promise<string> {
248+
if (addressList.length === 0) {
249+
await enable()
250+
}
251+
252+
try {
253+
const sig = await Lattice.signPersonalMessage(
254+
addressList[0],
255+
message.data
256+
)
257+
return sig
258+
} catch (err) {
259+
throw err
260+
}
261+
}
262+
263+
return provider
264+
}
265+
266+
export default lattice

0 commit comments

Comments
 (0)