import { create } from 'zustand'; import { invoke } from '../lib/tauri'; function logError(context: string, error: unknown): void { if (import.meta.env.PROD) { console.error(`[Swap] ${context}: ${error instanceof Error ? error.name : 'Unknown'}`); } else { console.error(`[Swap] ${context}:`, error); } } export interface SwapQuote { tokenIn: string; tokenOut: string; amountIn: string; amountOut: string; amountOutMin: string; priceImpactBps: number; route: string[]; estimatedGas: number; } export interface LiquidityPoolInfo { poolAddress: string; tokenA: string; tokenB: string; symbolA: string; symbolB: string; reserveA: string; reserveB: string; totalSupply: string; feeBps: number; } interface SwapState { quote: SwapQuote | null; pools: LiquidityPoolInfo[]; isLoadingQuote: boolean; isSwapping: boolean; isAddingLiquidity: boolean; isRemovingLiquidity: boolean; error: string | null; clearError: () => void; getQuote: (tokenIn: string, tokenOut: string, amountIn: string, slippageBps: number) => Promise; executeSwap: (tokenIn: string, tokenOut: string, amountIn: string, amountOutMin: string) => Promise; fetchPools: () => Promise; addLiquidity: (tokenA: string, tokenB: string, amountA: string, amountB: string) => Promise; removeLiquidity: (poolAddress: string, lpAmount: string) => Promise; } export const useSwapStore = create()((set) => ({ quote: null, pools: [], isLoadingQuote: false, isSwapping: false, isAddingLiquidity: false, isRemovingLiquidity: false, error: null, clearError: () => set({ error: null }), getQuote: async (tokenIn, tokenOut, amountIn, slippageBps) => { set({ isLoadingQuote: true, error: null }); try { const quote = await invoke('swap_get_quote', { tokenIn, tokenOut, amountIn, slippageBps, }); set({ quote, isLoadingQuote: false }); return quote; } catch (error) { const msg = error instanceof Error ? error.message : 'Quote failed'; logError('getQuote', error); set({ error: msg, isLoadingQuote: false }); throw error; } }, executeSwap: async (tokenIn, tokenOut, amountIn, amountOutMin) => { set({ isSwapping: true, error: null }); try { const txHash = await invoke('swap_execute', { tokenIn, tokenOut, amountIn, amountOutMin, }); set({ isSwapping: false, quote: null }); return txHash; } catch (error) { const msg = error instanceof Error ? error.message : 'Swap failed'; logError('executeSwap', error); set({ error: msg, isSwapping: false }); throw error; } }, fetchPools: async () => { try { const pools = await invoke('swap_get_pools'); set({ pools }); } catch (error) { logError('fetchPools', error); } }, addLiquidity: async (tokenA, tokenB, amountA, amountB) => { set({ isAddingLiquidity: true, error: null }); try { const txHash = await invoke('swap_add_liquidity', { tokenA, tokenB, amountA, amountB, }); set({ isAddingLiquidity: false }); return txHash; } catch (error) { const msg = error instanceof Error ? error.message : 'Add liquidity failed'; logError('addLiquidity', error); set({ error: msg, isAddingLiquidity: false }); throw error; } }, removeLiquidity: async (poolAddress, lpAmount) => { set({ isRemovingLiquidity: true, error: null }); try { const txHash = await invoke('swap_remove_liquidity', { poolAddress, lpAmount, }); set({ isRemovingLiquidity: false }); return txHash; } catch (error) { const msg = error instanceof Error ? error.message : 'Remove liquidity failed'; logError('removeLiquidity', error); set({ error: msg, isRemovingLiquidity: false }); throw error; } }, })); export function formatPriceImpact(bps: number): string { const pct = bps / 100; if (pct < 0.01) return '<0.01%'; return `${pct.toFixed(2)}%`; }