Skip to content

Commit 634e39b

Browse files
authored
Merge pull request #593 from blocknative/release/1.29.0
Release 1.29.0
2 parents 96aba9e + 4db3ead commit 634e39b

File tree

17 files changed

+172
-50
lines changed

17 files changed

+172
-50
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bnc-onboard",
3-
"version": "1.28.0",
3+
"version": "1.29.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",
@@ -43,6 +43,7 @@
4343
"eslint": "^6.8.0",
4444
"eslint-config-prettier": "^8.3.0",
4545
"prettier": "^2.0.5",
46+
"prettier-plugin-svelte": "^2.2.0",
4647
"rimraf": "^3.0.0",
4748
"rollup": "^1.27.5",
4849
"rollup-plugin-svelte": "^6.1.1",
@@ -75,7 +76,6 @@
7576
"ethereumjs-util": "^7.0.3",
7677
"fortmatic": "^2.2.1",
7778
"hdkey": "^2.0.1",
78-
"prettier-plugin-svelte": "^2.2.0",
7979
"regenerator-runtime": "^0.13.7",
8080
"trezor-connect": "^8.1.9",
8181
"walletlink": "^2.1.0",

src/components/Modal.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { fade } from 'svelte/transition'
33
import { app } from '../stores'
44
import Branding from '../elements/Branding.svelte'
5-
export let closeModal: () => void
5+
export let closeModal: () => void = () => {}
66
export let closeable: boolean = true
77
88
let closeHovered: boolean

src/elements/Spinner.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
<script>
2-
export let description
1+
<script lang="ts">
2+
export let description: string = ''
33
</script>
44

55
<style>

