import { createContext, useContext, useState, useEffect } from 'react'; import type { ReactNode } from 'react'; import { Keypair } from '@solana/web3.js'; import { AuthService } from '../services/authService'; import type { TossUser } from '../types/tossUser'; type WalletContextType = { isInitialized: boolean; isUnlocked: boolean; user: TossUser | null; keypair: Keypair | null; unlockWallet: () => Promise; lockWallet: () => Promise; signIn: (walletAddress: string, isTemporary?: boolean) => Promise; signOut: () => Promise; }; const WalletContext = createContext(undefined); export const WalletProvider: React.FC<{ children: ReactNode }> = ({ children, }) => { const [isInitialized, setIsInitialized] = useState(false); const [isUnlocked, setIsUnlocked] = useState(false); const [user, setUser] = useState(null); const [keypair, setKeypair] = useState(null); useEffect(() => { const checkAuth = async () => { try { const session = await AuthService.getSession(); if (session) { // In a real app, you'd fetch the user from your backend const { user: sessionUser } = await AuthService.signInWithWallet( session.walletAddress ); setUser(sessionUser); setIsUnlocked(await AuthService.isWalletUnlocked()); } } catch (error) { console.error('Auth check failed:', error); } finally { setIsInitialized(true); } }; checkAuth(); }, []); const unlockWallet = async (): Promise => { try { // Biometric authentication REQUIRED - throws if not authorized const unlockedKeypair = await AuthService.unlockWalletWithBiometrics(); if (unlockedKeypair) { // Keypair held ONLY in React state memory (NOT persisted to disk) setKeypair(unlockedKeypair); setIsUnlocked(true); return true; } return false; } catch (error) { console.error('Biometric authentication failed:', error); setIsUnlocked(false); setKeypair(null); return false; } }; const lockWallet = async (): Promise => { // Clear keypair from memory (from React state) // Encrypted keypair remains stored securely (requires biometric to re-unlock) setKeypair(null); setIsUnlocked(false); }; const signIn = async ( walletAddress: string, isTemporary: boolean = false ): Promise => { const { user: sessionUser } = await AuthService.signInWithWallet( walletAddress, isTemporary ); setUser(sessionUser); setIsUnlocked(true); }; const signOut = async (): Promise => { // Clear session from storage await AuthService.signOut(); // Clear all memory (state) setUser(null); setKeypair(null); // Remove from RAM setIsUnlocked(false); // NOTE: Encrypted keypair remains in SecureStore // It can only be accessed again with biometric authentication }; return ( {children} ); }; export const useWallet = (): WalletContextType => { const context = useContext(WalletContext); if (context === undefined) { throw new Error('useWallet must be used within a WalletProvider'); } return context; }; export default WalletContext;