Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions src/contexts/wallet/WalletContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ export function WalletProvider({ children }: WalletProviderProps) {
const embeddedAddressRef = useRef<AztecAddress | null>(null);
const previousNodeUrlRef = useRef<string | null>(null);
const hasConnectedExternalWalletRef = useRef(false);
// Generation counter. A stale createEmbeddedWallet resolving after a network switch
// checks this to skip overwriting current state.
const initIdRef = useRef(0);

// Provider tracking for disconnect handling
const currentProviderRef = useRef<WalletProvider | null>(null);
Expand All @@ -80,25 +83,43 @@ export function WalletProvider({ children }: WalletProviderProps) {

previousNodeUrlRef.current = nodeUrl;
hasConnectedExternalWalletRef.current = false;
// Drop the previous network's embedded wallet so it can't be restored on the new network.
embeddedWalletRef.current = null;
embeddedAddressRef.current = null;
const initId = ++initIdRef.current;

async function initializeWallet() {
try {
actions.initStart();

// Node is a property of the network, not the wallet. Publish it immediately so
// external-wallet flows don't have to wait on the slow embedded init.
const node = walletService.createNodeClient(nodeUrl);
actions.setNode(node);

const { wallet: embeddedWallet, address: defaultAccountAddress } = await walletService.createEmbeddedWallet(node);

// Store embedded wallet for later restoration
// Bail if a newer init has superseded this one (e.g. user switched network mid-init).
if (initId !== initIdRef.current) return;

embeddedWalletRef.current = embeddedWallet;
embeddedAddressRef.current = defaultAccountAddress;

// Only set embedded wallet as active if user hasn't connected an external wallet
if (!hasConnectedExternalWalletRef.current) {
actions.initEmbedded(embeddedWallet, node, defaultAccountAddress);
}
} catch (err) {
if (initId !== initIdRef.current) return;

const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';

// External wallet already connected. Embedded init failures here are background
// noise; don't clobber the working session with a fatal error.
if (hasConnectedExternalWalletRef.current) {
console.warn('Embedded wallet init failed (external wallet active):', errorMessage);
return;
}

const fullError =
errorMessage.includes('timeout') || errorMessage.includes('unreachable')
? `${errorMessage}\n\nIf using local network, make sure Aztec sandbox is running:\n aztec start --sandbox\n\nThen deploy contracts:\n yarn deploy:local`
Expand Down Expand Up @@ -238,10 +259,13 @@ export function WalletProvider({ children }: WalletProviderProps) {
}
currentProviderRef.current = null;

// Restore embedded wallet
// Restore embedded wallet if available; otherwise clear state so the UI doesn't
// keep showing the disconnected external wallet as active.
hasConnectedExternalWalletRef.current = false;
if (embeddedWalletRef.current) {
hasConnectedExternalWalletRef.current = false;
actions.restoreEmbedded(embeddedWalletRef.current, embeddedAddressRef.current);
} else {
actions.disconnect();
}
}, [actions]);

Expand Down
7 changes: 7 additions & 0 deletions src/contexts/wallet/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const initialWalletState: WalletState = {

export const walletActions = {
initStart: () => ({ type: 'wallet/INIT_START' as const }),
setNode: (node: AztecNode) => ({ type: 'wallet/SET_NODE' as const, node }),
initEmbedded: (wallet: Wallet, node: AztecNode, address: AztecAddress) => ({
type: 'wallet/INIT_EMBEDDED' as const,
wallet,
Expand Down Expand Up @@ -64,6 +65,9 @@ export function walletReducer(state: WalletState, action: WalletAction): WalletS
case 'wallet/INIT_START':
return { ...state, isLoading: true, error: null };

case 'wallet/SET_NODE':
return { ...state, node: action.node };

case 'wallet/INIT_EMBEDDED':
return {
...state,
Expand All @@ -81,6 +85,8 @@ export function walletReducer(state: WalletState, action: WalletAction): WalletS
wallet: action.wallet,
currentAddress: null,
isUsingEmbeddedWallet: false,
isLoading: false,
error: null,
};

case 'wallet/SET_ADDRESS':
Expand All @@ -100,6 +106,7 @@ export function walletReducer(state: WalletState, action: WalletAction): WalletS
wallet: action.wallet,
currentAddress: action.address,
isUsingEmbeddedWallet: true,
isLoading: false,
};

case 'wallet/SET_ERROR':
Expand Down
Loading