This repository has been archived by the owner on Jun 24, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 55
/
web3.ts
164 lines (141 loc) · 5.25 KB
/
web3.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import { IS_IN_IFRAME } from 'constants/misc'
import { useWeb3React } from '@web3-react/core'
import { AbstractConnector } from '@web3-react/abstract-connector'
import { useEffect, useState, useCallback } from 'react'
import { injected, gnosisSafe, walletconnect, getProviderType, WalletProvider, fortmatic, walletlink } from 'connectors'
import { isMobile } from 'utils/userAgent'
import { STORAGE_KEY_LAST_PROVIDER, WAITING_TIME_RECONNECT_LAST_PROVIDER } from 'constants/index'
// exports from the original file
export { useInactiveListener, useActiveWeb3React } from '@src/hooks/web3'
enum DefaultProvidersInjected {
METAMASK = WalletProvider.INJECTED,
COINBASE_WALLET = WalletProvider.WALLET_LINK,
}
export function useEagerConnect() {
const { activate, active, connector } = useWeb3React()
const [tried, setTried] = useState(false)
// gnosisSafe.isSafeApp() races a timeout against postMessage, so it delays pageload if we are not in a safe app;
// if we are not embedded in an iframe, it is not worth checking
const [triedSafe, setTriedSafe] = useState(!IS_IN_IFRAME)
// handle setting/removing wallet provider in local storage
const handleBeforeUnload = useCallback(() => {
const walletType = getProviderType(connector)
if (!walletType || !active) {
localStorage.removeItem(STORAGE_KEY_LAST_PROVIDER)
} else {
localStorage.setItem(STORAGE_KEY_LAST_PROVIDER, walletType)
}
}, [connector, active])
const connectInjected = useCallback(
(providerName = DefaultProvidersInjected.METAMASK) => {
// check if the our application is authorized/connected with Metamask
injected.isAuthorized().then((isAuthorized) => {
if (isAuthorized) {
setDefaultInjected(providerName)
activate(injected, undefined, true).catch(() => {
setTried(true)
})
} else {
if (isMobile && window.ethereum) {
setDefaultInjected(providerName)
activate(injected, undefined, true).catch(() => {
setTried(true)
})
} else {
setTried(true)
}
}
})
},
[activate, setTried]
)
const reconnectUninjectedProvider = useCallback(
(provider: AbstractConnector): void => {
activate(provider, undefined, true).catch(() => {
setTried(true)
})
},
[activate]
)
const connectSafe = useCallback(() => {
gnosisSafe.isSafeApp().then((loadedInSafe) => {
if (loadedInSafe) {
activate(gnosisSafe, undefined, true).catch(() => {
setTriedSafe(true)
})
} else {
setTriedSafe(true)
}
})
}, [activate, setTriedSafe])
useEffect(() => {
if (!active) {
const latestProvider = localStorage.getItem(STORAGE_KEY_LAST_PROVIDER)
// if there is no last saved provider set tried state to true
if (!latestProvider) {
if (!triedSafe) {
// First try to connect using Gnosis Safe
connectSafe()
} else {
// Then try to connect using the injected wallet
connectInjected()
}
} else if (latestProvider === WalletProvider.GNOSIS_SAFE) {
connectSafe()
} else if (latestProvider === WalletProvider.INJECTED) {
// MM is last provider
connectInjected()
} else if (latestProvider === WalletProvider.WALLET_CONNECT) {
// WC is last provider
reconnectUninjectedProvider(walletconnect)
} else if (latestProvider === WalletProvider.WALLET_LINK) {
reconnectUninjectedProvider(walletlink)
} else if (latestProvider === WalletProvider.FORMATIC) {
reconnectUninjectedProvider(fortmatic)
}
}
}, [connectInjected, active, connectSafe, triedSafe, reconnectUninjectedProvider]) // intentionally only running on mount (make sure it's only mounted once :))
// if the connection worked, wait until we get confirmation of that to flip the flag
useEffect(() => {
let timeout: NodeJS.Timeout | undefined
if (active) {
setTried(true)
} else {
timeout = setTimeout(() => {
localStorage.removeItem(STORAGE_KEY_LAST_PROVIDER)
setTried(true)
}, WAITING_TIME_RECONNECT_LAST_PROVIDER)
}
return () => timeout && clearTimeout(timeout)
}, [active])
useEffect(() => {
// add beforeunload event listener on initial component mount
window.addEventListener('beforeunload', handleBeforeUnload)
// remove beforeunload event listener on component unmount
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload)
}
})
return tried
}
/**
* Allows to select the default injected ethereum provider.
*
* It is assumed that metamask is the default injected Provider, however coinbaseWallet overrides this.
*/
export function setDefaultInjected(providerName: DefaultProvidersInjected) {
const { ethereum } = window
if (!ethereum?.providers) return
let provider
switch (providerName) {
case DefaultProvidersInjected.COINBASE_WALLET:
provider = ethereum.providers.find(({ isCoinbaseWallet }) => isCoinbaseWallet)
break
case DefaultProvidersInjected.METAMASK:
provider = ethereum.providers.find(({ isMetaMask }) => isMetaMask)
break
}
if (provider) {
ethereum.setSelectedProvider(provider)
}
}