@@ -329,106 +329,86 @@ export function metaMask(parameters: MetaMaskParameters = {}) {
329
329
} ) ( )
330
330
331
331
// Avoid back and forth on mobile by using `'wallet_addEthereumChain'` for non-default chains
332
- if ( ! isDefaultChain )
333
- try {
334
- const blockExplorerUrls = ( ( ) => {
335
- const { default : blockExplorer , ...blockExplorers } =
336
- chain . blockExplorers ?? { }
337
- if ( addEthereumChainParameter ?. blockExplorerUrls )
338
- return addEthereumChainParameter . blockExplorerUrls
339
- if ( blockExplorer )
340
- return [
341
- blockExplorer . url ,
342
- ...Object . values ( blockExplorers ) . map ( ( x ) => x . url ) ,
343
- ]
344
- return
345
- } ) ( )
346
-
347
- const rpcUrls = ( ( ) => {
348
- if ( addEthereumChainParameter ?. rpcUrls ?. length )
349
- return addEthereumChainParameter . rpcUrls
350
- return [ chain . rpcUrls . default ?. http [ 0 ] ?? '' ]
351
- } ) ( )
352
-
332
+ try {
333
+ if ( ! isDefaultChain )
353
334
await provider . request ( {
354
335
method : 'wallet_addEthereumChain' ,
355
336
params : [
356
337
{
357
- blockExplorerUrls,
338
+ blockExplorerUrls : ( ( ) => {
339
+ const { default : blockExplorer , ...blockExplorers } =
340
+ chain . blockExplorers ?? { }
341
+ if ( addEthereumChainParameter ?. blockExplorerUrls )
342
+ return addEthereumChainParameter . blockExplorerUrls
343
+ if ( blockExplorer )
344
+ return [
345
+ blockExplorer . url ,
346
+ ...Object . values ( blockExplorers ) . map ( ( x ) => x . url ) ,
347
+ ]
348
+ return
349
+ } ) ( ) ,
358
350
chainId : numberToHex ( chainId ) ,
359
351
chainName : addEthereumChainParameter ?. chainName ?? chain . name ,
360
352
iconUrls : addEthereumChainParameter ?. iconUrls ,
361
353
nativeCurrency :
362
354
addEthereumChainParameter ?. nativeCurrency ??
363
355
chain . nativeCurrency ,
364
- rpcUrls,
356
+ rpcUrls : ( ( ) => {
357
+ if ( addEthereumChainParameter ?. rpcUrls ?. length )
358
+ return addEthereumChainParameter . rpcUrls
359
+ return [ chain . rpcUrls . default ?. http [ 0 ] ?? '' ]
360
+ } ) ( ) ,
365
361
} satisfies AddEthereumChainParameter ,
366
362
] ,
367
363
} )
364
+ else
365
+ await provider . request ( {
366
+ method : 'wallet_switchEthereumChain' ,
367
+ params : [ { chainId : numberToHex ( chainId ) } ] ,
368
+ } )
369
+
370
+ // During `'wallet_switchEthereumChain'`, MetaMask makes a `'net_version'` RPC call to the target chain.
371
+ // If this request fails, MetaMask does not emit the `'chainChanged'` event, but will still switch the chain.
372
+ // To counter this behavior, we request and emit the current chain ID to confirm the chain switch either via
373
+ // this callback or an externally emitted `'chainChanged'` event.
374
+ // https://github.com/MetaMask/metamask-extension/issues/24247
375
+ await waitForChainIdToSync ( )
376
+ await sendAndWaitForChangeEvent ( chainId )
368
377
378
+ async function waitForChainIdToSync ( ) {
369
379
// On mobile, there is a race condition between the result of `'wallet_addEthereumChain'` and `'eth_chainId'`.
370
- // (`'eth_chainId'` from the MetaMask relay server).
371
380
// To avoid this, we wait for `'eth_chainId'` to return the expected chain ID with a retry loop.
372
- let retryCount = 0
373
- const currentChainId = await withRetry (
381
+ await withRetry (
374
382
async ( ) => {
375
- retryCount += 1
376
383
const value = hexToNumber (
377
384
// `'eth_chainId'` is cached by the MetaMask SDK side to avoid unnecessary deeplinks
378
385
( await provider . request ( { method : 'eth_chainId' } ) ) as Hex ,
379
386
)
380
- if ( value !== chainId ) {
381
- if ( retryCount === 5 ) return - 1
382
- // `value` doesn't match expected `chainId`, throw to trigger retry
383
- throw new Error ( 'Chain ID mismatch' )
384
- }
387
+ // `value` doesn't match expected `chainId`, throw to trigger retry
388
+ if ( value !== chainId )
389
+ throw new Error ( 'User rejected switch after adding network.' )
385
390
return value
386
391
} ,
387
392
{
388
- delay : 100 ,
389
- retryCount : 5 , // android device encryption is slower
393
+ delay : 50 ,
394
+ retryCount : 20 , // android device encryption is slower
390
395
} ,
391
396
)
392
-
393
- if ( currentChainId !== chainId )
394
- throw new Error ( 'User rejected switch after adding network.' )
395
-
396
- return chain
397
- } catch ( err ) {
398
- const error = err as RpcError
399
- if ( error . code === UserRejectedRequestError . code )
400
- throw new UserRejectedRequestError ( error )
401
- throw new SwitchChainError ( error )
402
397
}
403
398
404
- // Use to `'wallet_switchEthereumChain'` for default chains
405
- try {
406
- await Promise . all ( [
407
- provider
408
- . request ( {
409
- method : 'wallet_switchEthereumChain' ,
410
- params : [ { chainId : numberToHex ( chainId ) } ] ,
411
- } )
412
- // During `'wallet_switchEthereumChain'`, MetaMask makes a `'net_version'` RPC call to the target chain.
413
- // If this request fails, MetaMask does not emit the `'chainChanged'` event, but will still switch the chain.
414
- // To counter this behavior, we request and emit the current chain ID to confirm the chain switch either via
415
- // this callback or an externally emitted `'chainChanged'` event.
416
- // https://github.com/MetaMask/metamask-extension/issues/24247
417
- . then ( async ( ) => {
418
- const currentChainId = await this . getChainId ( )
419
- if ( currentChainId === chainId )
420
- config . emitter . emit ( 'change' , { chainId } )
421
- } ) ,
422
- new Promise < void > ( ( resolve ) => {
399
+ async function sendAndWaitForChangeEvent ( chainId : number ) {
400
+ await new Promise < void > ( ( resolve ) => {
423
401
const listener = ( ( data ) => {
424
402
if ( 'chainId' in data && data . chainId === chainId ) {
425
403
config . emitter . off ( 'change' , listener )
426
404
resolve ( )
427
405
}
428
406
} ) satisfies Parameters < typeof config . emitter . on > [ 1 ]
429
407
config . emitter . on ( 'change' , listener )
430
- } ) ,
431
- ] )
408
+ config . emitter . emit ( 'change' , { chainId } )
409
+ } )
410
+ }
411
+
432
412
return chain
433
413
} catch ( err ) {
434
414
const error = err as RpcError
0 commit comments