@wagmi/connectors 7.2.0 → 8.0.0
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/metaMask.js +116 -286
- package/dist/esm/metaMask.js.map +1 -1
- package/dist/esm/tsconfig.build.tsbuildinfo +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/types/metaMask.d.ts +27 -5
- package/dist/types/metaMask.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +4 -4
- package/src/metaMask.ts +147 -347
- package/src/version.ts +1 -1
package/src/metaMask.ts
CHANGED
|
@@ -1,32 +1,15 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from '@
|
|
2
|
+
createEVMClient,
|
|
3
|
+
EIP1193Provider,
|
|
4
|
+
MetamaskConnectEVM,
|
|
5
|
+
} from '@metamask/connect-evm'
|
|
6
|
+
import { ChainNotConfiguredError, createConnector } from '@wagmi/core'
|
|
7
|
+
import type { ExactPartial, OneOf, UnionCompute } from '@wagmi/core/internal'
|
|
7
8
|
import {
|
|
8
|
-
ChainNotConfiguredError,
|
|
9
|
-
type Connector,
|
|
10
|
-
createConnector,
|
|
11
|
-
extractRpcUrls,
|
|
12
|
-
ProviderNotFoundError,
|
|
13
|
-
} from '@wagmi/core'
|
|
14
|
-
import type {
|
|
15
|
-
Compute,
|
|
16
|
-
ExactPartial,
|
|
17
|
-
OneOf,
|
|
18
|
-
RemoveUndefined,
|
|
19
|
-
UnionCompute,
|
|
20
|
-
} from '@wagmi/core/internal'
|
|
21
|
-
import {
|
|
22
|
-
type AddEthereumChainParameter,
|
|
23
9
|
type Address,
|
|
24
10
|
getAddress,
|
|
25
|
-
type Hex,
|
|
26
|
-
hexToNumber,
|
|
27
11
|
numberToHex,
|
|
28
12
|
type ProviderConnectInfo,
|
|
29
|
-
type ProviderRpcError,
|
|
30
13
|
ResourceUnavailableRpcError,
|
|
31
14
|
type RpcError,
|
|
32
15
|
SwitchChainError,
|
|
@@ -36,8 +19,22 @@ import {
|
|
|
36
19
|
} from 'viem'
|
|
37
20
|
|
|
38
21
|
export type MetaMaskParameters = UnionCompute<
|
|
39
|
-
|
|
40
|
-
|
|
22
|
+
ExactPartial<Omit<CreateEVMClientParameters, 'api' | 'eventHandlers'>> & {
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated Use `dapp` instead.
|
|
25
|
+
*
|
|
26
|
+
* Metadata is used to fill details for the UX on confirmation screens in MetaMask.
|
|
27
|
+
*/
|
|
28
|
+
dappMetadata?: { name?: string; url?: string; iconUrl?: string } | undefined
|
|
29
|
+
/**
|
|
30
|
+
* @deprecated Use `debug` instead.
|
|
31
|
+
*/
|
|
32
|
+
logging?: { sdk?: boolean } | undefined
|
|
33
|
+
/**
|
|
34
|
+
* @deprecated Use `ui.headless` instead.
|
|
35
|
+
*/
|
|
36
|
+
headless?: boolean | undefined
|
|
37
|
+
} & OneOf<
|
|
41
38
|
| {
|
|
42
39
|
/* Shortcut to connect and sign a message */
|
|
43
40
|
connectAndSign?: string | undefined
|
|
@@ -50,66 +47,28 @@ export type MetaMaskParameters = UnionCompute<
|
|
|
50
47
|
>
|
|
51
48
|
>
|
|
52
49
|
|
|
53
|
-
type
|
|
54
|
-
ExactPartial<
|
|
55
|
-
Omit<
|
|
56
|
-
MetaMaskSDKOptions,
|
|
57
|
-
| '_source'
|
|
58
|
-
| 'forceDeleteProvider'
|
|
59
|
-
| 'forceInjectProvider'
|
|
60
|
-
| 'injectProvider'
|
|
61
|
-
| 'useDeeplink'
|
|
62
|
-
| 'readonlyRPCMap'
|
|
63
|
-
>
|
|
64
|
-
>
|
|
65
|
-
>
|
|
50
|
+
type CreateEVMClientParameters = Parameters<typeof createEVMClient>[0]
|
|
66
51
|
|
|
67
52
|
metaMask.type = 'metaMask' as const
|
|
68
53
|
export function metaMask(parameters: MetaMaskParameters = {}) {
|
|
69
|
-
type Provider =
|
|
54
|
+
type Provider = EIP1193Provider
|
|
70
55
|
type Properties = {
|
|
71
56
|
onConnect(connectInfo: ProviderConnectInfo): void
|
|
72
57
|
onDisplayUri(uri: string): void
|
|
58
|
+
getInstance(): Promise<MetamaskConnectEVM>
|
|
73
59
|
}
|
|
74
|
-
type Listener = Parameters<Provider['on']>[1]
|
|
75
|
-
|
|
76
|
-
let sdk: MetaMaskSDK
|
|
77
|
-
let provider: Provider | undefined
|
|
78
|
-
let providerPromise: Promise<typeof provider>
|
|
79
60
|
|
|
80
|
-
let
|
|
81
|
-
let
|
|
82
|
-
let connect: Connector['onConnect'] | undefined
|
|
83
|
-
let displayUri: ((uri: string) => void) | undefined
|
|
84
|
-
let disconnect: Connector['onDisconnect'] | undefined
|
|
61
|
+
let metamask: MetamaskConnectEVM | undefined
|
|
62
|
+
let metamaskPromise: Promise<MetamaskConnectEVM> | undefined
|
|
85
63
|
|
|
86
64
|
return createConnector<Provider, Properties>((config) => ({
|
|
87
65
|
id: 'metaMaskSDK',
|
|
88
66
|
name: 'MetaMask',
|
|
89
67
|
rdns: ['io.metamask', 'io.metamask.mobile'],
|
|
90
68
|
type: metaMask.type,
|
|
91
|
-
async setup() {
|
|
92
|
-
const provider = await this.getProvider()
|
|
93
|
-
if (provider?.on) {
|
|
94
|
-
if (!connect) {
|
|
95
|
-
connect = this.onConnect.bind(this)
|
|
96
|
-
provider.on('connect', connect as Listener)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// We shouldn't need to listen for `'accountsChanged'` here since the `'connect'` event should suffice (and wallet shouldn't be connected yet).
|
|
100
|
-
// Some wallets, like MetaMask, do not implement the `'connect'` event and overload `'accountsChanged'` instead.
|
|
101
|
-
if (!accountsChanged) {
|
|
102
|
-
accountsChanged = this.onAccountsChanged.bind(this)
|
|
103
|
-
provider.on('accountsChanged', accountsChanged as Listener)
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
69
|
async connect({ chainId, isReconnecting, withCapabilities } = {}) {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
displayUri = this.onDisplayUri
|
|
111
|
-
provider.on('display_uri', displayUri as Listener)
|
|
112
|
-
}
|
|
70
|
+
const instance = await this.getInstance()
|
|
71
|
+
const provider = instance.getProvider()
|
|
113
72
|
|
|
114
73
|
let accounts: readonly Address[] = []
|
|
115
74
|
if (isReconnecting) accounts = await this.getAccounts().catch(() => [])
|
|
@@ -118,25 +77,28 @@ export function metaMask(parameters: MetaMaskParameters = {}) {
|
|
|
118
77
|
let signResponse: string | undefined
|
|
119
78
|
let connectWithResponse: unknown | undefined
|
|
120
79
|
if (!accounts?.length) {
|
|
80
|
+
const chainIds = config.chains.map((chain) => numberToHex(chain.id))
|
|
121
81
|
if (parameters.connectAndSign || parameters.connectWith) {
|
|
122
82
|
if (parameters.connectAndSign)
|
|
123
|
-
signResponse = await
|
|
124
|
-
|
|
83
|
+
signResponse = await instance.connectAndSign({
|
|
84
|
+
chainIds,
|
|
85
|
+
message: parameters.connectAndSign,
|
|
125
86
|
})
|
|
126
87
|
else if (parameters.connectWith)
|
|
127
|
-
connectWithResponse = await
|
|
88
|
+
connectWithResponse = await instance.connectWith({
|
|
89
|
+
chainIds,
|
|
128
90
|
method: parameters.connectWith.method,
|
|
129
91
|
params: parameters.connectWith.params,
|
|
130
92
|
})
|
|
131
93
|
|
|
132
94
|
accounts = await this.getAccounts()
|
|
133
95
|
} else {
|
|
134
|
-
const
|
|
135
|
-
accounts =
|
|
96
|
+
const result = await instance.connect({ chainIds })
|
|
97
|
+
accounts = result.accounts.map((x) => getAddress(x))
|
|
136
98
|
}
|
|
137
99
|
}
|
|
138
100
|
// Switch to chain if provided
|
|
139
|
-
let currentChainId =
|
|
101
|
+
let currentChainId = await this.getChainId()
|
|
140
102
|
if (chainId && currentChainId !== chainId) {
|
|
141
103
|
const chain = await this.switchChain!({ chainId }).catch((error) => {
|
|
142
104
|
if (error.code === UserRejectedRequestError.code) throw error
|
|
@@ -145,43 +107,19 @@ export function metaMask(parameters: MetaMaskParameters = {}) {
|
|
|
145
107
|
currentChainId = chain?.id ?? currentChainId
|
|
146
108
|
}
|
|
147
109
|
|
|
148
|
-
if (displayUri) {
|
|
149
|
-
provider.removeListener('display_uri', displayUri)
|
|
150
|
-
displayUri = undefined
|
|
151
|
-
}
|
|
152
|
-
|
|
153
110
|
if (signResponse)
|
|
154
111
|
provider.emit('connectAndSign', {
|
|
155
112
|
accounts,
|
|
156
|
-
chainId: currentChainId,
|
|
113
|
+
chainId: numberToHex(currentChainId),
|
|
157
114
|
signResponse,
|
|
158
115
|
})
|
|
159
116
|
else if (connectWithResponse)
|
|
160
117
|
provider.emit('connectWith', {
|
|
161
118
|
accounts,
|
|
162
|
-
chainId: currentChainId,
|
|
119
|
+
chainId: numberToHex(currentChainId),
|
|
163
120
|
connectWithResponse,
|
|
164
121
|
})
|
|
165
122
|
|
|
166
|
-
// Manage EIP-1193 event listeners
|
|
167
|
-
// https://eips.ethereum.org/EIPS/eip-1193#events
|
|
168
|
-
if (connect) {
|
|
169
|
-
provider.removeListener('connect', connect)
|
|
170
|
-
connect = undefined
|
|
171
|
-
}
|
|
172
|
-
if (!accountsChanged) {
|
|
173
|
-
accountsChanged = this.onAccountsChanged.bind(this)
|
|
174
|
-
provider.on('accountsChanged', accountsChanged as Listener)
|
|
175
|
-
}
|
|
176
|
-
if (!chainChanged) {
|
|
177
|
-
chainChanged = this.onChainChanged.bind(this)
|
|
178
|
-
provider.on('chainChanged', chainChanged as Listener)
|
|
179
|
-
}
|
|
180
|
-
if (!disconnect) {
|
|
181
|
-
disconnect = this.onDisconnect.bind(this)
|
|
182
|
-
provider.on('disconnect', disconnect as Listener)
|
|
183
|
-
}
|
|
184
|
-
|
|
185
123
|
return {
|
|
186
124
|
// TODO(v3): Make `withCapabilities: true` default behavior
|
|
187
125
|
accounts: (withCapabilities
|
|
@@ -199,140 +137,82 @@ export function metaMask(parameters: MetaMaskParameters = {}) {
|
|
|
199
137
|
}
|
|
200
138
|
},
|
|
201
139
|
async disconnect() {
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
// Manage EIP-1193 event listeners
|
|
205
|
-
if (chainChanged) {
|
|
206
|
-
provider.removeListener('chainChanged', chainChanged)
|
|
207
|
-
chainChanged = undefined
|
|
208
|
-
}
|
|
209
|
-
if (disconnect) {
|
|
210
|
-
provider.removeListener('disconnect', disconnect)
|
|
211
|
-
disconnect = undefined
|
|
212
|
-
}
|
|
213
|
-
if (!connect) {
|
|
214
|
-
connect = this.onConnect.bind(this)
|
|
215
|
-
provider.on('connect', connect as Listener)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
await sdk.terminate()
|
|
140
|
+
const instance = await this.getInstance()
|
|
141
|
+
return instance.disconnect()
|
|
219
142
|
},
|
|
220
143
|
async getAccounts() {
|
|
221
|
-
const
|
|
144
|
+
const instance = await this.getInstance()
|
|
145
|
+
if (instance.accounts.length)
|
|
146
|
+
return instance.accounts.map((x) => getAddress(x))
|
|
147
|
+
// Fallback to provider if SDK doesn't return accounts
|
|
148
|
+
const provider = instance.getProvider()
|
|
222
149
|
const accounts = (await provider.request({
|
|
223
150
|
method: 'eth_accounts',
|
|
224
151
|
})) as string[]
|
|
225
152
|
return accounts.map((x) => getAddress(x))
|
|
226
153
|
},
|
|
227
154
|
async getChainId() {
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
155
|
+
const instance = await this.getInstance()
|
|
156
|
+
if (instance.getChainId()) return Number(instance.getChainId())
|
|
157
|
+
// Fallback to provider if SDK doesn't return chainId
|
|
158
|
+
const provider = instance.getProvider()
|
|
159
|
+
const chainId = await provider.request({ method: 'eth_chainId' })
|
|
232
160
|
return Number(chainId)
|
|
233
161
|
},
|
|
234
162
|
async getProvider() {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
// See: https://github.com/vitejs/vite/issues/9703
|
|
238
|
-
const MetaMaskSDK = await (async () => {
|
|
239
|
-
const { default: SDK } = await (() => {
|
|
240
|
-
// safe webpack optional peer dependency dynamic import
|
|
241
|
-
try {
|
|
242
|
-
return import('@metamask/sdk')
|
|
243
|
-
} catch {
|
|
244
|
-
throw new Error('dependency "@metamask/sdk" not found')
|
|
245
|
-
}
|
|
246
|
-
})()
|
|
247
|
-
if (typeof SDK !== 'function' && typeof SDK.default === 'function')
|
|
248
|
-
return SDK.default
|
|
249
|
-
return SDK as unknown as typeof SDK.default
|
|
250
|
-
})()
|
|
251
|
-
|
|
252
|
-
const readonlyRPCMap: RPC_URLS_MAP = {}
|
|
253
|
-
for (const chain of config.chains)
|
|
254
|
-
readonlyRPCMap[numberToHex(chain.id)] = extractRpcUrls({
|
|
255
|
-
chain,
|
|
256
|
-
transports: config.transports,
|
|
257
|
-
})?.[0]
|
|
258
|
-
|
|
259
|
-
sdk = new MetaMaskSDK({
|
|
260
|
-
// Workaround cast since MetaMask SDK does not support `'exactOptionalPropertyTypes'`
|
|
261
|
-
...(parameters as RemoveUndefined<typeof parameters>),
|
|
262
|
-
_source: 'wagmi',
|
|
263
|
-
forceDeleteProvider: false,
|
|
264
|
-
forceInjectProvider: false,
|
|
265
|
-
injectProvider: false,
|
|
266
|
-
readonlyRPCMap,
|
|
267
|
-
dappMetadata: {
|
|
268
|
-
...parameters.dappMetadata,
|
|
269
|
-
// Test if name and url are set AND not empty
|
|
270
|
-
name: parameters.dappMetadata?.name
|
|
271
|
-
? parameters.dappMetadata?.name
|
|
272
|
-
: 'wagmi',
|
|
273
|
-
url: parameters.dappMetadata?.url
|
|
274
|
-
? parameters.dappMetadata?.url
|
|
275
|
-
: typeof window !== 'undefined'
|
|
276
|
-
? window.location.origin
|
|
277
|
-
: 'https://wagmi.sh',
|
|
278
|
-
},
|
|
279
|
-
useDeeplink: true,
|
|
280
|
-
})
|
|
281
|
-
const result = await sdk.init()
|
|
282
|
-
// On initial load, sometimes `sdk.getProvider` does not return provider.
|
|
283
|
-
// https://github.com/wevm/wagmi/issues/4367
|
|
284
|
-
// Use result of `init` call if available.
|
|
285
|
-
const provider = (() => {
|
|
286
|
-
if (result?.activeProvider) return result.activeProvider
|
|
287
|
-
return sdk.getProvider()
|
|
288
|
-
})()
|
|
289
|
-
if (!provider) throw new ProviderNotFoundError()
|
|
290
|
-
return provider
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
if (!provider) {
|
|
294
|
-
if (!providerPromise) providerPromise = initProvider()
|
|
295
|
-
provider = await providerPromise
|
|
296
|
-
}
|
|
297
|
-
return provider!
|
|
163
|
+
const instance = await this.getInstance()
|
|
164
|
+
return instance.getProvider()
|
|
298
165
|
},
|
|
299
166
|
async isAuthorized() {
|
|
300
167
|
try {
|
|
301
168
|
// MetaMask mobile provider sometimes fails to immediately resolve
|
|
302
169
|
// JSON-RPC requests on page load
|
|
303
|
-
const timeout =
|
|
170
|
+
const timeout = 10
|
|
304
171
|
const accounts = await withRetry(
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
172
|
+
async () =>
|
|
173
|
+
withTimeout(
|
|
174
|
+
async () => {
|
|
175
|
+
const accounts = await this.getAccounts()
|
|
176
|
+
if (!accounts.length) throw new Error('try again')
|
|
177
|
+
return accounts
|
|
178
|
+
},
|
|
179
|
+
{ timeout },
|
|
180
|
+
),
|
|
181
|
+
{ delay: timeout + 1, retryCount: 3 },
|
|
310
182
|
)
|
|
311
|
-
return
|
|
183
|
+
return Boolean(accounts.length)
|
|
312
184
|
} catch {
|
|
313
185
|
return false
|
|
314
186
|
}
|
|
315
187
|
},
|
|
316
188
|
async switchChain({ addEthereumChainParameter, chainId }) {
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
const chain = config.chains.find((x) => x.id === chainId)
|
|
189
|
+
const chain = config.chains.find(({ id }) => id === Number(chainId))
|
|
320
190
|
if (!chain) throw new SwitchChainError(new ChainNotConfiguredError())
|
|
321
191
|
|
|
192
|
+
const hexChainId = numberToHex(chainId)
|
|
193
|
+
|
|
322
194
|
try {
|
|
323
|
-
await
|
|
324
|
-
|
|
325
|
-
|
|
195
|
+
const instance = await this.getInstance()
|
|
196
|
+
await instance.switchChain({
|
|
197
|
+
chainId: hexChainId,
|
|
198
|
+
chainConfiguration: {
|
|
199
|
+
blockExplorerUrls: addEthereumChainParameter?.blockExplorerUrls
|
|
200
|
+
? [...addEthereumChainParameter.blockExplorerUrls]
|
|
201
|
+
: chain.blockExplorers?.default.url
|
|
202
|
+
? [chain.blockExplorers.default.url]
|
|
203
|
+
: undefined,
|
|
204
|
+
chainId: hexChainId,
|
|
205
|
+
chainName: addEthereumChainParameter?.chainName ?? chain.name,
|
|
206
|
+
iconUrls: addEthereumChainParameter?.iconUrls,
|
|
207
|
+
nativeCurrency:
|
|
208
|
+
addEthereumChainParameter?.nativeCurrency ?? chain.nativeCurrency,
|
|
209
|
+
rpcUrls: addEthereumChainParameter?.rpcUrls
|
|
210
|
+
? [...addEthereumChainParameter.rpcUrls]
|
|
211
|
+
: chain.rpcUrls.default?.http
|
|
212
|
+
? [...chain.rpcUrls.default.http]
|
|
213
|
+
: undefined,
|
|
214
|
+
},
|
|
326
215
|
})
|
|
327
|
-
|
|
328
|
-
// During `'wallet_switchEthereumChain'`, MetaMask makes a `'net_version'` RPC call to the target chain.
|
|
329
|
-
// If this request fails, MetaMask does not emit the `'chainChanged'` event, but will still switch the chain.
|
|
330
|
-
// To counter this behavior, we request and emit the current chain ID to confirm the chain switch either via
|
|
331
|
-
// this callback or an externally emitted `'chainChanged'` event.
|
|
332
|
-
// https://github.com/MetaMask/metamask-extension/issues/24247
|
|
333
|
-
await waitForChainIdToSync()
|
|
334
|
-
await sendAndWaitForChangeEvent(chainId)
|
|
335
|
-
|
|
336
216
|
return chain
|
|
337
217
|
} catch (err) {
|
|
338
218
|
const error = err as RpcError
|
|
@@ -340,113 +220,13 @@ export function metaMask(parameters: MetaMaskParameters = {}) {
|
|
|
340
220
|
if (error.code === UserRejectedRequestError.code)
|
|
341
221
|
throw new UserRejectedRequestError(error)
|
|
342
222
|
|
|
343
|
-
// Indicates chain is not added to provider
|
|
344
|
-
if (
|
|
345
|
-
error.code === 4902 ||
|
|
346
|
-
// Unwrapping for MetaMask Mobile
|
|
347
|
-
// https://github.com/MetaMask/metamask-mobile/issues/2944#issuecomment-976988719
|
|
348
|
-
(error as ProviderRpcError<{ originalError?: { code: number } }>)
|
|
349
|
-
?.data?.originalError?.code === 4902
|
|
350
|
-
) {
|
|
351
|
-
try {
|
|
352
|
-
await provider.request({
|
|
353
|
-
method: 'wallet_addEthereumChain',
|
|
354
|
-
params: [
|
|
355
|
-
{
|
|
356
|
-
blockExplorerUrls: (() => {
|
|
357
|
-
const { default: blockExplorer, ...blockExplorers } =
|
|
358
|
-
chain.blockExplorers ?? {}
|
|
359
|
-
if (addEthereumChainParameter?.blockExplorerUrls)
|
|
360
|
-
return addEthereumChainParameter.blockExplorerUrls
|
|
361
|
-
if (blockExplorer)
|
|
362
|
-
return [
|
|
363
|
-
blockExplorer.url,
|
|
364
|
-
...Object.values(blockExplorers).map((x) => x.url),
|
|
365
|
-
]
|
|
366
|
-
return
|
|
367
|
-
})(),
|
|
368
|
-
chainId: numberToHex(chainId),
|
|
369
|
-
chainName: addEthereumChainParameter?.chainName ?? chain.name,
|
|
370
|
-
iconUrls: addEthereumChainParameter?.iconUrls,
|
|
371
|
-
nativeCurrency:
|
|
372
|
-
addEthereumChainParameter?.nativeCurrency ??
|
|
373
|
-
chain.nativeCurrency,
|
|
374
|
-
rpcUrls: (() => {
|
|
375
|
-
if (addEthereumChainParameter?.rpcUrls?.length)
|
|
376
|
-
return addEthereumChainParameter.rpcUrls
|
|
377
|
-
return [chain.rpcUrls.default?.http[0] ?? '']
|
|
378
|
-
})(),
|
|
379
|
-
} satisfies AddEthereumChainParameter,
|
|
380
|
-
],
|
|
381
|
-
})
|
|
382
|
-
|
|
383
|
-
await waitForChainIdToSync()
|
|
384
|
-
await sendAndWaitForChangeEvent(chainId)
|
|
385
|
-
|
|
386
|
-
return chain
|
|
387
|
-
} catch (err) {
|
|
388
|
-
const error = err as RpcError
|
|
389
|
-
if (error.code === UserRejectedRequestError.code)
|
|
390
|
-
throw new UserRejectedRequestError(error)
|
|
391
|
-
throw new SwitchChainError(error)
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
223
|
throw new SwitchChainError(error)
|
|
396
224
|
}
|
|
397
|
-
|
|
398
|
-
async function waitForChainIdToSync() {
|
|
399
|
-
// On mobile, there is a race condition between the result of `'wallet_addEthereumChain'` and `'eth_chainId'`.
|
|
400
|
-
// To avoid this, we wait for `'eth_chainId'` to return the expected chain ID with a retry loop.
|
|
401
|
-
await withRetry(
|
|
402
|
-
async () => {
|
|
403
|
-
const value = hexToNumber(
|
|
404
|
-
// `'eth_chainId'` is cached by the MetaMask SDK side to avoid unnecessary deeplinks
|
|
405
|
-
(await provider.request({ method: 'eth_chainId' })) as Hex,
|
|
406
|
-
)
|
|
407
|
-
// `value` doesn't match expected `chainId`, throw to trigger retry
|
|
408
|
-
if (value !== chainId)
|
|
409
|
-
throw new Error('User rejected switch after adding network.')
|
|
410
|
-
return value
|
|
411
|
-
},
|
|
412
|
-
{
|
|
413
|
-
delay: 50,
|
|
414
|
-
retryCount: 20, // android device encryption is slower
|
|
415
|
-
},
|
|
416
|
-
)
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
async function sendAndWaitForChangeEvent(chainId: number) {
|
|
420
|
-
await new Promise<void>((resolve) => {
|
|
421
|
-
const listener = ((data) => {
|
|
422
|
-
if ('chainId' in data && data.chainId === chainId) {
|
|
423
|
-
config.emitter.off('change', listener)
|
|
424
|
-
resolve()
|
|
425
|
-
}
|
|
426
|
-
}) satisfies Parameters<typeof config.emitter.on>[1]
|
|
427
|
-
config.emitter.on('change', listener)
|
|
428
|
-
config.emitter.emit('change', { chainId })
|
|
429
|
-
})
|
|
430
|
-
}
|
|
431
225
|
},
|
|
432
226
|
async onAccountsChanged(accounts) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
if (sdk.isExtensionActive()) this.onDisconnect()
|
|
437
|
-
// FIXME(upstream): Mobile app sometimes emits invalid `accountsChanged` event with empty accounts array
|
|
438
|
-
else return
|
|
439
|
-
}
|
|
440
|
-
// Connect if emitter is listening for connect event (e.g. is disconnected and connects through wallet interface)
|
|
441
|
-
else if (config.emitter.listenerCount('connect')) {
|
|
442
|
-
const chainId = (await this.getChainId()).toString()
|
|
443
|
-
this.onConnect({ chainId })
|
|
444
|
-
}
|
|
445
|
-
// Regular change event
|
|
446
|
-
else
|
|
447
|
-
config.emitter.emit('change', {
|
|
448
|
-
accounts: accounts.map((x) => getAddress(x)),
|
|
449
|
-
})
|
|
227
|
+
config.emitter.emit('change', {
|
|
228
|
+
accounts: accounts.map((x) => getAddress(x)),
|
|
229
|
+
})
|
|
450
230
|
},
|
|
451
231
|
onChainChanged(chain) {
|
|
452
232
|
const chainId = Number(chain)
|
|
@@ -458,52 +238,72 @@ export function metaMask(parameters: MetaMaskParameters = {}) {
|
|
|
458
238
|
|
|
459
239
|
const chainId = Number(connectInfo.chainId)
|
|
460
240
|
config.emitter.emit('connect', { accounts, chainId })
|
|
461
|
-
|
|
462
|
-
const provider = await this.getProvider()
|
|
463
|
-
if (connect) {
|
|
464
|
-
provider.removeListener('connect', connect)
|
|
465
|
-
connect = undefined
|
|
466
|
-
}
|
|
467
|
-
if (!accountsChanged) {
|
|
468
|
-
accountsChanged = this.onAccountsChanged.bind(this)
|
|
469
|
-
provider.on('accountsChanged', accountsChanged as Listener)
|
|
470
|
-
}
|
|
471
|
-
if (!chainChanged) {
|
|
472
|
-
chainChanged = this.onChainChanged.bind(this)
|
|
473
|
-
provider.on('chainChanged', chainChanged as Listener)
|
|
474
|
-
}
|
|
475
|
-
if (!disconnect) {
|
|
476
|
-
disconnect = this.onDisconnect.bind(this)
|
|
477
|
-
provider.on('disconnect', disconnect as Listener)
|
|
478
|
-
}
|
|
479
241
|
},
|
|
480
242
|
async onDisconnect(error) {
|
|
481
|
-
const provider = await this.getProvider()
|
|
482
|
-
|
|
483
243
|
// If MetaMask emits a `code: 1013` error, wait for reconnection before disconnecting
|
|
484
244
|
// https://github.com/MetaMask/providers/pull/120
|
|
485
245
|
if (error && (error as RpcError<1013>).code === 1013) {
|
|
486
|
-
|
|
246
|
+
const provider = await this.getProvider()
|
|
247
|
+
if (provider && Boolean((await this.getAccounts()).length)) return
|
|
487
248
|
}
|
|
488
249
|
|
|
489
250
|
config.emitter.emit('disconnect')
|
|
490
|
-
|
|
491
|
-
// Manage EIP-1193 event listeners
|
|
492
|
-
if (chainChanged) {
|
|
493
|
-
provider.removeListener('chainChanged', chainChanged)
|
|
494
|
-
chainChanged = undefined
|
|
495
|
-
}
|
|
496
|
-
if (disconnect) {
|
|
497
|
-
provider.removeListener('disconnect', disconnect)
|
|
498
|
-
disconnect = undefined
|
|
499
|
-
}
|
|
500
|
-
if (!connect) {
|
|
501
|
-
connect = this.onConnect.bind(this)
|
|
502
|
-
provider.on('connect', connect as Listener)
|
|
503
|
-
}
|
|
504
251
|
},
|
|
505
252
|
onDisplayUri(uri) {
|
|
506
253
|
config.emitter.emit('message', { type: 'display_uri', data: uri })
|
|
507
254
|
},
|
|
255
|
+
async getInstance() {
|
|
256
|
+
if (!metamask) {
|
|
257
|
+
if (!metamaskPromise) {
|
|
258
|
+
const { createEVMClient } = await (async () => {
|
|
259
|
+
try {
|
|
260
|
+
return import('@metamask/connect-evm')
|
|
261
|
+
} catch {
|
|
262
|
+
throw new Error('dependency "@metamask/connect-evm" not found')
|
|
263
|
+
}
|
|
264
|
+
})()
|
|
265
|
+
const defaultDappParams =
|
|
266
|
+
typeof window === 'undefined'
|
|
267
|
+
? { name: 'wagmi' }
|
|
268
|
+
: { name: window.location.hostname, url: window.location.href }
|
|
269
|
+
|
|
270
|
+
metamaskPromise = createEVMClient({
|
|
271
|
+
...parameters,
|
|
272
|
+
api: {
|
|
273
|
+
supportedNetworks: Object.fromEntries(
|
|
274
|
+
config.chains.map((chain) => [
|
|
275
|
+
numberToHex(chain.id),
|
|
276
|
+
chain.rpcUrls.default?.http[0] ?? '',
|
|
277
|
+
]),
|
|
278
|
+
),
|
|
279
|
+
},
|
|
280
|
+
dapp: parameters.dapp ?? {
|
|
281
|
+
...defaultDappParams,
|
|
282
|
+
...parameters.dappMetadata,
|
|
283
|
+
},
|
|
284
|
+
debug: parameters.debug ?? parameters.logging?.sdk,
|
|
285
|
+
eventHandlers: {
|
|
286
|
+
accountsChanged: this.onAccountsChanged.bind(this),
|
|
287
|
+
chainChanged: this.onChainChanged.bind(this),
|
|
288
|
+
connect: this.onConnect.bind(this),
|
|
289
|
+
disconnect: this.onDisconnect.bind(this),
|
|
290
|
+
displayUri: this.onDisplayUri.bind(this),
|
|
291
|
+
},
|
|
292
|
+
analytics: {
|
|
293
|
+
integrationType: 'wagmi',
|
|
294
|
+
},
|
|
295
|
+
ui: {
|
|
296
|
+
...parameters.ui,
|
|
297
|
+
...(parameters.headless != null && {
|
|
298
|
+
headless: parameters.headless,
|
|
299
|
+
}),
|
|
300
|
+
},
|
|
301
|
+
...(parameters.mobile && { mobile: parameters.mobile }),
|
|
302
|
+
})
|
|
303
|
+
}
|
|
304
|
+
metamask = await metamaskPromise
|
|
305
|
+
}
|
|
306
|
+
return metamask
|
|
307
|
+
},
|
|
508
308
|
}))
|
|
509
309
|
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '
|
|
1
|
+
export const version = '8.0.0'
|