Skip to content
This repository was archived by the owner on Nov 10, 2023. It is now read-only.

Commit 781c87d

Browse files
committed
Revert "fix: decouple pairing provider (#3753)"
1 parent f9ad409 commit 781c87d

File tree

12 files changed

+100
-135
lines changed

12 files changed

+100
-135
lines changed

.prettierrc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,5 @@
33
"printWidth": 120,
44
"trailingComma": "all",
55
"singleQuote": true,
6-
"semi": false,
7-
"endOfLine": "auto"
6+
"semi": false
87
}

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"generate-types:erc721": "cross-env typechain --target=web3-v1 --out-dir './src/types/contracts' './node_modules/@openzeppelin/contracts/build/contracts/ERC721.json'",
2727
"generate-types:spendingLimit": "cross-env typechain --target=web3-v1 --out-dir './src/types/contracts' ./node_modules/@gnosis.pm/safe-modules-deployments/dist/assets/**/*.json",
2828
"generate-types:safeDeployments": "cross-env typechain --target=web3-v1 --out-dir './src/types/contracts' ./node_modules/@gnosis.pm/safe-deployments/dist/assets/**/*.json",
29-
"lint:check": "cross-env eslint './src/**/*.{js,jsx,ts,tsx}'",
29+
"lint:check": "eslint './src/**/*.{js,jsx,ts,tsx}'",
3030
"lint:fix": "yarn lint:check --fix",
3131
"postinstall": "patch-package && yarn generate-types",
3232
"prettier:check": "yarn prettier --check",
@@ -94,7 +94,7 @@
9494
"abi-decoder": "^2.4.0",
9595
"axios": "0.21.4",
9696
"bignumber.js": "9.0.1",
97-
"bnc-onboard": "^1.38.2",
97+
"bnc-onboard": "^1.37.3",
9898
"classnames": "^2.2.6",
9999
"currency-flags": "3.2.1",
100100
"date-fns": "^2.20.2",

src/components/AppLayout/Header/components/ProviderDetails/PairingDetails.tsx

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
import { ReactElement } from 'react'
1+
import { CSSProperties, ReactElement } from 'react'
2+
import Skeleton from '@material-ui/lab/Skeleton'
3+
import RefreshIcon from '@material-ui/icons/Refresh'
4+
import IconButton from '@material-ui/core/IconButton'
25
import { Divider, Link } from '@gnosis.pm/safe-react-components'
36
import styled from 'styled-components'
47
import QRCode from 'qrcode.react'
58

