@@ -132,7 +132,7 @@ export async function connectWC(
132132 ...( wcOptions ?. pairingTopic
133133 ? { pairingTopic : wcOptions ?. pairingTopic }
134134 : { } ) ,
135- namespaces : {
135+ optionalNamespaces : {
136136 [ NAMESPACE ] : {
137137 chains : chainsToRequest ,
138138 events : [ "chainChanged" , "accountsChanged" ] ,
@@ -157,14 +157,8 @@ export async function connectWC(
157157 ) ;
158158 const currentChainId = chainsToRequest [ 0 ] ?. split ( ":" ) [ 1 ] || 1 ;
159159 const providerChainId = normalizeChainId ( currentChainId ) ;
160- const accounts : string [ ] = await provider . request (
161- {
162- method : "eth_requestAccounts" ,
163- params : [ ] ,
164- } ,
165- `eip155:${ providerChainId } ` ,
166- ) ;
167- const address = accounts [ 0 ] ;
160+ const account = firstAccountOn ( provider . session , `eip155:1` ) ; // grab the address from mainnet
161+ const address = account ;
168162 if ( ! address ) {
169163 throw new Error ( "No accounts found on provider." ) ;
170164 }
@@ -202,6 +196,109 @@ export async function connectWC(
202196 ) ;
203197}
204198
199+ async function ensureTargetChain (
200+ provider : Awaited < ReturnType < typeof initProvider > > ,
201+ chain : Chain ,
202+ walletInfo : WalletInfo ,
203+ ) {
204+ if ( ! provider . session ) {
205+ throw new Error ( "No session found on provider." ) ;
206+ }
207+ const TARGET_CAIP = `eip155:${ chain . id } ` ;
208+ const TARGET_HEX = numberToHex ( chain . id ) ;
209+
210+ // Fast path: already enabled
211+ if ( hasChainEnabled ( provider . session , TARGET_CAIP ) ) {
212+ provider . setDefaultChain ( TARGET_CAIP ) ;
213+ return ;
214+ }
215+
216+ // 1) Try switch
217+ try {
218+ await requestAndOpenWallet ( {
219+ provider,
220+ payload : {
221+ method : "wallet_switchEthereumChain" ,
222+ params : [ { chainId : TARGET_HEX } ] ,
223+ } ,
224+ chain : TARGET_CAIP , // route to target
225+ walletInfo,
226+ } ) ;
227+ provider . setDefaultChain ( TARGET_CAIP ) ;
228+ return ;
229+ } catch ( err : any ) {
230+ const code = err ?. code ?? err ?. data ?. originalError ?. code ;
231+ // 4001 user rejected; stop
232+ if ( code === 4001 ) throw new Error ( "User rejected chain switch" ) ;
233+ // fall through on 4902 or unknown -> try add
234+ }
235+
236+ // 2) Add the chain via any chain we already have
237+ const routeChain = anyRoutableChain ( provider . session ) ;
238+ if ( ! routeChain )
239+ throw new Error ( "No routable chain to send wallet_addEthereumChain" ) ;
240+
241+ try {
242+ await requestAndOpenWallet ( {
243+ provider,
244+ payload : {
245+ method : "wallet_addEthereumChain" ,
246+ params : [
247+ {
248+ chainId : TARGET_HEX ,
249+ chainName : chain . name ,
250+ nativeCurrency : chain . nativeCurrency ,
251+ rpcUrls : [ chain . rpc ] ,
252+ blockExplorerUrls : [ chain . blockExplorers ?. [ 0 ] ?. url ?? "" ] ,
253+ } ,
254+ ] ,
255+ } ,
256+ chain : routeChain , // route via known-good chain, not the target
257+ walletInfo,
258+ } ) ;
259+ } catch ( err : any ) {
260+ const code = err ?. code ?? err ?. data ?. originalError ?. code ;
261+ if ( code === 4001 ) throw new Error ( "User rejected add chain" ) ;
262+ throw new Error ( `Add chain failed: ${ err ?. message || String ( err ) } ` ) ;
263+ }
264+
265+ // 3) Re-try switch after add
266+ await requestAndOpenWallet ( {
267+ provider,
268+ payload : {
269+ method : "wallet_switchEthereumChain" ,
270+ params : [ { chainId : TARGET_HEX } ] ,
271+ } ,
272+ chain : TARGET_CAIP ,
273+ walletInfo,
274+ } ) ;
275+ provider . setDefaultChain ( TARGET_CAIP ) ;
276+
277+ // 4) Verify enablement
278+ if ( ! hasChainEnabled ( provider . session , TARGET_CAIP ) ) {
279+ throw new Error ( "Target chain still not enabled by wallet" ) ;
280+ }
281+ }
282+
283+ type WCSession = Awaited < ReturnType < typeof UniversalProvider . init > > [ "session" ] ;
284+
285+ function getNS ( session : WCSession ) {
286+ return session ?. namespaces ?. eip155 ;
287+ }
288+ function hasChainEnabled ( session : WCSession , caip : string ) {
289+ const ns = getNS ( session ) ;
290+ return ! ! ns ?. accounts ?. some ( ( a ) => a . startsWith ( `${ caip } :` ) ) ;
291+ }
292+ function firstAccountOn ( session : WCSession , caip : string ) : string | null {
293+ const ns = getNS ( session ) ;
294+ const hit = ns ?. accounts ?. find ( ( a ) => a . startsWith ( `${ caip } :` ) ) ;
295+ return hit ? ( hit . split ( ":" ) [ 2 ] ?? null ) : null ;
296+ }
297+ function anyRoutableChain ( session : WCSession ) : string | null {
298+ const ns = getNS ( session ) ;
299+ return ns ?. accounts ?. [ 0 ] ?. split ( ":" ) ?. slice ( 0 , 2 ) ?. join ( ":" ) ?? null ; // e.g. "eip155:1"
300+ }
301+
205302/**
206303 * Auto connect to already connected wallet connect session.
207304 * @internal
@@ -545,14 +642,17 @@ function onConnect(
545642 account ,
546643 chain ,
547644 disconnect ,
548- ( newChain ) => switchChainWC ( provider , newChain ) ,
645+ ( newChain ) => switchChainWC ( provider , newChain , walletInfo ) ,
549646 ] ;
550647}
551648
552- async function switchChainWC ( provider : WCProvider , chain : Chain ) {
553- const chainId = chain . id ;
649+ async function switchChainWC (
650+ provider : WCProvider ,
651+ chain : Chain ,
652+ walletInfo : WalletInfo ,
653+ ) {
554654 try {
555- provider . setDefaultChain ( `eip155: ${ chainId } ` ) ;
655+ await ensureTargetChain ( provider , chain , walletInfo ) ;
556656 } catch ( error ) {
557657 const message =
558658 typeof error === "string" ? error : ( error as ProviderRpcError ) ?. message ;
@@ -605,7 +705,10 @@ function getChainsToRequest(options: {
605705 chainIds . push ( chain . id ) ;
606706 }
607707
608- if ( ! options . chain && optionalChains . length === 0 ) {
708+ // always include mainnet
709+ // many wallets only support a handful of chains, but mainnet is always supported
710+ // we will add additional chains in switchChain if needed
711+ if ( ! chainIds . includes ( 1 ) ) {
609712 rpcMap [ 1 ] = getCachedChain ( 1 ) . rpc ;
610713 chainIds . push ( 1 ) ;
611714 }
0 commit comments