@wagmi/connectors 4.3.8 → 4.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/tsconfig.build.tsbuildinfo +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/esm/walletConnect.js +115 -59
- package/dist/esm/walletConnect.js.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/dist/types/walletConnect.d.ts +4 -8
- package/dist/types/walletConnect.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/version.ts +1 -1
- package/src/walletConnect.ts +131 -81
package/src/walletConnect.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ChainNotConfiguredError,
|
|
3
|
+
type Connector,
|
|
3
4
|
ProviderNotFoundError,
|
|
4
5
|
createConnector,
|
|
5
6
|
} from '@wagmi/core'
|
|
@@ -8,18 +9,24 @@ import {
|
|
|
8
9
|
type ExactPartial,
|
|
9
10
|
type Omit,
|
|
10
11
|
} from '@wagmi/core/internal'
|
|
11
|
-
import type
|
|
12
|
+
import { type EthereumProvider } from '@walletconnect/ethereum-provider'
|
|
12
13
|
import {
|
|
13
14
|
type AddEthereumChainParameter,
|
|
14
15
|
type Address,
|
|
15
16
|
type ProviderConnectInfo,
|
|
16
17
|
type ProviderRpcError,
|
|
18
|
+
type RpcError,
|
|
17
19
|
SwitchChainError,
|
|
18
20
|
UserRejectedRequestError,
|
|
19
21
|
getAddress,
|
|
20
22
|
numberToHex,
|
|
21
23
|
} from 'viem'
|
|
22
24
|
|
|
25
|
+
type WalletConnectConnector = Connector & {
|
|
26
|
+
onDisplayUri(uri: string): void
|
|
27
|
+
onSessionDelete(data: { topic: string }): void
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
type EthereumProviderOptions = Parameters<typeof EthereumProvider['init']>[0]
|
|
24
31
|
|
|
25
32
|
export type WalletConnectParameters = Evaluate<
|
|
@@ -30,10 +37,6 @@ export type WalletConnectParameters = Evaluate<
|
|
|
30
37
|
* WalletConnect has yet to establish a relationship with (e.g. the user has not approved or
|
|
31
38
|
* rejected the chain).
|
|
32
39
|
*
|
|
33
|
-
* Preface: Whereas WalletConnect v1 supported dynamic chain switching, WalletConnect v2 requires
|
|
34
|
-
* the user to pre-approve a set of chains up-front. This comes with consequent UX nuances (see below) when
|
|
35
|
-
* a user tries to switch to a chain that they have not approved.
|
|
36
|
-
*
|
|
37
40
|
* This flag mainly affects the behavior when a wallet does not support dynamic chain authorization
|
|
38
41
|
* with WalletConnect v2.
|
|
39
42
|
*
|
|
@@ -45,10 +48,11 @@ export type WalletConnectParameters = Evaluate<
|
|
|
45
48
|
* be a confusing user experience (e.g. the user will not know they have to reconnect
|
|
46
49
|
* unless the dapp handles these types of errors).
|
|
47
50
|
*
|
|
48
|
-
* If `false`, the new chain will be treated as a
|
|
51
|
+
* If `false`, the new chain will be treated as a potentially valid chain. This means that if the user
|
|
49
52
|
* has yet to establish a relationship with the chain in their WalletConnect session, wagmi will successfully
|
|
50
53
|
* auto-connect the user. This comes with the trade-off that the connector will throw an error
|
|
51
|
-
* when attempting to switch to the unapproved chain
|
|
54
|
+
* when attempting to switch to the unapproved chain if the wallet does not support dynamic session updates.
|
|
55
|
+
* This may be useful in cases where a dapp constantly
|
|
52
56
|
* modifies their configured chains, and they do not want to disconnect the user upon
|
|
53
57
|
* auto-connecting. If the user decides to switch to the unapproved chain, it is important that the
|
|
54
58
|
* dapp handles this error and prompts the user to reconnect to the dapp in order to approve
|
|
@@ -76,16 +80,12 @@ export function walletConnect(parameters: WalletConnectParameters) {
|
|
|
76
80
|
const isNewChainsStale = parameters.isNewChainsStale ?? true
|
|
77
81
|
|
|
78
82
|
type Provider = Awaited<ReturnType<typeof EthereumProvider['init']>>
|
|
79
|
-
type NamespaceMethods =
|
|
80
|
-
| 'wallet_addEthereumChain'
|
|
81
|
-
| 'wallet_switchEthereumChain'
|
|
82
83
|
type Properties = {
|
|
83
84
|
connect(parameters?: { chainId?: number; pairingTopic?: string }): Promise<{
|
|
84
85
|
accounts: readonly Address[]
|
|
85
86
|
chainId: number
|
|
86
87
|
}>
|
|
87
88
|
getNamespaceChainsIds(): number[]
|
|
88
|
-
getNamespaceMethods(): NamespaceMethods[]
|
|
89
89
|
getRequestedChainsIds(): Promise<number[]>
|
|
90
90
|
isChainsStale(): Promise<boolean>
|
|
91
91
|
onConnect(connectInfo: ProviderConnectInfo): void
|
|
@@ -102,6 +102,13 @@ export function walletConnect(parameters: WalletConnectParameters) {
|
|
|
102
102
|
let providerPromise: Promise<typeof provider_>
|
|
103
103
|
const NAMESPACE = 'eip155'
|
|
104
104
|
|
|
105
|
+
let accountsChanged: WalletConnectConnector['onAccountsChanged'] | undefined
|
|
106
|
+
let chainChanged: WalletConnectConnector['onChainChanged'] | undefined
|
|
107
|
+
let connect: WalletConnectConnector['onConnect'] | undefined
|
|
108
|
+
let displayUri: WalletConnectConnector['onDisplayUri'] | undefined
|
|
109
|
+
let sessionDelete: WalletConnectConnector['onSessionDelete'] | undefined
|
|
110
|
+
let disconnect: WalletConnectConnector['onDisconnect'] | undefined
|
|
111
|
+
|
|
105
112
|
return createConnector<Provider, Properties, StorageItem>((config) => ({
|
|
106
113
|
id: 'walletConnect',
|
|
107
114
|
name: 'WalletConnect',
|
|
@@ -109,14 +116,23 @@ export function walletConnect(parameters: WalletConnectParameters) {
|
|
|
109
116
|
async setup() {
|
|
110
117
|
const provider = await this.getProvider().catch(() => null)
|
|
111
118
|
if (!provider) return
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
if (!connect) {
|
|
120
|
+
connect = this.onConnect.bind(this)
|
|
121
|
+
provider.on('connect', connect)
|
|
122
|
+
}
|
|
123
|
+
if (!sessionDelete) {
|
|
124
|
+
sessionDelete = this.onSessionDelete.bind(this)
|
|
125
|
+
provider.on('session_delete', sessionDelete)
|
|
126
|
+
}
|
|
114
127
|
},
|
|
115
128
|
async connect({ chainId, ...rest } = {}) {
|
|
116
129
|
try {
|
|
117
130
|
const provider = await this.getProvider()
|
|
118
131
|
if (!provider) throw new ProviderNotFoundError()
|
|
119
|
-
|
|
132
|
+
if (!displayUri) {
|
|
133
|
+
displayUri = this.onDisplayUri
|
|
134
|
+
provider.on('display_uri', displayUri)
|
|
135
|
+
}
|
|
120
136
|
|
|
121
137
|
let targetChainId = chainId
|
|
122
138
|
if (!targetChainId) {
|
|
@@ -152,12 +168,30 @@ export function walletConnect(parameters: WalletConnectParameters) {
|
|
|
152
168
|
const accounts = (await provider.enable()).map((x) => getAddress(x))
|
|
153
169
|
const currentChainId = await this.getChainId()
|
|
154
170
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
171
|
+
if (displayUri) {
|
|
172
|
+
provider.removeListener('display_uri', displayUri)
|
|
173
|
+
displayUri = undefined
|
|
174
|
+
}
|
|
175
|
+
if (connect) {
|
|
176
|
+
provider.removeListener('connect', connect)
|
|
177
|
+
connect = undefined
|
|
178
|
+
}
|
|
179
|
+
if (!accountsChanged) {
|
|
180
|
+
accountsChanged = this.onAccountsChanged.bind(this)
|
|
181
|
+
provider.on('accountsChanged', accountsChanged)
|
|
182
|
+
}
|
|
183
|
+
if (!chainChanged) {
|
|
184
|
+
chainChanged = this.onChainChanged.bind(this)
|
|
185
|
+
provider.on('chainChanged', chainChanged)
|
|
186
|
+
}
|
|
187
|
+
if (!disconnect) {
|
|
188
|
+
disconnect = this.onDisconnect.bind(this)
|
|
189
|
+
provider.on('disconnect', disconnect)
|
|
190
|
+
}
|
|
191
|
+
if (!sessionDelete) {
|
|
192
|
+
sessionDelete = this.onSessionDelete.bind(this)
|
|
193
|
+
provider.on('session_delete', sessionDelete)
|
|
194
|
+
}
|
|
161
195
|
|
|
162
196
|
return { accounts, chainId: currentChainId }
|
|
163
197
|
} catch (error) {
|
|
@@ -178,17 +212,26 @@ export function walletConnect(parameters: WalletConnectParameters) {
|
|
|
178
212
|
} catch (error) {
|
|
179
213
|
if (!/No matching key/i.test((error as Error).message)) throw error
|
|
180
214
|
} finally {
|
|
181
|
-
|
|
182
|
-
'
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
215
|
+
if (chainChanged) {
|
|
216
|
+
provider?.removeListener('chainChanged', chainChanged)
|
|
217
|
+
chainChanged = undefined
|
|
218
|
+
}
|
|
219
|
+
if (disconnect) {
|
|
220
|
+
provider?.removeListener('disconnect', disconnect)
|
|
221
|
+
disconnect = undefined
|
|
222
|
+
}
|
|
223
|
+
if (!connect) {
|
|
224
|
+
connect = this.onConnect.bind(this)
|
|
225
|
+
provider?.on('connect', connect)
|
|
226
|
+
}
|
|
227
|
+
if (accountsChanged) {
|
|
228
|
+
provider?.removeListener('accountsChanged', accountsChanged)
|
|
229
|
+
accountsChanged = undefined
|
|
230
|
+
}
|
|
231
|
+
if (sessionDelete) {
|
|
232
|
+
provider?.removeListener('session_delete', sessionDelete)
|
|
233
|
+
sessionDelete = undefined
|
|
234
|
+
}
|
|
192
235
|
|
|
193
236
|
this.setRequestedChainsIds([])
|
|
194
237
|
}
|
|
@@ -253,19 +296,43 @@ export function walletConnect(parameters: WalletConnectParameters) {
|
|
|
253
296
|
}
|
|
254
297
|
},
|
|
255
298
|
async switchChain({ addEthereumChainParameter, chainId }) {
|
|
256
|
-
const
|
|
299
|
+
const provider = await this.getProvider()
|
|
300
|
+
if (!provider) throw new ProviderNotFoundError()
|
|
301
|
+
|
|
302
|
+
const chain = config.chains.find((x) => x.id === chainId)
|
|
257
303
|
if (!chain) throw new SwitchChainError(new ChainNotConfiguredError())
|
|
258
304
|
|
|
259
305
|
try {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
306
|
+
await Promise.all([
|
|
307
|
+
new Promise<void>((resolve) => {
|
|
308
|
+
const listener = ({
|
|
309
|
+
chainId: currentChainId,
|
|
310
|
+
}: { chainId?: number }) => {
|
|
311
|
+
if (currentChainId === chainId) {
|
|
312
|
+
config.emitter.off('change', listener)
|
|
313
|
+
resolve()
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
config.emitter.on('change', listener)
|
|
317
|
+
}),
|
|
318
|
+
provider.request({
|
|
319
|
+
method: 'wallet_switchEthereumChain',
|
|
320
|
+
params: [{ chainId: numberToHex(chainId) }],
|
|
321
|
+
}),
|
|
322
|
+
])
|
|
264
323
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
324
|
+
const requestedChains = await this.getRequestedChainsIds()
|
|
325
|
+
this.setRequestedChainsIds([...requestedChains, chainId])
|
|
326
|
+
|
|
327
|
+
return chain
|
|
328
|
+
} catch (err) {
|
|
329
|
+
const error = err as RpcError
|
|
330
|
+
|
|
331
|
+
if (/(user rejected)/i.test(error.message))
|
|
332
|
+
throw new UserRejectedRequestError(error)
|
|
333
|
+
|
|
334
|
+
// Indicates chain is not added to provider
|
|
335
|
+
try {
|
|
269
336
|
let blockExplorerUrls
|
|
270
337
|
if (addEthereumChainParameter?.blockExplorerUrls)
|
|
271
338
|
blockExplorerUrls = addEthereumChainParameter.blockExplorerUrls
|
|
@@ -293,23 +360,13 @@ export function walletConnect(parameters: WalletConnectParameters) {
|
|
|
293
360
|
method: 'wallet_addEthereumChain',
|
|
294
361
|
params: [addEthereumChain],
|
|
295
362
|
})
|
|
363
|
+
|
|
296
364
|
const requestedChains = await this.getRequestedChainsIds()
|
|
297
365
|
this.setRequestedChainsIds([...requestedChains, chainId])
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
await provider.request({
|
|
301
|
-
method: 'wallet_switchEthereumChain',
|
|
302
|
-
params: [{ chainId: numberToHex(chainId) }],
|
|
303
|
-
})
|
|
304
|
-
return chain
|
|
305
|
-
} catch (error) {
|
|
306
|
-
const message =
|
|
307
|
-
typeof error === 'string'
|
|
308
|
-
? error
|
|
309
|
-
: (error as ProviderRpcError)?.message
|
|
310
|
-
if (/user rejected request/i.test(message))
|
|
366
|
+
return chain
|
|
367
|
+
} catch (error) {
|
|
311
368
|
throw new UserRejectedRequestError(error as Error)
|
|
312
|
-
|
|
369
|
+
}
|
|
313
370
|
}
|
|
314
371
|
},
|
|
315
372
|
onAccountsChanged(accounts) {
|
|
@@ -333,14 +390,26 @@ export function walletConnect(parameters: WalletConnectParameters) {
|
|
|
333
390
|
config.emitter.emit('disconnect')
|
|
334
391
|
|
|
335
392
|
const provider = await this.getProvider()
|
|
336
|
-
|
|
337
|
-
'accountsChanged',
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
393
|
+
if (accountsChanged) {
|
|
394
|
+
provider.removeListener('accountsChanged', accountsChanged)
|
|
395
|
+
accountsChanged = undefined
|
|
396
|
+
}
|
|
397
|
+
if (chainChanged) {
|
|
398
|
+
provider.removeListener('chainChanged', chainChanged)
|
|
399
|
+
chainChanged = undefined
|
|
400
|
+
}
|
|
401
|
+
if (disconnect) {
|
|
402
|
+
provider.removeListener('disconnect', disconnect)
|
|
403
|
+
disconnect = undefined
|
|
404
|
+
}
|
|
405
|
+
if (sessionDelete) {
|
|
406
|
+
provider.removeListener('session_delete', sessionDelete)
|
|
407
|
+
sessionDelete = undefined
|
|
408
|
+
}
|
|
409
|
+
if (!connect) {
|
|
410
|
+
connect = this.onConnect.bind(this)
|
|
411
|
+
provider.on('connect', connect)
|
|
412
|
+
}
|
|
344
413
|
},
|
|
345
414
|
onDisplayUri(uri) {
|
|
346
415
|
config.emitter.emit('message', { type: 'display_uri', data: uri })
|
|
@@ -355,12 +424,6 @@ export function walletConnect(parameters: WalletConnectParameters) {
|
|
|
355
424
|
)
|
|
356
425
|
return chainIds ?? []
|
|
357
426
|
},
|
|
358
|
-
getNamespaceMethods() {
|
|
359
|
-
if (!provider_) return []
|
|
360
|
-
const methods = provider_.session?.namespaces[NAMESPACE]
|
|
361
|
-
?.methods as NamespaceMethods[]
|
|
362
|
-
return methods ?? []
|
|
363
|
-
},
|
|
364
427
|
async getRequestedChainsIds() {
|
|
365
428
|
return (
|
|
366
429
|
(await config.storage?.getItem(this.requestedChainsStorageKey)) ?? []
|
|
@@ -376,21 +439,8 @@ export function walletConnect(parameters: WalletConnectParameters) {
|
|
|
376
439
|
* There may be a scenario where a dapp adds a chain to the
|
|
377
440
|
* connector later on, however, this chain will not have been approved or rejected
|
|
378
441
|
* by the wallet. In this case, the chain is considered stale.
|
|
379
|
-
*
|
|
380
|
-
* There are exceptions however:
|
|
381
|
-
* - If the wallet supports dynamic chain addition via `eth_addEthereumChain`,
|
|
382
|
-
* then the chain is not considered stale.
|
|
383
|
-
* - If the `isNewChainsStale` flag is falsy on the connector, then the chain is
|
|
384
|
-
* not considered stale.
|
|
385
|
-
*
|
|
386
|
-
* For the above cases, chain validation occurs dynamically when the user
|
|
387
|
-
* attempts to switch chain.
|
|
388
|
-
*
|
|
389
|
-
* Also check that dapp supports at least 1 chain from previously approved session.
|
|
390
442
|
*/
|
|
391
443
|
async isChainsStale() {
|
|
392
|
-
const namespaceMethods = this.getNamespaceMethods()
|
|
393
|
-
if (namespaceMethods.includes('wallet_addEthereumChain')) return false
|
|
394
444
|
if (!isNewChainsStale) return false
|
|
395
445
|
|
|
396
446
|
const connectorChains = config.chains.map((x) => x.id)
|