Skip to content

Commit 41a43ae

Browse files
authored
Merge pull request #171 from MeshJS/bug/wallet-connector
2 parents a781497 + 8e7b85f commit 41a43ae

File tree

2 files changed

+261
-48
lines changed

2 files changed

+261
-48
lines changed

src/components/common/cardano-objects/connect-wallet.tsx

Lines changed: 167 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
} from "@/components/ui/dropdown-menu";
1111
import { useWallet, useWalletList } from "@meshsdk/react";
1212
import { useSiteStore } from "@/lib/zustand/site";
13-
import { useEffect } from "react";
13+
import { useEffect, useRef } from "react";
1414
import useUser from "@/hooks/useUser";
1515
import { useUserStore } from "@/lib/zustand/user";
1616
import { 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

Comments
 (0)