@wagmi/connectors 4.0.0-alpha.1 → 4.0.0-alpha.3

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/src/injected.ts CHANGED
@@ -31,6 +31,7 @@ export type InjectedParameters = {
31
31
  */
32
32
  target?:
33
33
  | TargetId
34
+ | (TargetMap[TargetId] & { id: string })
34
35
  | (() => (TargetMap[TargetId] & { id: string }) | undefined)
35
36
  | undefined
36
37
  }
@@ -46,18 +47,14 @@ const targetMap = {
46
47
  metaMask: {
47
48
  name: 'MetaMask',
48
49
  provider(window) {
49
- return findProvider(window, (windowProvider) => {
50
- if (!windowProvider.isMetaMask) return false
50
+ return findProvider(window, (provider) => {
51
+ if (!provider.isMetaMask) return false
51
52
  // Brave tries to make itself look like MetaMask
52
53
  // Could also try RPC `web3_clientVersion` if following is unreliable
53
- if (
54
- windowProvider.isBraveWallet &&
55
- !windowProvider._events &&
56
- !windowProvider._state
57
- )
54
+ if (provider.isBraveWallet && !provider._events && !provider._state)
58
55
  return false
59
56
  // Other wallets that try to look like MetaMask
60
- const flags: (keyof WindowProviderFlags)[] = [
57
+ const flags: WalletProviderFlags[] = [
61
58
  'isApexWallet',
62
59
  'isAvalanche',
63
60
  'isBitKeep',
@@ -75,11 +72,10 @@ const targetMap = {
75
72
  'isTokenary',
76
73
  'isZerion',
77
74
  ]
78
- for (const flag of flags) if (windowProvider[flag]) return false
75
+ for (const flag of flags) if (provider[flag]) return false
79
76
  return true
80
77
  })
81
78
  },
82
- features: ['wallet_requestPermissions'],
83
79
  },
84
80
  phantom: {
85
81
  name: 'Phantom',
@@ -91,15 +87,17 @@ const targetMap = {
91
87
  } as const satisfies TargetMap
92
88
 
93
89
  export function injected(parameters: InjectedParameters = {}) {
94
- const shimDisconnect = parameters.shimDisconnect ?? true
95
- const unstable_shimAsyncInject = parameters.unstable_shimAsyncInject
90
+ const { shimDisconnect = true, unstable_shimAsyncInject } = parameters
96
91
 
97
- function getWindowProvider(): TargetMap[TargetId] & { id: string } {
92
+ function getTarget(): Evaluate<TargetMap[TargetId] & { id: string }> {
98
93
  const target = parameters.target
99
94
  if (typeof target === 'function') {
100
95
  const result = target()
101
96
  if (result) return result
102
97
  }
98
+
99
+ if (typeof target === 'object') return target
100
+
103
101
  if (typeof target === 'string')
104
102
  return {
105
103
  ...(targetMap[target as keyof typeof targetMap] ?? {
@@ -108,6 +106,7 @@ export function injected(parameters: InjectedParameters = {}) {
108
106
  }),
109
107
  id: target,
110
108
  }
109
+
111
110
  return {
112
111
  id: 'injected',
113
112
  name: 'Injected',
@@ -117,7 +116,7 @@ export function injected(parameters: InjectedParameters = {}) {
117
116
  }
118
117
  }
119
118
 
120
- type Provider = WindowProvider | undefined
119
+ type Provider = WalletProvider | undefined
121
120
  type Properties = {
122
121
  onConnect(connectInfo: ProviderConnectInfo): void
123
122
  }
@@ -125,10 +124,10 @@ export function injected(parameters: InjectedParameters = {}) {
125
124
 
126
125
  return createConnector<Provider, Properties, StorageItem>((config) => ({
127
126
  get id() {
128
- return getWindowProvider().id
127
+ return getTarget().id
129
128
  },
130
129
  get name() {
131
- return getWindowProvider().name
130
+ return getTarget().name
132
131
  },
133
132
  async setup() {
134
133
  const provider = await this.getProvider()
@@ -142,47 +141,41 @@ export function injected(parameters: InjectedParameters = {}) {
142
141
  const provider = await this.getProvider()
143
142
  if (!provider) throw new ProviderNotFoundError()
144
143
 
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
- }
144
+ // Attempt to show select prompt with `wallet_requestPermissions` when
145
+ // `shimDisconnect` is active and account is in disconnected state (flag in storage)
146
+ const isDisconnected =
147
+ shimDisconnect &&
148
+ !(await config.storage?.getItem(`${this.id}.connected`))
149
+
150
+ let accounts: readonly Address[] | null = null
151
+ if (isDisconnected) {
152
+ accounts = await this.getAccounts().catch(() => null)
153
+ const isAuthorized = !!accounts?.length
154
+ if (isAuthorized)
155
+ // Attempt to show another prompt for selecting connector if already connected
156
+ try {
157
+ const permissions = await provider.request({
158
+ method: 'wallet_requestPermissions',
159
+ params: [{ eth_accounts: {} }],
160
+ })
161
+ accounts = permissions[0]?.caveats?.[0]?.value?.map(getAddress)
162
+ } catch (err) {
163
+ const error = err as RpcError
164
+ // Not all injected providers support `wallet_requestPermissions` (e.g. MetaMask iOS).
165
+ // Only bubble up error if user rejects request
166
+ if (error.code === UserRejectedRequestError.code)
167
+ throw new UserRejectedRequestError(error)
168
+ // Or prompt is already open
169
+ if (error.code === ResourceUnavailableRpcError.code) throw error
170
+ }
171
+ }
180
172
 
173
+ try {
181
174
  if (!accounts?.length) {
182
- const accounts_ = await provider.request({
175
+ const requestedAccounts = await provider.request({
183
176
  method: 'eth_requestAccounts',
184
177
  })
185
- accounts = accounts_.map(getAddress)
178
+ accounts = requestedAccounts.map(getAddress)
186
179
  }
187
180
 
188
181
  provider.removeListener('connect', this.onConnect.bind(this))
@@ -204,11 +197,12 @@ export function injected(parameters: InjectedParameters = {}) {
204
197
  await config.storage?.setItem(`${this.id}.connected`, true)
205
198
 
206
199
  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)
200
+ } catch (err) {
201
+ const error = err as RpcError
202
+ if (error.code === UserRejectedRequestError.code)
203
+ throw new UserRejectedRequestError(error)
204
+ if (error.code === ResourceUnavailableRpcError.code)
205
+ throw new ResourceUnavailableRpcError(error)
212
206
  throw error
213
207
  }
214
208
  },
@@ -242,10 +236,10 @@ export function injected(parameters: InjectedParameters = {}) {
242
236
  },
243
237
  async getProvider() {
244
238
  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)
239
+ const target = getTarget()
240
+ if (typeof target.provider === 'function')
241
+ return target.provider(window as Window | undefined)
242
+ return findProvider(window, target.provider)
249
243
  },
250
244
  async isAuthorized() {
251
245
  try {
@@ -298,6 +292,7 @@ export function injected(parameters: InjectedParameters = {}) {
298
292
 
299
293
  throw new ProviderNotFoundError()
300
294
  }
295
+
301
296
  const accounts = await this.getAccounts()
302
297
  return !!accounts.length
303
298
  } catch {
@@ -326,10 +321,12 @@ export function injected(parameters: InjectedParameters = {}) {
326
321
  ),
327
322
  ])
328
323
  return chain
329
- } catch (error) {
324
+ } catch (err) {
325
+ const error = err as RpcError
326
+
330
327
  // Indicates chain is not added to provider
331
328
  if (
332
- (error as ProviderRpcError).code === 4902 ||
329
+ error.code === 4902 ||
333
330
  // Unwrapping for MetaMask Mobile
334
331
  // https://github.com/MetaMask/metamask-mobile/issues/2944#issuecomment-976988719
335
332
  (error as ProviderRpcError<{ originalError?: { code: number } }>)
@@ -370,9 +367,9 @@ export function injected(parameters: InjectedParameters = {}) {
370
367
  }
371
368
  }
372
369
 
373
- if ((error as ProviderRpcError).code === 4_001)
374
- throw new UserRejectedRequestError(error as RpcError)
375
- throw new SwitchChainError(error as RpcError)
370
+ if (error.code === UserRejectedRequestError.code)
371
+ throw new UserRejectedRequestError(error)
372
+ throw new SwitchChainError(error)
376
373
  }
377
374
  },
378
375
  async onAccountsChanged(accounts) {
@@ -436,100 +433,99 @@ export function injected(parameters: InjectedParameters = {}) {
436
433
  }))
437
434
  }
438
435
 
439
- export type TargetId = Evaluate<
440
- keyof WindowProviderFlags
441
- > extends `is${infer name}`
436
+ type Target = {
437
+ name: string
438
+ provider:
439
+ | WalletProviderFlags
440
+ | ((window?: Window | undefined) => WalletProvider | undefined)
441
+ }
442
+
443
+ export type TargetId = Evaluate<WalletProviderFlags> extends `is${infer name}`
442
444
  ? name extends `${infer char}${infer rest}`
443
445
  ? `${Lowercase<char>}${rest}`
444
446
  : never
445
447
  : never
446
448
 
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
449
  type TargetMap = { [_ in TargetId]?: Target | undefined }
455
450
 
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
- }
451
+ type WalletProviderFlags =
452
+ | 'isApexWallet'
453
+ | 'isAvalanche'
454
+ | 'isBackpack'
455
+ | 'isBifrost'
456
+ | 'isBitKeep'
457
+ | 'isBitski'
458
+ | 'isBlockWallet'
459
+ | 'isBraveWallet'
460
+ | 'isCoinbaseWallet'
461
+ | 'isDawn'
462
+ | 'isEnkrypt'
463
+ | 'isExodus'
464
+ | 'isFrame'
465
+ | 'isFrontier'
466
+ | 'isGamestop'
467
+ | 'isHyperPay'
468
+ | 'isImToken'
469
+ | 'isKuCoinWallet'
470
+ | 'isMathWallet'
471
+ | 'isMetaMask'
472
+ | 'isOkxWallet'
473
+ | 'isOKExWallet'
474
+ | 'isOneInchAndroidWallet'
475
+ | 'isOneInchIOSWallet'
476
+ | 'isOpera'
477
+ | 'isPhantom'
478
+ | 'isPortal'
479
+ | 'isRabby'
480
+ | 'isRainbow'
481
+ | 'isStatus'
482
+ | 'isTally'
483
+ | 'isTokenPocket'
484
+ | 'isTokenary'
485
+ | 'isTrust'
486
+ | 'isTrustWallet'
487
+ | 'isXDEFI'
488
+ | 'isZerion'
489
+
490
+ type WalletProvider = Evaluate<
491
+ EIP1193Provider & {
492
+ [key in WalletProviderFlags]?: true | undefined
493
+ } & {
494
+ providers?: WalletProvider[] | undefined
495
+ /** Only exists in MetaMask as of 2022/04/03 */
496
+ _events?: { connect?: (() => void) | undefined } | undefined
497
+ /** Only exists in MetaMask as of 2022/04/03 */
498
+ _state?:
499
+ | {
500
+ accounts?: string[]
501
+ initialized?: boolean
502
+ isConnected?: boolean
503
+ isPermanentlyDisconnected?: boolean
504
+ isUnlocked?: boolean
505
+ }
506
+ | undefined
507
+ }
513
508
  >
514
509
 
515
510
  type Window = {
516
- coinbaseWalletExtension?: WindowProvider | undefined
517
- ethereum?: WindowProvider | undefined
518
- phantom?: { ethereum: WindowProvider } | undefined
511
+ coinbaseWalletExtension?: WalletProvider | undefined
512
+ ethereum?: WalletProvider | undefined
513
+ phantom?: { ethereum: WalletProvider } | undefined
519
514
  }
520
515
 
521
516
  function findProvider(
522
- window: Window | undefined,
523
- condition:
524
- | keyof WindowProviderFlags
525
- | ((provider: WindowProvider) => boolean),
517
+ window: globalThis.Window | Window | undefined,
518
+ select?: WalletProviderFlags | ((provider: WalletProvider) => boolean),
526
519
  ) {
527
- function isProvider(provider: WindowProvider) {
528
- if (typeof condition === 'function') return condition(provider)
529
- return provider[condition]
520
+ function isProvider(provider: WalletProvider) {
521
+ if (typeof select === 'function') return select(provider)
522
+ if (typeof select === 'string') return provider[select]
523
+ return true
530
524
  }
531
- if (window?.ethereum?.providers)
532
- return window.ethereum.providers.find((provider) => isProvider(provider))
533
- if (window?.ethereum && isProvider(window.ethereum)) return window.ethereum
525
+
526
+ const ethereum = (window as Window).ethereum
527
+ if (ethereum?.providers)
528
+ return ethereum.providers.find((provider) => isProvider(provider))
529
+ if (ethereum && isProvider(ethereum)) return ethereum
534
530
  return undefined
535
531
  }
package/src/ledger.ts CHANGED
@@ -41,7 +41,7 @@ export function ledger(parameters: LedgerParameters = {}) {
41
41
  id: 'ledger',
42
42
  name: 'Ledger',
43
43
  async setup() {
44
- const provider = await this.getProvider()
44
+ const provider = await this.getProvider().catch(() => null)
45
45
  if (!provider) return
46
46
  provider.on('connect', this.onConnect.bind(this))
47
47
  provider.on('session_delete', this.onSessionDelete.bind(this))
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '4.0.0-alpha.1'
1
+ export const version = '4.0.0-alpha.3'
@@ -105,7 +105,7 @@ export function walletConnect(parameters: WalletConnectParameters) {
105
105
  id: 'walletConnect',
106
106
  name: 'WalletConnect',
107
107
  async setup() {
108
- const provider = await this.getProvider()
108
+ const provider = await this.getProvider().catch(() => null)
109
109
  if (!provider) return
110
110
  provider.on('connect', this.onConnect.bind(this))
111
111
  provider.on('session_delete', this.onSessionDelete.bind(this))
@@ -173,21 +173,21 @@ export function walletConnect(parameters: WalletConnectParameters) {
173
173
  async disconnect() {
174
174
  const provider = await this.getProvider()
175
175
  try {
176
- await provider.disconnect()
176
+ await provider?.disconnect()
177
177
  } catch (error) {
178
178
  if (!/No matching key/i.test((error as Error).message)) throw error
179
179
  } finally {
180
- provider.removeListener(
180
+ provider?.removeListener(
181
181
  'accountsChanged',
182
182
  this.onAccountsChanged.bind(this),
183
183
  )
184
- provider.removeListener('chainChanged', this.onChainChanged)
185
- provider.removeListener('disconnect', this.onDisconnect.bind(this))
186
- provider.removeListener(
184
+ provider?.removeListener('chainChanged', this.onChainChanged)
185
+ provider?.removeListener('disconnect', this.onDisconnect.bind(this))
186
+ provider?.removeListener(
187
187
  'session_delete',
188
188
  this.onSessionDelete.bind(this),
189
189
  )
190
- provider.on('connect', this.onConnect.bind(this))
190
+ provider?.on('connect', this.onConnect.bind(this))
191
191
 
192
192
  this.setRequestedChainsIds([])
193
193
  }