@@ -12,6 +12,8 @@ import {
1212 type StoredSession ,
1313} from '@/lib/auth' ;
1414import { NETWORK } from '@/lib/network' ;
15+ import { isThanosConnector , isThanosIdentity , THANOS_INSTALL_URL } from '@/lib/thanos' ;
16+ import { ensureExplorerNetwork , type WalletRequestProvider } from '@/lib/walletNetwork' ;
1517
1618/**
1719 * "Sign in with Thanos" — SIWE authentication, unified with wallet connection.
@@ -36,32 +38,57 @@ import { NETWORK } from '@/lib/network';
3638
3739const APP_NAME = `${ NETWORK . label } Explorer` ;
3840const CHAIN_ID = NETWORK . evmChainId ;
39- const THANOS_RDNS = 'fi.thanos.wallet' ;
40- const THANOS_INSTALL_URL = 'https://thanos.fi' ;
41-
4241function shorten ( addr : string ) : string {
4342 return addr . length > 12 ? `${ addr . slice ( 0 , 6 ) } …${ addr . slice ( - 4 ) } ` : addr ;
4443}
4544
4645function findThanosConnector ( ) : Connector | undefined {
47- return ConnectorController . state . connectors . find (
48- ( c ) =>
49- c . id === 'eip6963' &&
50- ( c . info ?. rdns === THANOS_RDNS || c . name ?. toLowerCase ( ) . includes ( 'thanos' ) ) ,
51- ) ;
46+ return ConnectorController . state . connectors . find ( isThanosConnector ) ;
5247}
5348
5449/**
5550 * Thanos may announce after Web3Modal's init-time EIP-6963 discovery (the
5651 * extension's service worker can wake late). Re-request announcements once
5752 * before concluding it isn't installed.
5853 */
59- async function discoverThanosConnector ( ) : Promise < Connector | undefined > {
54+ type ThanosWallet = { connector ?: Connector ; provider : Eip1193Provider } ;
55+
56+ async function discoverThanosWallet ( ) : Promise < ThanosWallet | undefined > {
6057 const existing = findThanosConnector ( ) ;
61- if ( existing ) return existing ;
58+ if ( existing ?. provider ) {
59+ return { connector : existing , provider : existing . provider as Eip1193Provider } ;
60+ }
61+
62+ let announcedProvider : Eip1193Provider | undefined ;
63+ const onAnnouncement = ( event : Event ) => {
64+ const detail = ( event as CustomEvent < {
65+ info ?: { rdns ?: string ; name ?: string } ;
66+ provider ?: Eip1193Provider ;
67+ } > ) . detail ;
68+ if ( detail ?. provider && isThanosIdentity ( detail . info ?. rdns , detail . info ?. name ) ) {
69+ announcedProvider = detail . provider ;
70+ }
71+ } ;
72+
73+ window . addEventListener ( 'eip6963:announceProvider' , onAnnouncement ) ;
6274 window . dispatchEvent ( new Event ( 'eip6963:requestProvider' ) ) ;
63- await new Promise ( ( resolve ) => setTimeout ( resolve , 300 ) ) ;
64- return findThanosConnector ( ) ;
75+
76+ try {
77+ // Extension service workers can wake after Web3Modal's initial discovery.
78+ // Allow late announcements and prefer Web3Modal's connector when it appears.
79+ for ( let attempt = 0 ; attempt < 8 ; attempt += 1 ) {
80+ await new Promise ( ( resolve ) => setTimeout ( resolve , 150 ) ) ;
81+ const connector = findThanosConnector ( ) ;
82+ if ( connector ?. provider ) {
83+ return { connector, provider : connector . provider as Eip1193Provider } ;
84+ }
85+ if ( announcedProvider ) return { provider : announcedProvider } ;
86+ }
87+ } finally {
88+ window . removeEventListener ( 'eip6963:announceProvider' , onAnnouncement ) ;
89+ }
90+
91+ return announcedProvider ? { provider : announcedProvider } : undefined ;
6592}
6693
6794/**
@@ -176,24 +203,27 @@ export default function ThanosSignIn() {
176203 setThanosMissing ( false ) ;
177204 setPhase ( 'connecting' ) ;
178205 try {
179- const connector = await discoverThanosConnector ( ) ;
180- if ( ! connector ) {
206+ const wallet = await discoverThanosWallet ( ) ;
207+ if ( ! wallet ) {
181208 setThanosMissing ( true ) ;
182209 return ;
183210 }
184- // Connects (or switches the active connection to) Thanos with no picker
185- // UI, updating all Web3Modal account state along the way.
186- await ConnectionController . connectExternal ( connector , connector . chain ) ;
187- const provider = connector . provider as Eip1193Provider | undefined ;
188- const accounts = provider
189- ? ( ( await provider . request ( { method : 'eth_accounts' } ) ) as string [ ] )
190- : [ ] ;
211+ const { connector, provider } = wallet ;
212+ if ( connector ) {
213+ // Keep Web3Modal's shared account state in sync when its connector is available.
214+ await ConnectionController . connectExternal ( connector , connector . chain ) ;
215+ }
216+ let accounts = ( await provider . request ( { method : 'eth_accounts' } ) ) as string [ ] ;
217+ if ( ! accounts ?. length && ! connector ) {
218+ accounts = ( await provider . request ( { method : 'eth_requestAccounts' } ) ) as string [ ] ;
219+ }
191220 const address = accounts ?. [ 0 ] ;
192- if ( ! provider || ! address ) {
221+ if ( ! address ) {
193222 // connectExternal swallows a user rejection (it stores the error and
194223 // resolves) — an empty account list is how the rejection surfaces here.
195224 throw new Error ( 'Wallet connection was declined in Thanos.' ) ;
196225 }
226+ await ensureExplorerNetwork ( provider as WalletRequestProvider ) ;
197227 setPhase ( 'signing' ) ;
198228 const stored = await signSession ( provider , address ) ;
199229 setSession ( stored ) ;
0 commit comments