@wagmi/connectors 4.0.0-alpha.0 → 4.0.0-alpha.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.
Files changed (49) hide show
  1. package/README.md +13 -0
  2. package/dist/esm/coinbaseWallet.js +11 -14
  3. package/dist/esm/coinbaseWallet.js.map +1 -1
  4. package/dist/esm/exports/index.js +8 -0
  5. package/dist/esm/exports/index.js.map +1 -0
  6. package/dist/esm/exports/index.test-d.js.map +1 -0
  7. package/dist/esm/ledger.js +2 -2
  8. package/dist/esm/ledger.js.map +1 -1
  9. package/dist/esm/metaMask.js +246 -0
  10. package/dist/esm/metaMask.js.map +1 -0
  11. package/dist/esm/safe.js +17 -16
  12. package/dist/esm/safe.js.map +1 -1
  13. package/dist/esm/tsconfig.build.tsbuildinfo +1 -1
  14. package/dist/esm/version.js +1 -1
  15. package/dist/esm/version.js.map +1 -1
  16. package/dist/esm/walletConnect.js +7 -7
  17. package/dist/esm/walletConnect.js.map +1 -1
  18. package/dist/types/coinbaseWallet.d.ts.map +1 -1
  19. package/dist/types/exports/index.d.ts +8 -0
  20. package/dist/types/exports/index.d.ts.map +1 -0
  21. package/dist/types/exports/index.test-d.d.ts.map +1 -0
  22. package/dist/types/metaMask.d.ts +10 -0
  23. package/dist/types/metaMask.d.ts.map +1 -0
  24. package/dist/types/safe.d.ts +2 -2
  25. package/dist/types/safe.d.ts.map +1 -1
  26. package/dist/types/version.d.ts +1 -1
  27. package/dist/types/version.d.ts.map +1 -1
  28. package/package.json +19 -24
  29. package/src/coinbaseWallet.ts +12 -14
  30. package/src/exports/index.ts +24 -0
  31. package/src/ledger.ts +2 -2
  32. package/src/metaMask.ts +316 -0
  33. package/src/safe.ts +24 -20
  34. package/src/version.ts +1 -1
  35. package/src/walletConnect.ts +7 -7
  36. package/dist/esm/index.js +0 -7
  37. package/dist/esm/index.js.map +0 -1
  38. package/dist/esm/index.test-d.js.map +0 -1
  39. package/dist/esm/injected.js +0 -372
  40. package/dist/esm/injected.js.map +0 -1
  41. package/dist/types/index.d.ts +0 -7
  42. package/dist/types/index.d.ts.map +0 -1
  43. package/dist/types/index.test-d.d.ts.map +0 -1
  44. package/dist/types/injected.d.ts +0 -382
  45. package/dist/types/injected.d.ts.map +0 -1
  46. package/src/index.ts +0 -17
  47. package/src/injected.ts +0 -535
  48. /package/dist/esm/{index.test-d.js → exports/index.test-d.js} +0 -0
  49. /package/dist/types/{index.test-d.d.ts → exports/index.test-d.d.ts} +0 -0
