@@ -41,45 +41,105 @@ export function makeWalletClient(chain: Chain): any {
4141 } ) ;
4242}
4343
44+ function extractErrorCode ( e : any ) : string | number | null {
45+ const codes = [
46+ e ?. code ,
47+ e ?. cause ?. code ,
48+ e ?. cause ?. cause ?. code ,
49+ e ?. data ?. code ,
50+ e ?. cause ?. data ?. code ,
51+ e ?. cause ?. cause ?. data ?. code
52+ ] ;
53+
54+ for ( const c of codes ) {
55+ if ( c === undefined || c === null ) continue ;
56+ return c ;
57+ }
58+ return null ;
59+ }
60+
61+ function extractErrorMessage ( e : any ) : string {
62+ const parts = [
63+ e ?. shortMessage ,
64+ e ?. message ,
65+ e ?. cause ?. message ,
66+ e ?. cause ?. cause ?. message
67+ ]
68+ . filter ( Boolean )
69+ . map ( String ) ;
70+
71+ if ( parts . length > 0 ) return parts . join ( ' | ' ) ;
72+ try {
73+ return JSON . stringify ( e ) ;
74+ } catch {
75+ return String ( e ?? '' ) ;
76+ }
77+ }
78+
79+ function isUserRejected ( e : any ) : boolean {
80+ const code = extractErrorCode ( e ) ;
81+ const msg = extractErrorMessage ( e ) ;
82+ return String ( code ) === '4001' || / u s e r r e j e c t e d | r e j e c t e d t h e r e q u e s t / i. test ( msg ) ;
83+ }
84+
4485export async function requestWalletAddress ( chain : Chain ) : Promise < `0x${string } `> {
4586 const wallet = makeWalletClient ( chain ) ;
87+
88+ // Connect first. Some wallets behave better if the dapp is already connected before switching networks.
89+ let addr : `0x${string } ` | undefined ;
90+ try {
91+ const addrs = await wallet . requestAddresses ( ) ;
92+ addr = addrs ?. [ 0 ] ;
93+ } catch ( e : any ) {
94+ if ( isUserRejected ( e ) ) {
95+ throw new Error ( 'Wallet connection was rejected. Please approve the wallet connection prompt and retry.' ) ;
96+ }
97+ throw new Error ( `Wallet connection failed. ${ extractErrorMessage ( e ) } ` ) ;
98+ }
99+
100+ if ( ! addr ) throw new Error ( 'No wallet address returned.' ) ;
101+
46102 const currentChainId = await wallet . getChainId ( ) ;
47103 if ( currentChainId !== chain . id ) {
104+ const rpcUrl = resolveRpcUrl ( chain ) ;
105+ const manualHint = rpcUrl
106+ ? `In MetaMask, add/switch to "${ chain . name } " (chainId ${ chain . id } ) with RPC URL ${ rpcUrl } .`
107+ : `Switch networks in your wallet to chainId ${ chain . id } .` ;
108+
48109 try {
49110 await wallet . switchChain ( { id : chain . id } ) ;
50- } catch ( e : any ) {
51- const code = e ?. cause ?. code ?? e ?. code ?? null ;
52- const msg = String ( e ?. shortMessage ?? e ?. message ?? e ?? '' ) ;
53-
54- // MetaMask uses 4902 for "Unrecognized chain" when switching to a chain that hasn't been added.
55- const looksUnrecognized =
56- String ( code ) === '4902' ||
57- / 4 9 0 2 / . test ( msg ) ||
58- / u n r e c o g n i z e d c h a i n | u n k n o w n c h a i n | n o t a d d e d / i. test ( msg ) ;
59-
60- if ( looksUnrecognized ) {
61- try {
62- // Attempt to add the chain to the wallet, then retry the switch.
63- await wallet . addChain ( { chain } ) ;
64- await wallet . switchChain ( { id : chain . id } ) ;
65- } catch ( e2 : any ) {
66- const msg2 = String ( e2 ?. shortMessage ?? e2 ?. message ?? e2 ?? '' ) ;
111+ } catch ( e1 : any ) {
112+ if ( isUserRejected ( e1 ) ) {
113+ throw new Error (
114+ `Wrong network. Wallet is on chainId ${ currentChainId } but this app's primary deployment is chainId ${ chain . id } . ` +
115+ `You rejected the network switch request. Please approve it and retry.`
116+ ) ;
117+ }
118+
119+ // Many wallets don't reliably surface the "unknown chain" code/message.
120+ // Try add+switch as a best-effort fallback.
121+ try {
122+ await wallet . addChain ( { chain } ) ;
123+ } catch ( eAdd : any ) {
124+ if ( isUserRejected ( eAdd ) ) {
67125 throw new Error (
68126 `Wrong network. Wallet is on chainId ${ currentChainId } but this app's primary deployment is chainId ${ chain . id } . ` +
69- `We tried to add/switch the chain automatically but it failed. ` +
70- `Add/switch networks in your wallet and retry. ${ msg2 ? `(${ msg2 } )` : '' } `
127+ `You rejected the request to add the network. ${ manualHint } `
71128 ) ;
72129 }
130+ // Ignore other addChain errors and still retry switching; the chain may already exist.
73131 }
74132
75- throw new Error (
76- `Wrong network. Wallet is on chainId ${ currentChainId } but this app's primary deployment is chainId ${ chain . id } . ` +
77- `Switch networks in your wallet and retry. ${ msg ? `(${ msg } )` : '' } `
78- ) ;
133+ try {
134+ await wallet . switchChain ( { id : chain . id } ) ;
135+ } catch ( e2 : any ) {
136+ throw new Error (
137+ `Wrong network. Wallet is on chainId ${ currentChainId } but this app's primary deployment is chainId ${ chain . id } . ` +
138+ `Automatic network switch failed. ${ manualHint } (${ extractErrorMessage ( e2 ) } )`
139+ ) ;
140+ }
79141 }
80142 }
81- const addrs = await wallet . requestAddresses ( ) ;
82- const addr = addrs ?. [ 0 ] ;
83- if ( ! addr ) throw new Error ( 'No wallet address returned.' ) ;
143+
84144 return addr ;
85145}
0 commit comments