Skip to content

Commit 7c759bf

Browse files
committed
refactor: Wallet Connection Bug Fix (#503, Issue #105)
- Add Starknet event listeners (accountsChanged, networkChanged) to useWeb3Wallet hook - Ensure both MetaMask and Starknet wallet providers have proper event handling - Gracefully handle Starknet wallets that may not support .on()/.off() methods - Add unit test for Starknet accountsChanged event disconnection behavior - All 9 wallet tests passing with no regressions
1 parent 56d7178 commit 7c759bf

2 files changed

Lines changed: 82 additions & 20 deletions

File tree

src/hooks/__tests__/useWeb3Wallet.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,35 @@ describe('useWeb3Wallet', () => {
155155
expect(result.current.provider).toBe('starknet');
156156
expect(result.current.address).toBe('0xstarkaddress');
157157
});
158+
159+
it('should update Starknet connection state when Starknet accountsChanged event is fired', async () => {
160+
let mockAccountListener: ((accounts: string[]) => void) | null = null;
161+
mockStarknet.on.mockImplementation((event: string, callback: any) => {
162+
if (event === 'accountsChanged') {
163+
mockAccountListener = callback;
164+
}
165+
});
166+
167+
mockStarknet.enable.mockResolvedValue(['0xstarkaddress']);
168+
169+
const { result } = renderHook(() => useWeb3Wallet());
170+
171+
// Connect to Starknet
172+
await act(async () => {
173+
await result.current.connect('starknet');
174+
});
175+
176+
expect(result.current.provider).toBe('starknet');
177+
expect(result.current.address).toBe('0xstarkaddress');
178+
179+
// Trigger accountsChanged event on Starknet with empty accounts
180+
await act(async () => {
181+
if (mockAccountListener) {
182+
mockAccountListener([]);
183+
}
184+
});
185+
186+
expect(result.current.isConnected).toBe(false);
187+
expect(result.current.address).toBeNull();
188+
});
158189
});

src/hooks/useWeb3Wallet.ts

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -379,31 +379,62 @@ export function useWeb3Wallet() {
379379
*/
380380
useEffect(() => {
381381
if (typeof window === 'undefined') return;
382-
if (state.provider !== 'metamask') return;
383382

384-
const ethereum = (window as Window & { ethereum?: any }).ethereum;
385-
if (!ethereum) return;
383+
if (state.provider === 'metamask') {
384+
const ethereum = (window as Window & { ethereum?: any }).ethereum;
385+
if (!ethereum) return;
386386

387-
const handleAccountsChanged = (accounts: string[]) => {
388-
if (accounts.length === 0) {
389-
disconnect();
390-
} else if (accounts[0] !== state.address) {
391-
setState((prev) => ({ ...prev, address: accounts[0] }));
392-
}
393-
};
387+
const handleAccountsChanged = (accounts: string[]) => {
388+
if (accounts.length === 0) {
389+
disconnect();
390+
} else if (accounts[0] !== state.address) {
391+
setState((prev) => ({ ...prev, address: accounts[0] }));
392+
}
393+
};
394394

395-
const handleChainChanged = (chainId: string) => {
396-
setState((prev) => ({ ...prev, chainId }));
397-
window.location.reload(); // Reload on chain change to update contract references
398-
};
395+
const handleChainChanged = (chainId: string) => {
396+
setState((prev) => ({ ...prev, chainId }));
397+
window.location.reload(); // Reload on chain change to update contract references
398+
};
399399

400-
ethereum.on('accountsChanged', handleAccountsChanged);
401-
ethereum.on('chainChanged', handleChainChanged);
400+
ethereum.on('accountsChanged', handleAccountsChanged);
401+
ethereum.on('chainChanged', handleChainChanged);
402402

403-
return () => {
404-
ethereum.removeListener('accountsChanged', handleAccountsChanged);
405-
ethereum.removeListener('chainChanged', handleChainChanged);
406-
};
403+
return () => {
404+
ethereum.removeListener('accountsChanged', handleAccountsChanged);
405+
ethereum.removeListener('chainChanged', handleChainChanged);
406+
};
407+
} else if (state.provider === 'starknet') {
408+
const starknet = (window as Window & { starknet?: any }).starknet;
409+
if (!starknet) return;
410+
411+
const handleAccountsChanged = (accounts: string[]) => {
412+
if (accounts.length === 0) {
413+
disconnect();
414+
} else if (accounts[0] !== state.address) {
415+
setState((prev) => ({ ...prev, address: accounts[0] }));
416+
}
417+
};
418+
419+
const handleNetworkChanged = () => {
420+
window.location.reload(); // Reload on network change to update contract references
421+
};
422+
423+
if (typeof starknet.on === 'function') {
424+
starknet.on('accountsChanged', handleAccountsChanged);
425+
starknet.on('networkChanged', handleNetworkChanged);
426+
}
427+
428+
return () => {
429+
if (typeof starknet.off === 'function') {
430+
starknet.off('accountsChanged', handleAccountsChanged);
431+
starknet.off('networkChanged', handleNetworkChanged);
432+
} else if (typeof starknet.removeListener === 'function') {
433+
starknet.removeListener('accountsChanged', handleAccountsChanged);
434+
starknet.removeListener('networkChanged', handleNetworkChanged);
435+
}
436+
};
437+
}
407438
}, [state.address, state.provider, disconnect]);
408439

409440
return {

0 commit comments

Comments
 (0)