@@ -10,7 +10,7 @@ import {
1010} from "@/components/ui/dropdown-menu" ;
1111import { useWallet , useWalletList } from "@meshsdk/react" ;
1212import { useSiteStore } from "@/lib/zustand/site" ;
13- import { useEffect } from "react" ;
13+ import { useEffect , useRef } from "react" ;
1414import useUser from "@/hooks/useUser" ;
1515import { useUserStore } from "@/lib/zustand/user" ;
1616import { getProvider } from "@/utils/get-provider" ;
@@ -24,11 +24,17 @@ export default function ConnectWallet() {
2424 const setUserAssetMetadata = useUserStore (
2525 ( state ) => state . setUserAssetMetadata ,
2626 ) ;
27- const { user } = useUser ( ) ;
27+ const { user, isLoading : userLoading } = useUser ( ) ;
2828
2929 const wallets = useWalletList ( ) ;
3030 const { connect, connected, wallet, name } = useWallet ( ) ;
3131 const network = useSiteStore ( ( state ) => state . network ) ;
32+ const connectingRef = useRef ( false ) ;
33+ const fetchingAssetsRef = useRef ( false ) ;
34+ const lastWalletIdRef = useRef < string | null > ( null ) ;
35+ const fetchingNetworkRef = useRef ( false ) ;
36+ const lastNetworkWalletRef = useRef < string | null > ( null ) ;
37+ const userAssets = useUserStore ( ( state ) => state . userAssets ) ;
3238
3339 async function connectWallet ( walletId : string ) {
3440 setPastWallet ( walletId ) ;
@@ -37,70 +43,204 @@ export default function ConnectWallet() {
3743
3844 /**
3945 * Try to connect the wallet when the user loads the application, if user had connected before,
46+ * but only if:
47+ * 1. The wallet list has been loaded (wallets.length > 0)
48+ * 2. The pastWallet exists in the available wallets
49+ * 3. We're not already connected
50+ * 4. We're not already attempting to connect
4051 */
4152 useEffect ( ( ) => {
4253 async function handleAutoWalletConnect ( ) {
43- if ( pastWallet && ! connected ) {
44- try {
45- await connect ( pastWallet ) ;
46- } catch ( e ) {
47- setPastWallet ( undefined ) ;
48- }
54+ // Don't attempt if already connected or already connecting
55+ if ( connected || connectingRef . current ) {
56+ return ;
57+ }
58+
59+ // Don't attempt if no pastWallet is stored
60+ if ( ! pastWallet ) {
61+ return ;
62+ }
63+
64+ // Wait for wallet list to be available
65+ // If wallets array is empty, wallets might still be loading
66+ // The effect will re-run when wallets become available
67+ if ( wallets . length === 0 ) {
68+ return ;
69+ }
70+
71+ // Check if the pastWallet exists in the available wallets
72+ const walletExists = wallets . some ( ( w ) => w . id === pastWallet ) ;
73+ if ( ! walletExists ) {
74+ console . warn (
75+ `Stored wallet "${ pastWallet } " not found in available wallets. Clearing stored wallet.` ,
76+ ) ;
77+ setPastWallet ( undefined ) ;
78+ return ;
79+ }
80+
81+ // Attempt to connect
82+ connectingRef . current = true ;
83+ try {
84+ console . log ( `Attempting to auto-connect wallet: ${ pastWallet } ` ) ;
85+ await connect ( pastWallet ) ;
86+ console . log ( `Successfully auto-connected wallet: ${ pastWallet } ` ) ;
87+ } catch ( e ) {
88+ console . error (
89+ `Failed to auto-connect wallet "${ pastWallet } ":` ,
90+ e instanceof Error ? e . message : e ,
91+ ) ;
92+ setPastWallet ( undefined ) ;
93+ } finally {
94+ connectingRef . current = false ;
4995 }
5096 }
97+
5198 handleAutoWalletConnect ( ) ;
52- } , [ pastWallet , connected ] ) ;
99+ } , [ pastWallet , connected , wallets , connect , setPastWallet ] ) ;
53100
54101 useEffect ( ( ) => {
55102 async function lookupWalletAssets ( ) {
56103 if ( ! wallet ) return ;
104+
105+ // Prevent multiple simultaneous calls
106+ if ( fetchingAssetsRef . current ) {
107+ console . log ( "Assets fetch already in progress, skipping..." ) ;
108+ return ;
109+ }
110+
111+ // Use wallet name as identifier (doesn't require API call)
112+ const walletId = name || "unknown" ;
113+
114+ // Skip if we've already fetched for this wallet and have assets
115+ if ( lastWalletIdRef . current === walletId && userAssets . length > 0 ) {
116+ console . log ( "Assets already loaded for this wallet, skipping fetch" ) ;
117+ return ;
118+ }
119+
120+ fetchingAssetsRef . current = true ;
121+ lastWalletIdRef . current = walletId ;
122+
57123 try {
124+ console . log ( "Fetching wallet balance..." ) ;
58125 const assets = await wallet . getBalance ( ) ;
59- const provider = getProvider ( await wallet . getNetworkId ( ) ) ;
60- const userAssets : Asset [ ] = [ ] ;
126+ // Use network from store if available, otherwise fetch it
127+ let networkId = network ;
128+ if ( ! networkId ) {
129+ try {
130+ networkId = await wallet . getNetworkId ( ) ;
131+ setNetwork ( networkId ) ;
132+ } catch ( networkError ) {
133+ console . error ( "Error getting network ID for provider:" , networkError ) ;
134+ // Use default network if we can't get it
135+ networkId = 0 ; // Mainnet default
136+ }
137+ }
138+ const provider = getProvider ( networkId ) ;
139+ const fetchedAssets : Asset [ ] = [ ] ;
61140 if ( assets ) {
62141 for ( const asset of assets ) {
63- userAssets . push ( {
142+ fetchedAssets . push ( {
64143 unit : asset . unit ,
65144 quantity : asset . quantity ,
66145 } ) ;
67146 if ( asset . unit === "lovelace" ) continue ;
68- const assetInfo = await provider . get ( `/assets/${ asset . unit } ` ) ;
69- setUserAssetMetadata (
70- asset . unit ,
71- assetInfo ?. metadata ?. name ||
72- assetInfo ?. onchain_metadata ?. name ||
147+ try {
148+ const assetInfo = await provider . get ( `/assets/${ asset . unit } ` ) ;
149+ setUserAssetMetadata (
73150 asset . unit ,
74- assetInfo ?. metadata ?. decimals || 0 ,
75- ) ;
151+ assetInfo ?. metadata ?. name ||
152+ assetInfo ?. onchain_metadata ?. name ||
153+ asset . unit ,
154+ assetInfo ?. metadata ?. decimals || 0 ,
155+ ) ;
156+ } catch ( assetError ) {
157+ // If asset metadata fetch fails, continue with other assets
158+ console . warn ( `Failed to fetch metadata for asset ${ asset . unit } :` , assetError ) ;
159+ }
76160 }
77- setUserAssets ( userAssets ) ;
161+ setUserAssets ( fetchedAssets ) ;
162+ console . log ( "Successfully fetched wallet assets" ) ;
78163 }
164+ // Reset the fetching flag after successful fetch
165+ fetchingAssetsRef . current = false ;
79166 } catch ( error ) {
80167 console . error ( "Error looking up wallet assets:" , error ) ;
168+ // If it's a rate limit error, don't clear the ref immediately
169+ // to prevent rapid retries - wait 5 seconds before allowing retry
170+ if ( error instanceof Error && error . message . includes ( "too many requests" ) ) {
171+ console . warn ( "Rate limit hit, will retry after delay" ) ;
172+ setTimeout ( ( ) => {
173+ fetchingAssetsRef . current = false ;
174+ } , 5000 ) ;
175+ return ;
176+ }
177+ // For other errors, reset immediately so we can retry
178+ fetchingAssetsRef . current = false ;
81179 }
82180 }
181+
83182 async function handleNetworkChange ( ) {
84- if ( connected ) {
85- setNetwork ( await wallet . getNetworkId ( ) ) ;
183+ if ( ! connected || ! wallet ) return ;
184+
185+ // Prevent multiple simultaneous network ID fetches
186+ if ( fetchingNetworkRef . current ) {
187+ console . log ( "Network ID fetch already in progress, skipping..." ) ;
188+ return ;
189+ }
190+
191+ // Use wallet name as identifier (doesn't require API call)
192+ const walletId = name || "unknown" ;
193+
194+ // Skip if we've already fetched network for this wallet
195+ if ( lastNetworkWalletRef . current === walletId && network !== undefined ) {
196+ console . log ( "Network ID already fetched for this wallet, skipping" ) ;
197+ return ;
198+ }
199+
200+ fetchingNetworkRef . current = true ;
201+ lastNetworkWalletRef . current = walletId ;
202+
203+ try {
204+ console . log ( "Fetching network ID..." ) ;
205+ const networkId = await wallet . getNetworkId ( ) ;
206+ setNetwork ( networkId ) ;
207+ console . log ( "Successfully fetched network ID:" , networkId ) ;
208+ fetchingNetworkRef . current = false ;
209+ } catch ( error ) {
210+ console . error ( "Error getting network ID:" , error ) ;
211+ // If rate limited, wait before retry
212+ if ( error instanceof Error && error . message . includes ( "too many requests" ) ) {
213+ console . warn ( "Rate limit hit for network ID, will retry after delay" ) ;
214+ setTimeout ( ( ) => {
215+ fetchingNetworkRef . current = false ;
216+ } , 5000 ) ;
217+ return ;
218+ }
219+ fetchingNetworkRef . current = false ;
86220 }
87221 }
222+
88223 async function getWalletAssets ( ) {
89224 if ( wallet && connected ) {
90225 await lookupWalletAssets ( ) ;
91226 }
92227 }
93- handleNetworkChange ( ) ;
94- getWalletAssets ( ) ;
95- } , [ connected , wallet , setNetwork ] ) ;
228+
229+ // Only run if wallet and connected state are available
230+ if ( wallet && connected ) {
231+ handleNetworkChange ( ) ;
232+ getWalletAssets ( ) ;
233+ }
234+ } , [ connected , wallet , name , setNetwork , setUserAssets , setUserAssetMetadata ] ) ;
96235
97236 return (
98237 < DropdownMenu >
99238 < DropdownMenuTrigger asChild >
100239 < Button variant = "secondary" className = "rounded-full" >
101240 < Wallet className = "mr-2 h-5 w-5" />
102- { ! user && connected && "Connecting..." }
103- { ! user && ! connected && "Connect" }
241+ { connected && ( ! user || userLoading ) && "Connecting..." }
242+ { ! connected && "Connect" }
243+ { connected && user && ! userLoading && name }
104244 </ Button >
105245 </ DropdownMenuTrigger >
106246 < DropdownMenuContent align = "end" >
0 commit comments