69
import Paragraph from 'src/components/layout/Paragraph'
710
import Row from 'src/components/layout/Row'
811
import usePairing from 'src/logic/wallets/pairing/hooks/usePairing'
12+
import { initPairing, isPairingModule } from 'src/logic/wallets/pairing/utils'
13+
import { useGetPairingUri } from 'src/logic/wallets/pairing/hooks/useGetPairingUri'
914
import { OVERVIEW_EVENTS } from 'src/utils/events/overview'
1015
import Track from 'src/components/Track'
1116
import AppstoreButton from 'src/components/AppstoreButton'
@@ -17,8 +22,15 @@ const StyledDivider = styled(Divider)`
1722

1823
const QR_DIMENSION = 120
1924

25+
const qrRefresh: CSSProperties = {
26+
width: QR_DIMENSION,
27+
height: QR_DIMENSION,
28+
}
29+
2030
const PairingDetails = ({ classes }: { classes: Record<string, string> }): ReactElement => {
21-
const { uri } = usePairing()
31+
const uri = useGetPairingUri()
32+
const isPairingLoaded = isPairingModule()
33+
usePairing()
2234

2335
return (
2436
<>
@@ -31,7 +43,15 @@ const PairingDetails = ({ classes }: { classes: Record<string, string> }): React
3143
</Row>
3244

3345
<Row className={classes.justifyCenter}>
34-
<QRCode value={uri} size={QR_DIMENSION} />
46+
{uri ? (
47+
<QRCode value={uri} size={QR_DIMENSION} />
48+
) : isPairingLoaded ? (
49+
<Skeleton variant="rect" width={QR_DIMENSION} height={QR_DIMENSION} />
50+
) : (
51+
<IconButton disableRipple style={qrRefresh} onClick={initPairing}>
52+
<RefreshIcon fontSize="large" />
53+
</IconButton>
54+
)}
3555
</Row>
3656

3757
<Row>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { getPairingUri } from 'src/logic/wallets/pairing/utils'
2+
import { useEffect, useState } from 'react'
3+
4+
export const useGetPairingUri = (): string | undefined => {
5+
const onboardUri = getPairingUri()
6+
const [uri, setUri] = useState<string>()
7+
8+
useEffect(() => {
9+
setTimeout(() => {
10+
setUri(getPairingUri())
11+
}, 100)
12+
}, [onboardUri])
13+
14+
return uri
15+
}
Lines changed: 6 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,13 @@
1-
import { useCallback, useEffect, useMemo, useState } from 'react'
2-
import { IEventEmitter } from '@walletconnect/types'
1+
import { useEffect } from 'react'
32

4-
import { getPairingUri } from 'src/logic/wallets/pairing/utils'
5-
import onboard from 'src/logic/wallets/onboard'
6-
import { getPairingProvider, PAIRING_MODULE_NAME } from 'src/logic/wallets/pairing/module'
7-
8-
let defaultEvents: IEventEmitter[]
9-
10-
// These handful of events relate to the session lifecycle
11-
enum WC_EVENT {
12-
CONNECT = 'connect',
13-
DISCONNECT = 'disconnect',
14-
DISPLAY_URI = 'display_uri',
15-
SESSION_UPDATE = 'wc_sessionUpdate',
16-
}
17-
18-
const usePairing = (): { uri: string } => {
19-
const provider = useMemo(getPairingProvider, [])
20-
21-
const [uri, setUri] = useState<string>(getPairingUri(provider.wc.uri))
22-
23-
// Pairing session lifecycle
24-
const createPairingSession = useCallback(() => {
25-
if (!provider.wc.connected) {
26-
provider.enable()
27-
provider.wc.createSession()
28-
}
29-
}, [provider])
3+
import { initPairing, isPairingConnected } from 'src/logic/wallets/pairing/utils'
304

5+
const usePairing = (): void => {
316
useEffect(() => {
32-
if (!defaultEvents) {
33-
defaultEvents = (provider.wc as any)._eventManager._eventEmitters as IEventEmitter[]
7+
if (!isPairingConnected()) {
8+
initPairing()
349
}
35-
36-
// Resest event listeners to default
37-
;(provider.wc as any)._eventManager._eventEmitters = defaultEvents
38-
39-
// Watch for URI change
40-
Object.values(WC_EVENT).forEach((event) =>
41-
provider.wc.on(event, () => {
42-
const pairingUri = getPairingUri(provider.wc.uri)
43-
setUri(pairingUri)
44-
}),
45-
)
46-
47-
// Watch for connection
48-
provider.wc.on(WC_EVENT.CONNECT, () => {
49-
onboard().walletSelect(PAIRING_MODULE_NAME)
50-
})
51-
52-
// Handle disconnection (`walletReset()` occurs inside pairing module)
53-
provider.wc.on(WC_EVENT.DISCONNECT, createPairingSession)
54-
provider.wc.on(WC_EVENT.SESSION_UPDATE, (_, { params }) => {
55-
const didRevokeSession = params[0]?.approved === false
56-
if (didRevokeSession) {
57-
createPairingSession()
58-
}
59-
})
60-
61-
// Create pairing session if one isn't already active
62-
createPairingSession()
63-
}, [createPairingSession, provider.wc])
64-
65-
return { uri }
10+
}, [])
6611
}
6712

6813
export default usePairing

src/logic/wallets/pairing/module.ts

Lines changed: 20 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import WalletConnectProvider from '@walletconnect/web3-provider'
21
import { IClientMeta } from '@walletconnect/types'
32
import { WalletModule } from 'bnc-onboard/dist/src/interfaces'
43
import UAParser from 'ua-parser-js'
54

65
import { APP_VERSION, PUBLIC_URL } from 'src/utils/constants'
6+
import { ChainId } from 'src/config/chain'
77
import { getWCWalletInterface, getWalletConnectProvider } from 'src/logic/wallets/walletConnect/utils'
8-
import { _getChainId } from 'src/config'
98

109
// Modified version of the built in WC module in Onboard v1.35.5
1110
// https://github.com/blocknative/onboard/blob/release/1.35.5/src/modules/select/wallets/wallet-connect.ts
@@ -34,59 +33,40 @@ const getClientMeta = (): IClientMeta => {
3433
}
3534
}
3635

37-
const createPairingProvider = (): WalletConnectProvider => {
36+
// Note: this shares a lot of similarities with the patchedWalletConnect module
37+
const getPairingModule = (chainId: ChainId): WalletModule => {
3838
const STORAGE_ID = 'SAFE__pairingProvider'
3939
const clientMeta = getClientMeta()
4040

41-
// Successful pairing does not use chainId of provider but that of the pairee
42-
// so we can use any chainId here
43-
const provider = getWalletConnectProvider(_getChainId(), {
44-
storageId: STORAGE_ID,
45-
qrcode: false, // Don't show QR modal
46-
clientMeta,
47-
})
48-
49-
// WalletConnect overrides the clientMeta, so we need to set it back
50-
;(provider.wc as any).clientMeta = clientMeta
51-
;(provider.wc as any)._clientMeta = clientMeta
52-
53-
return provider
54-
}
55-
56-
let _pairingProvider: WalletConnectProvider | undefined
57-
58-
export const getPairingProvider = (): WalletConnectProvider => {
59-
// We cannot initialize provider immediately as we need to wait for chains to load RPCs
60-
if (!_pairingProvider) {
61-
_pairingProvider = createPairingProvider()
62-
}
63-
return _pairingProvider
64-
}
65-
66-
// Note: this shares a lot of similarities with the patchedWalletConnect module
67-
const getPairingModule = (): WalletModule => {
68-
const name = PAIRING_MODULE_NAME
69-
const provider = getPairingProvider()
70-
7141
return {
72-
name,
42+
name: PAIRING_MODULE_NAME,
7343
wallet: async ({ resetWalletState }) => {
74-
// Enable provider when a previously interrupted session exists
75-
if (provider.wc.session.connected) {
76-
provider.enable()
44+
const provider = getWalletConnectProvider(chainId, {
45+
storageId: STORAGE_ID,
46+
qrcode: false, // Don't show QR modal
47+
clientMeta,
48+
})
49+
50+
// WalletConnect overrides the clientMeta, so we need to set it back
51+
;(provider.wc as any).clientMeta = clientMeta
52+
;(provider.wc as any)._clientMeta = clientMeta
53+
54+
const onDisconnect = () => {
55+
resetWalletState({ disconnected: true, walletName: PAIRING_MODULE_NAME })
7756
}
7857

79-
const onDisconnect = () => resetWalletState({ walletName: name, disconnected: true })
8058
provider.wc.on('disconnect', onDisconnect)
8159

82-
// Kill session if module unmounts (a non-pairing wallet connects)
8360
window.addEventListener('unload', onDisconnect, { once: true })
8461

62+
// Establish WC connection
63+
provider.enable()
64+
8565
return {
8666
provider,
8767
interface: {
8868
...getWCWalletInterface(provider),
89-
name,
69+
name: PAIRING_MODULE_NAME,
9070
},
9171
}
9272
},

src/logic/wallets/pairing/utils.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ import { PAIRING_MODULE_NAME } from 'src/logic/wallets/pairing/module'
55
import { WALLETS } from 'src/config/chain.d'
66
import onboard from 'src/logic/wallets/onboard'
77

8+
export const initPairing = async (): Promise<void> => {
9+
await onboard().walletSelect(PAIRING_MODULE_NAME)
10+
}
11+
12+
// Is WC connected (may work for other providers)
13+
export const isPairingConnected = (): boolean => {
14+
return onboard().getState().wallet.provider?.connected
15+
}
16+
817
export const isPairingSupported = (): boolean => {
918
return !getDisabledWallets().includes(WALLETS.SAFE_MOBILE)
1019
}
@@ -14,7 +23,8 @@ export const isPairingModule = (name: Wallet['name'] = onboard().getState().wall
1423
return name === PAIRING_MODULE_NAME
1524
}
1625

17-
export const getPairingUri = (wcUri: string): string => {
26+
export const getPairingUri = (): string | undefined => {
27+
const wcUri = onboard().getState().wallet.provider?.wc?.uri
1828
const PAIRING_MODULE_URI_PREFIX = 'safe-'
19-
return wcUri ? `${PAIRING_MODULE_URI_PREFIX}${wcUri}` : ''
29+
return wcUri ? `${PAIRING_MODULE_URI_PREFIX}${wcUri}` : undefined
2030
}

src/logic/wallets/patchedWalletConnect.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import { WalletModule, Helpers } from 'bnc-onboard/dist/src/interfaces'
44

55
import { getRpcServiceUrl } from 'src/config'
66
import { getChains } from 'src/config/cache/chains'
7-
import { INFURA_TOKEN, WC_BRIDGE } from 'src/utils/constants'
7+
import { INFURA_TOKEN } from 'src/utils/constants'
88
import { ChainId } from 'src/config/chain'
99

10+
// TODO: When desktop pairing is merged, import these into there
11+
export const WC_BRIDGE = 'https://safe-walletconnect.gnosis.io/'
12+
1013
// Modified version of the built in WC module in Onboard v1.35.5, including:
1114
// https://github.com/blocknative/onboard/blob/release/1.35.5/src/modules/select/wallets/wallet-connect.ts
1215

src/logic/wallets/utils/walletList.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,5 @@ export const getSupportedWallets = (chainId: ChainId): WalletSelectModuleOptions
9393
}
9494

9595
// Pairing must be 1st in list (to hide via CSS)
96-
return isPairingSupported() ? [getPairingModule(), ...supportedWallets] : supportedWallets
96+
return isPairingSupported() ? [getPairingModule(chainId), ...supportedWallets] : supportedWallets
9797
}

src/logic/wallets/walletConnect/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import { WalletInterface } from 'bnc-onboard/dist/src/interfaces'
55
import { getRpcServiceUrl } from 'src/config'
66
import { getChains } from 'src/config/cache/chains'
77
import { ChainId } from 'src/config/chain'
8-
import { INFURA_TOKEN, WC_BRIDGE } from 'src/utils/constants'
8+
import { INFURA_TOKEN } from 'src/utils/constants'
99

1010
type Options = Omit<IWalletConnectProviderOptions, 'bridge' | 'infuraId' | 'rpc' | 'chainId' | 'pollingInterval'>
1111

1212
export const getWalletConnectProvider = (chainId: ChainId, options: Options = {}): WalletConnectProvider => {
13+
const WC_BRIDGE = 'https://safe-walletconnect.gnosis.io/'
1314
// Prevent `eth_getBlockByNumber` polling every 4 seconds
1415
// https://github.com/WalletConnect/walletconnect-monorepo/issues/357#issuecomment-789663540
1516
const POLLING_INTERVAL = 60_000 * 60 // 1 hour

0 commit comments

Comments
 (0)