package/src/injected.ts DELETED
@@ -1,535 +0,0 @@
1
- import {
2
- ChainNotConfiguredError,
3
- ProviderNotFoundError,
4
- createConnector,
5
- normalizeChainId,
6
- } from '@wagmi/core'
7
- import type { Evaluate } from '@wagmi/core/internal'
8
- import {
9
- type Address,
10
- type EIP1193Provider,
11
- type ProviderConnectInfo,
12
- ProviderRpcError,
13
- ResourceUnavailableRpcError,
14
- RpcError,
15
- SwitchChainError,
16
- UserRejectedRequestError,
17
- getAddress,
18
- numberToHex,
19
- } from 'viem'
20
-
21
- export type InjectedParameters = {
22
- /**
23
- * MetaMask and other injected providers do not support programmatic disconnect.
24
- * This flag simulates the disconnect behavior by keeping track of connection status in storage. See [GitHub issue](https://github.com/MetaMask/metamask-extension/issues/10353) for more info.
25
- * @default true
26
- */
27
- shimDisconnect?: boolean | undefined
28
- unstable_shimAsyncInject?: boolean | number | undefined
29
- /**
30
- * [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) Ethereum Provider to target
31
- */
32
- target?:
33
- | TargetId
34
- | (() => (TargetMap[TargetId] & { id: string }) | undefined)
35
- | undefined
36
- }
37
-
38
- const targetMap = {
39
- coinbaseWallet: {
40
- name: 'Coinbase Wallet',
41
- provider(window) {
42
- if (window?.coinbaseWalletExtension) return window.coinbaseWalletExtension
43
- return findProvider(window, 'isCoinbaseWallet')
44
- },
45
- },
46
- metaMask: {
47
- name: 'MetaMask',
48
- provider(window) {
49
- return findProvider(window, (windowProvider) => {
50
- if (!windowProvider.isMetaMask) return false
51
- // Brave tries to make itself look like MetaMask
52
- // Could also try RPC `web3_clientVersion` if following is unreliable
53
- if (
54
- windowProvider.isBraveWallet &&
55
- !windowProvider._events &&
56
- !windowProvider._state
57
- )
58
- return false
59
- // Other wallets that try to look like MetaMask
60
- const flags: (keyof WindowProviderFlags)[] = [
61
- 'isApexWallet',
62
- 'isAvalanche',
63
- 'isBitKeep',
64
- 'isBlockWallet',
65
- 'isKuCoinWallet',
66
- 'isMathWallet',
67
- 'isOkxWallet',
68
- 'isOKExWallet',
69
- 'isOneInchIOSWallet',
70
- 'isOneInchAndroidWallet',
71
- 'isOpera',
72
- 'isPortal',
73
- 'isRabby',
74
- 'isTokenPocket',
75
- 'isTokenary',
76
- 'isZerion',
77
- ]
78
- for (const flag of flags) if (windowProvider[flag]) return false
79
- return true
80
- })
81
- },
82
- features: ['wallet_requestPermissions'],
83
- },
84
- phantom: {
85
- name: 'Phantom',
86
- provider(window) {
87
- if (window?.phantom?.ethereum) return window.phantom?.ethereum
88
- return findProvider(window, 'isPhantom')
89
- },
90
- },
91
- } as const satisfies TargetMap
92
-
93
- export function injected(parameters: InjectedParameters = {}) {
94
- const shimDisconnect = parameters.shimDisconnect ?? true
95
- const unstable_shimAsyncInject = parameters.unstable_shimAsyncInject
96
-
97
- function getWindowProvider(): TargetMap[TargetId] & { id: string } {
98
- const target = parameters.target
99
- if (typeof target === 'function') {
100
- const result = target()
101
- if (result) return result
102
- }
103
- if (typeof target === 'string')
104
- return {
105
- ...(targetMap[target as keyof typeof targetMap] ?? {
106
- name: `${target[0]!.toUpperCase()}${target.slice(1)}`,
107
- provider: `is${target[0]!.toUpperCase()}${target.slice(1)}`,
108
- }),
109
- id: target,
110
- }
111
- return {
112
- id: 'injected',
113
- name: 'Injected',
114
- provider(window) {
115
- return window?.ethereum
116
- },
117
- }
118
- }
119
-
120
- type Provider = WindowProvider | undefined
121
- type Properties = {
122
- onConnect(connectInfo: ProviderConnectInfo): void
123
- }
124
- type StorageItem = { [_ in `${string}.connected`]: true }
125
-
126
- return createConnector<Provider, Properties, StorageItem>((config) => ({
127
- get id() {
128
- return getWindowProvider().id
129
- },
130
- get name() {
131
- return getWindowProvider().name
132
- },
133
- async setup() {
134
- const provider = await this.getProvider()
135
- // Only start listening for events if `target` is set, otherwise `injected()` will also receive events
136
- if (provider && parameters.target) {
137
- provider.on('accountsChanged', this.onAccountsChanged.bind(this))
138
- provider.on('connect', this.onConnect.bind(this))
139
- }
140
- },
141
- async connect({ chainId } = {}) {
142
- const provider = await this.getProvider()
143
- if (!provider) throw new ProviderNotFoundError()
144
-
145
- try {
146
- // Attempt to show select prompt with `wallet_requestPermissions` when
147
- // `shimDisconnect` is active and account is in disconnected state (flag in storage)
148
- const canSelectAccount = getWindowProvider().features?.includes(
149
- 'wallet_requestPermissions',
150
- )
151
- const isDisconnected =
152
- shimDisconnect &&
153
- !(await config.storage?.getItem(`${this.id}.connected`))
154
-
155
- let accounts: readonly Address[] | null = null
156
- if (canSelectAccount && isDisconnected) {
157
- accounts = await this.getAccounts().catch(() => null)
158
- const isAuthorized = !!accounts?.length
159
- if (isAuthorized)
160
- // Attempt to show another prompt for selecting connector if already connected
161
- try {
162
- const permissions = await provider.request({
163
- method: 'wallet_requestPermissions',
164
- params: [{ eth_accounts: {} }],
165
- })
166
- accounts = permissions[0]?.caveats?.[0]?.value?.map(getAddress)
167
- } catch (error) {
168
- // Not all injected providers support `wallet_requestPermissions` (e.g. MetaMask iOS).
169
- // Only bubble up error if user rejects request
170
- if ((error as ProviderRpcError).code === 4_001)
171
- throw new UserRejectedRequestError(error as RpcError)
172
- // Or prompt is already open
173
- if (
174
- (error as RpcError).code ===
175
- new ResourceUnavailableRpcError(error as Error).code
176
- )
177
- throw error
178
- }
179
- }
180
-
181
- if (!accounts?.length) {
182
- const accounts_ = await provider.request({
183
- method: 'eth_requestAccounts',
184
- })
185
- accounts = accounts_.map(getAddress)
186
- }
187
-
188
- provider.removeListener('connect', this.onConnect.bind(this))
189
- provider.on('accountsChanged', this.onAccountsChanged.bind(this))
190
- provider.on('chainChanged', this.onChainChanged)
191
- provider.on('disconnect', this.onDisconnect.bind(this))
192
-
193
- // Switch to chain if provided
194
- let currentChainId = await this.getChainId()
195
- if (chainId && currentChainId !== chainId) {
196
- const chain = await this.switchChain?.({ chainId }).catch(() => ({
197
- id: currentChainId,
198
- }))
199
- currentChainId = chain?.id ?? currentChainId
200
- }
201
-
202
- // Add shim to storage signalling connector is connected
203
- if (shimDisconnect)
204
- await config.storage?.setItem(`${this.id}.connected`, true)
205
-
206
- return { accounts, chainId: currentChainId }
207
- } catch (error) {
208
- if ((error as ProviderRpcError).code === 4_001)
209
- throw new UserRejectedRequestError(error as RpcError)
210
- if ((error as RpcError).code === -32_002)
211
- throw new ResourceUnavailableRpcError(error as RpcError)
212
- throw error
213
- }
214
- },
215
- async disconnect() {
216
- const provider = await this.getProvider()
217
- if (!provider) throw new ProviderNotFoundError()
218
-
219
- provider.removeListener(
220
- 'accountsChanged',
221
- this.onAccountsChanged.bind(this),
222
- )
223
- provider.removeListener('chainChanged', this.onChainChanged)
224
- provider.removeListener('disconnect', this.onDisconnect.bind(this))
225
- provider.on('connect', this.onConnect.bind(this))
226
-
227
- // Remove shim signalling connector is disconnected
228
- if (shimDisconnect)
229
- await config.storage?.removeItem(`${this.id}.connected`)
230
- },
231
- async getAccounts() {
232
- const provider = await this.getProvider()
233
- if (!provider) throw new ProviderNotFoundError()
234
- const accounts = await provider.request({ method: 'eth_accounts' })
235
- return accounts.map(getAddress)
236
- },
237
- async getChainId() {
238
- const provider = await this.getProvider()
239
- if (!provider) throw new ProviderNotFoundError()
240
- const hexChainId = await provider.request({ method: 'eth_chainId' })
241
- return normalizeChainId(hexChainId)
242
- },
243
- async getProvider() {
244
- if (typeof window === 'undefined') return undefined
245
- const windowProvider = getWindowProvider()
246
- if (typeof windowProvider.provider === 'function')
247
- return windowProvider.provider(window as Window | undefined)
248
- return findProvider(window as Window | undefined, () => true)
249
- },
250
- async isAuthorized() {
251
- try {
252
- const isDisconnected =
253
- shimDisconnect &&
254
- // If shim does not exist in storage, connector is disconnected
255
- !(await config.storage?.getItem(`${this.id}.connected`))
256
- if (isDisconnected) return false
257
-
258
- const provider = await this.getProvider()
259
- if (!provider) {
260
- if (
261
- unstable_shimAsyncInject !== undefined &&
262
- unstable_shimAsyncInject !== false
263
- ) {
264
- // If no provider is found, check for async injection
265
- // https://github.com/wagmi-dev/references/issues/167
266
- // https://github.com/MetaMask/detect-provider
267
- const handleEthereum = async () => {
268
- if (typeof window !== 'undefined')
269
- window.removeEventListener(
270
- 'ethereum#initialized',
271
- handleEthereum,
272
- )
273
- const provider = await this.getProvider()
274
- return !!provider
275
- }
276
- const timeout =
277
- typeof unstable_shimAsyncInject === 'number'
278
- ? unstable_shimAsyncInject
279
- : 1_000
280
- const res = await Promise.race([
281
- ...(typeof window !== 'undefined'
282
- ? [
283
- new Promise<boolean>((resolve) =>
284
- window.addEventListener(
285
- 'ethereum#initialized',
286
- () => resolve(handleEthereum()),
287
- { once: true },
288
- ),
289
- ),
290
- ]
291
- : []),
292
- new Promise<boolean>((resolve) =>
293
- setTimeout(() => resolve(handleEthereum()), timeout),
294
- ),
295
- ])
296
- if (res) return true
297
- }
298
-
299
- throw new ProviderNotFoundError()
300
- }
301
- const accounts = await this.getAccounts()
302
- return !!accounts.length
303
- } catch {
304
- return false
305
- }
306
- },
307
- async switchChain({ chainId }) {
308
- const provider = await this.getProvider()
309
- if (!provider) throw new ProviderNotFoundError()
310
-
311
- const chain = config.chains.find((x) => x.id === chainId)
312
- if (!chain) throw new SwitchChainError(new ChainNotConfiguredError())
313
-
314
- const id = numberToHex(chainId)
315
-
316
- try {
317
- await Promise.all([
318
- provider.request({
319
- method: 'wallet_switchEthereumChain',
320
- params: [{ chainId: id }],
321
- }),
322
- new Promise<void>((resolve) =>
323
- config.emitter.once('change', ({ chainId: currentChainId }) => {
324
- if (currentChainId === chainId) resolve()
325
- }),
326
- ),
327
- ])
328
- return chain
329
- } catch (error) {
330
- // Indicates chain is not added to provider
331
- if (
332
- (error as ProviderRpcError).code === 4902 ||
333
- // Unwrapping for MetaMask Mobile
334
- // https://github.com/MetaMask/metamask-mobile/issues/2944#issuecomment-976988719
335
- (error as ProviderRpcError<{ originalError?: { code: number } }>)
336
- ?.data?.originalError?.code === 4902
337
- ) {
338
- try {
339
- const { default: blockExplorer, ...blockExplorers } =
340
- chain.blockExplorers ?? {}
341
- let blockExplorerUrls: string[] = []
342
- if (blockExplorer)
343
- blockExplorerUrls = [
344
- blockExplorer.url,
345
- ...Object.values(blockExplorers).map((x) => x.url),
346
- ]
347
-
348
- await provider.request({
349
- method: 'wallet_addEthereumChain',
350
- params: [
351
- {
352
- chainId: id,
353
- chainName: chain.name,
354
- nativeCurrency: chain.nativeCurrency,
355
- rpcUrls: [chain.rpcUrls.public?.http[0] ?? ''],
356
- blockExplorerUrls,
357
- },
358
- ],
359
- })
360
-
361
- const currentChainId = await this.getChainId()
362
- if (currentChainId !== chainId)
363
- throw new UserRejectedRequestError(
364
- new Error('User rejected switch after adding network.'),
365
- )
366
-
367
- return chain
368
- } catch (error) {
369
- throw new UserRejectedRequestError(error as Error)
370
- }
371
- }
372
-
373
- if ((error as ProviderRpcError).code === 4_001)
374
- throw new UserRejectedRequestError(error as RpcError)
375
- throw new SwitchChainError(error as RpcError)
376
- }
377
- },
378
- async onAccountsChanged(accounts) {
379
- // Disconnect if there are no accounts
380
- if (accounts.length === 0) this.onDisconnect()
381
- // Connect if emitter is listening for connect event (e.g. is disconnected)
382
- else if (config.emitter.listenerCount('connect')) {
383
- const chainId = (await this.getChainId()).toString()
384
- this.onConnect({ chainId })
385
- }
386
- // Regular change event
387
- else config.emitter.emit('change', { accounts: accounts.map(getAddress) })
388
- },
389
- onChainChanged(chain) {
390
- const chainId = normalizeChainId(chain)
391
- config.emitter.emit('change', { chainId })
392
- },
393
- async onConnect(connectInfo) {
394
- const accounts = await this.getAccounts()
395
- if (accounts.length === 0) return
396
-
397
- const chainId = normalizeChainId(connectInfo.chainId)
398
- config.emitter.emit('connect', { accounts, chainId })
399
-
400
- const provider = await this.getProvider()
401
- if (provider) {
402
- provider.removeListener('connect', this.onConnect.bind(this))
403
- provider.on('accountsChanged', this.onAccountsChanged.bind(this))
404
- provider.on('chainChanged', this.onChainChanged)
405
- provider.on('disconnect', this.onDisconnect.bind(this))
406
- }
407
-
408
- // Add shim to storage signalling connector is connected
409
- if (shimDisconnect)
410
- await config.storage?.setItem(`${this.id}.connected`, true)
411
- },
412
- async onDisconnect(error) {
413
- const provider = await this.getProvider()
414
-
415
- // If MetaMask emits a `code: 1013` error, wait for reconnection before disconnecting
416
- // https://github.com/MetaMask/providers/pull/120
417
- if (error && (error as RpcError<1013>).code === 1013) {
418
- if (provider && !!(await this.getAccounts()).length) return
419
- }
420
-
421
- // No need to remove `shimDisconnectStorageKey` from storage because `onDisconnect` is typically
422
- // only called when the wallet is disconnected through the wallet's interface, meaning the wallet
423
- // actually disconnected and we don't need to simulate it.
424
- config.emitter.emit('disconnect')
425
-
426
- if (provider) {
427
- provider.removeListener(
428
- 'accountsChanged',
429
- this.onAccountsChanged.bind(this),
430
- )
431
- provider.removeListener('chainChanged', this.onChainChanged)
432
- provider.removeListener('disconnect', this.onDisconnect.bind(this))
433
- provider.on('connect', this.onConnect.bind(this))
434
- }
435
- },
436
- }))
437
- }
438
-
439
- export type TargetId = Evaluate<
440
- keyof WindowProviderFlags
441
- > extends `is${infer name}`
442
- ? name extends `${infer char}${infer rest}`
443
- ? `${Lowercase<char>}${rest}`
444
- : never
445
- : never
446
-
447
- type Target = {
448
- name: string
449
- provider:
450
- | keyof WindowProviderFlags
451
- | ((window?: Window | undefined) => WindowProvider | undefined)
452
- features?: readonly 'wallet_requestPermissions'[] | undefined
453
- }
454
- type TargetMap = { [_ in TargetId]?: Target | undefined }
455
-
456
- type WindowProviderFlags = {
457
- isApexWallet?: true | undefined
458
- isAvalanche?: true | undefined
459
- isBackpack?: true | undefined
460
- isBifrost?: true | undefined
461
- isBitKeep?: true | undefined
462
- isBitski?: true | undefined
463
- isBlockWallet?: true | undefined
464
- isBraveWallet?: true | undefined
465
- isCoinbaseWallet?: true | undefined
466
- isDawn?: true | undefined
467
- isEnkrypt?: true | undefined
468
- isExodus?: true | undefined
469
- isFrame?: true | undefined
470
- isFrontier?: true | undefined
471
- isGamestop?: true | undefined
472
- isHyperPay?: true | undefined
473
- isImToken?: true | undefined
474
- isKuCoinWallet?: true | undefined
475
- isMathWallet?: true | undefined
476
- isMetaMask?: true | undefined
477
- isOkxWallet?: true | undefined
478
- isOKExWallet?: true | undefined
479
- isOneInchAndroidWallet?: true | undefined
480
- isOneInchIOSWallet?: true | undefined
481
- isOpera?: true | undefined
482
- isPhantom?: true | undefined
483
- isPortal?: true | undefined
484
- isRabby?: true | undefined
485
- isRainbow?: true | undefined
486
- isStatus?: true | undefined
487
- isTally?: true | undefined
488
- isTokenPocket?: true | undefined
489
- isTokenary?: true | undefined
490
- isTrust?: true | undefined
491
- isTrustWallet?: true | undefined
492
- isXDEFI?: true | undefined
493
- isZerion?: true | undefined
494
- }
495
-
496
- type WindowProvider = Evaluate<
497
- EIP1193Provider &
498
- WindowProviderFlags & {
499
- providers?: WindowProvider[] | undefined
500
- /** Only exists in MetaMask as of 2022/04/03 */
501
- _events?: { connect?: (() => void) | undefined } | undefined
502
- /** Only exists in MetaMask as of 2022/04/03 */
503
- _state?:
504
- | {
505
- accounts?: string[]
506
- initialized?: boolean
507
- isConnected?: boolean
508
- isPermanentlyDisconnected?: boolean
509
- isUnlocked?: boolean
510
- }
511
- | undefined
512
- }
513
- >
514
-
515
- type Window = {
516
- coinbaseWalletExtension?: WindowProvider | undefined
517
- ethereum?: WindowProvider | undefined
518
- phantom?: { ethereum: WindowProvider } | undefined
519
- }
520
-
521
- function findProvider(
522
- window: Window | undefined,
523
- condition:
524
- | keyof WindowProviderFlags
525
- | ((provider: WindowProvider) => boolean),
526
- ) {
527
- function isProvider(provider: WindowProvider) {
528
- if (typeof condition === 'function') return condition(provider)
529
- return provider[condition]
530
- }
531
- if (window?.ethereum?.providers)
532
- return window.ethereum.providers.find((provider) => isProvider(provider))
533
- if (window?.ethereum && isProvider(window.ethereum)) return window.ethereum
534
- return undefined
535
- }