src/interfaces.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ export interface UserState {
8888
export interface StateAndHelpers extends UserState {
8989
BigNumber: any
9090
walletSelect: WalletSelectFunction
91+
walletCheck: WalletCheck
9192
wallet: Wallet
92-
exit: (completed?: boolean) => void
93+
exit: (completed?: boolean, state?: Partial<AppState>) => void
9394
stateSyncStatus: {
9495
[key: string]:
9596
| null
@@ -398,19 +399,19 @@ export interface WalletSelectFunction {
398399
(autoSelectWallet?: string): Promise<boolean>
399400
}
400401

401-
interface WalletCheck {
402+
export interface WalletCheck {
402403
(): Promise<boolean>
403404
}
404405

405-
interface AccountSelect {
406+
export interface AccountSelect {
406407
(): Promise<boolean>
407408
}
408409

409-
interface Config {
410+
export interface Config {
410411
(options: ConfigOptions): void
411412
}
412413

413-
interface GetState {
414+
export interface GetState {
414415
(): UserState
415416
}
416417

@@ -490,6 +491,7 @@ export interface AppState {
490491
accountSelectInProgress: boolean
491492
walletSelectDisplayedUI: boolean
492493
walletCheckDisplayedUI: boolean
494+
switchingWallets: boolean
493495
displayBranding: boolean
494496
agreement: TermsOfServiceAgreementOptions
495497
}

src/modules/check/network.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ import { networkName } from '../../utilities'
22
import {
33
WalletCheckModal,
44
StateAndHelpers,
5-
WalletCheckCustomOptions
5+
WalletCheckCustomOptions,
6+
AppState
67
} from '../../interfaces'
78
import { networkIcon } from './icons'
89

10+
import { app } from '../../stores'
11+
912
function network(
1013
options: WalletCheckCustomOptions = {}
1114
): (currentState: StateAndHelpers) => Promise<WalletCheckModal | undefined> {
@@ -16,6 +19,7 @@ function network(
1619
network,
1720
appNetworkId,
1821
walletSelect,
22+
walletCheck,
1923
exit,
2024
stateSyncStatus,
2125
stateStore
@@ -49,9 +53,16 @@ function network(
4953
)}</b> for this Dapp. <br><br> <i style="font-size: inherit; font-family: inherit;">*Some wallets may not support changing networks. If you can not change networks in your wallet you may consider switching to a different wallet.</i>`,
5054
eventCode: 'networkFail',
5155
button: button || {
52-
onclick: () => {
53-
exit()
54-
walletSelect()
56+
onclick: async () => {
57+
exit(false, { switchingWallets: true })
58+
const walletSelected = await walletSelect()
59+
const walletReady = walletSelected && (await walletCheck())
60+
61+
app.update((store: AppState) => ({
62+
...store,
63+
switchingWallets: false,
64+
walletCheckCompleted: walletReady
65+
}))
5566
},
5667
text: 'Switch Wallet'
5768
},

src/modules/select/index.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,21 @@ import {
44
AllWalletInitOptions
55
} from '../../interfaces'
66
import { isWalletInit } from '../../validation'
7+
import { getProviderName } from '../../utilities'
78

89
// wallets that qualify for default wallets need to have no
910
// init parameters that are required for full functionality
10-
const desktopDefaultWalletNames = ['metamask', 'torus', 'opera', 'liquality']
11+
const desktopDefaultWalletNames = [
12+
'detectedwallet',
13+
'metamask',
14+
'frame',
15+
'torus',
16+
'opera',
17+
'liquality'
18+
]
1119

1220
const mobileDefaultWalletNames = [
21+
'detectedwallet',
1322
'metamask',
1423
'coinbase',
1524
'trust',
@@ -28,6 +37,9 @@ const mobileDefaultWalletNames = [
2837
'authereum'
2938
]
3039

40+
const injectedWalletDetected = () =>
41+
window.ethereum && getProviderName(window.ethereum) === undefined
42+
3143
function select(
3244
wallets: Array<WalletInitOptions | WalletModule> | undefined,
3345
networkId: number,
@@ -39,10 +51,15 @@ function select(
3951

4052
if (wallets) {
4153
return Promise.all(
42-
wallets.map(wallet => {
43-
if (isWalletInit(wallet)) {
44-
const { walletName, ...initParams } = wallet
45-
54+
wallets
55+
// only include a detected wallet if it's not already one of the provided options
56+
.filter(
57+
wallet =>
58+
isWalletInit(wallet) &&
59+
(wallet.walletName !== 'detectedwallet' || injectedWalletDetected())
60+
)
61+
.map(wallet => {
62+
const { walletName, ...initParams } = wallet as WalletInitOptions
4663
try {
4764
return getModule(walletName).then((m: any) =>
4865
m.default({ ...initParams, networkId, isMobile })
@@ -54,17 +71,22 @@ function select(
5471
throw error
5572
}
5673
}
57-
}
5874

59-
return Promise.resolve(wallet)
60-
})
75+
return Promise.resolve(wallet)
76+
})
6177
)
6278
}
6379

6480
return Promise.all(
65-
defaultWalletNames.map(walletName =>
66-
getModule(walletName).then((m: any) => m.default({ networkId }))
67-
)
81+
defaultWalletNames
82+
// only include a detected wallet if it's not already one of the provided options
83+
.filter(
84+
walletName =>
85+
walletName !== 'detectedwallet' || injectedWalletDetected()
86+
)
87+
.map(walletName =>
88+
getModule(walletName).then((m: any) => m.default({ networkId }))
89+
)
6890
)
6991
}
7092

@@ -146,6 +168,8 @@ function getModule(name: string): Promise<{
146168
return import('./wallets/bitpie')
147169
case 'gnosis':
148170
return import('./wallets/gnosis')
171+
case 'detectedwallet':
172+
return import('./wallets/detectedwallet')
149173
default:
150174
throw new Error(`${name} is not a valid walletName.`)
151175
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2+
<path d="M21 18V19C21 20.1 20.1 21 19 21H5C3.89 21 3 20.1 3 19V5C3 3.9 3.89 3 5 3H19C20.1 3 21 3.9 21 5V6H12C10.89 6 10 6.9 10 8V16C10 17.1 10.89 18 12 18H21ZM12 16H22V8H12V16ZM16 13.5C15.17 13.5 14.5 12.83 14.5 12C14.5 11.17 15.17 10.5 16 10.5C16.83 10.5 17.5 11.17 17.5 12C17.5 12.83 16.83 13.5 16 13.5Z" fill="black"/>
3+
</svg>`
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const injectedIcon = `
2+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
3+
<path fill-rule="evenodd" d="M16.168 2.924L4.51 13.061a.25.25 0 00.164.439h5.45a.75.75 0 01.692 1.041l-2.559 6.066 11.215-9.668a.25.25 0 00-.164-.439H14a.75.75 0 01-.687-1.05l2.855-6.526zm-.452-1.595a1.341 1.341 0 012.109 1.55L15.147 9h4.161c1.623 0 2.372 2.016 1.143 3.075L8.102 22.721a1.149 1.149 0 01-1.81-1.317L8.996 15H4.674c-1.619 0-2.37-2.008-1.148-3.07l12.19-10.6z">
4+
</path>
5+
</svg>
6+
`
7+
8+
export default injectedIcon
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { extensionInstallMessage } from '../content'
2+
import { WalletModule, Helpers, CommonWalletOptions } from '../../../interfaces'
3+
import injectedIcon from '../wallet-icons/icon-detected-wallet'
4+
5+
function injected(options: CommonWalletOptions): WalletModule {
6+
const { preferred, label, svg } = options
7+
8+
const provider =
9+
(window as any).ethereum ||
10+
((window as any).web3 && (window as any).web3.currentProvider)
11+
12+
const name =
13+
label ||
14+
Object.keys(provider)
15+
.find(key => key.startsWith('is') && !key.includes('MetaMask'))
16+
?.split('is')[1] ||
17+
'Detected Wallet'
18+
19+
return {
20+
name,
21+
svg: svg || injectedIcon,
22+
wallet: async (helpers: Helpers) => {
23+
const {
24+
getProviderName,
25+
createModernProviderInterface,
26+
createLegacyProviderInterface
27+
} = helpers
28+
29+
return {
30+
provider,
31+
interface:
32+
provider && getProviderName(provider) === undefined
33+
? typeof provider.enable === 'function'
34+
? createModernProviderInterface(provider)
35+
: createLegacyProviderInterface(provider)
36+
: null
37+
}
38+
},
39+
type: 'injected',
40+
installMessage: extensionInstallMessage,
41+
desktop: true,
42+
mobile: true,
43+
preferred
44+
}
45+
}
46+
47+
export default injected

src/modules/select/wallets/frame.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ import { WalletModule, Helpers, CommonWalletOptions } from '../../../interfaces'
44
import frameIcon from '../wallet-icons/icon-frame.png'
55
import frameIcon2x from '../wallet-icons/icon-frame@2x.png'
66

7+
async function getProvider() {
8+
const injected = window.ethereum
9+
10+
if (injected && (injected as any).isFrame) {
11+
return injected
12+
}
13+
14+
const { default: ethProvider } = await import('eth-provider')
15+
return ethProvider('frame')
16+
}
17+
718
function frame(options: CommonWalletOptions): WalletModule {
819
const { preferred, label, iconSrc, svg } = options
920

@@ -15,8 +26,7 @@ function frame(options: CommonWalletOptions): WalletModule {
1526
wallet: async (helpers: Helpers) => {
1627
const { createModernProviderInterface } = helpers
1728

18-
const { default: ethProvider } = await import('eth-provider')
19-
const provider = ethProvider('frame')
29+
const provider = await getProvider()
2030

2131
return {
2232
provider,

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,12 @@ export function isValidPath(path: string) {
5454
return true
5555
}
5656

57-
const accountFieldDigit = Number(parts[3][0])
57+
const accountFieldNumber = Number(parts[3].slice(0, -1))
5858

5959
if (
60-
isNaN(accountFieldDigit) ||
61-
accountFieldDigit < 0 ||
62-
parts[3][1] !== "'"
60+
isNaN(accountFieldNumber) ||
61+
accountFieldNumber < 0 ||
62+
parts[3].slice(-1) !== "'"
6363
) {
6464
return false
6565
}
@@ -68,19 +68,19 @@ export function isValidPath(path: string) {
6868
return true
6969
}
7070

71-
const changeFieldDigit = Number(parts[4][0])
71+
const changeFieldNumber = Number(parts[4])
7272

73-
if (isNaN(changeFieldDigit) || changeFieldDigit < 0) {
73+
if (isNaN(changeFieldNumber) || changeFieldNumber < 0) {
7474
return false
7575
}
7676

7777
if (parts[5] === undefined) {
7878
return true
7979
}
8080

81-
const addressFieldDigit = Number(parts[5][0])
81+
const addressFieldNumber = Number(parts[5])
8282

83-
if (isNaN(addressFieldDigit) || addressFieldDigit < 0) {
83+
if (isNaN(addressFieldNumber) || addressFieldNumber < 0) {
8484
return false
8585
}
8686

src/onboard.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ function init(initialization: Initialization): API {
121121
target: document.body,
122122
props: {
123123
walletSelectModule: initializedModules.walletSelect,
124-
walletSelect
124+
walletSelect,
125+
walletCheck
125126
}
126127
})
127128

@@ -206,9 +207,11 @@ function init(initialization: Initialization): API {
206207
const {
207208
walletCheckInProgress,
208209
walletCheckCompleted,
209-
walletCheckDisplayedUI
210+
walletCheckDisplayedUI,
211+
switchingWallets
210212
} = store
211-
if (walletCheckInProgress === false) {
213+
214+
if (!switchingWallets && walletCheckInProgress === false) {
212215
appUnsubscribe()
213216
walletCheckDisplayedUI
214217
? setTimeout(() => {

src/stores.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const app: WritableStore = writable({
2828
walletSelectCompleted: false,
2929
walletCheckInProgress: false,
3030
walletCheckCompleted: false,
31+
switchingWallets: false,
3132
accountSelectInProgress: false,
3233
autoSelectWallet: '',
3334
checkModules: [],

0 commit comments

Comments
 (0)