import { create } from 'zustand'; import { invoke } from '@tauri-apps/api/core'; export interface YieldOpportunity { id: string; name: string; protocol: string; asset: string; apy: number; tvl: number; riskLevel: 'low' | 'medium' | 'high'; lockupPeriodDays: number; minDeposit: number; } export interface YieldPosition { id: string; opportunityId: string; depositedAmount: number; currentValue: number; rewardsEarned: number; autoCompound: boolean; createdAt: number; lastCompoundAt?: number; } interface YieldState { opportunities: YieldOpportunity[]; positions: YieldPosition[]; isLoading: boolean; error: string | null; } interface YieldActions { loadOpportunities: () => Promise; deposit: (opportunityId: string, amount: number, autoCompound: boolean) => Promise; withdraw: (positionId: string, amount?: number) => Promise; listPositions: () => Promise; compound: (positionId: string) => Promise; clearError: () => void; } // Transform snake_case to camelCase const transformOpportunity = (data: Record): YieldOpportunity => ({ id: data.id as string, name: data.name as string, protocol: data.protocol as string, asset: data.asset as string, apy: data.apy as number, tvl: data.tvl as number, riskLevel: data.risk_level as YieldOpportunity['riskLevel'], lockupPeriodDays: data.lockup_period_days as number, minDeposit: data.min_deposit as number, }); const transformPosition = (data: Record): YieldPosition => ({ id: data.id as string, opportunityId: data.opportunity_id as string, depositedAmount: data.deposited_amount as number, currentValue: data.current_value as number, rewardsEarned: data.rewards_earned as number, autoCompound: data.auto_compound as boolean, createdAt: data.created_at as number, lastCompoundAt: data.last_compound_at as number | undefined, }); export const useYieldStore = create((set) => ({ opportunities: [], positions: [], isLoading: false, error: null, loadOpportunities: async () => { try { set({ isLoading: true, error: null }); const data = await invoke[]>('yield_get_opportunities'); const opportunities = data.map(transformOpportunity); set({ opportunities, isLoading: false }); } catch (error) { set({ error: String(error), isLoading: false }); } }, deposit: async (opportunityId: string, amount: number, autoCompound: boolean) => { try { set({ isLoading: true, error: null }); const data = await invoke>('yield_deposit', { opportunityId, amount, autoCompound, }); const position = transformPosition(data); set((state) => ({ positions: [position, ...state.positions], isLoading: false, })); return position; } catch (error) { set({ error: String(error), isLoading: false }); throw error; } }, withdraw: async (positionId: string, amount?: number) => { try { set({ isLoading: true, error: null }); const data = await invoke>('yield_withdraw', { positionId, amount, }); const position = transformPosition(data); set((state) => ({ positions: state.positions.map((p) => (p.id === positionId ? position : p)), isLoading: false, })); return position; } catch (error) { set({ error: String(error), isLoading: false }); throw error; } }, listPositions: async () => { try { set({ isLoading: true, error: null }); const data = await invoke[]>('yield_list_positions'); const positions = data.map(transformPosition); set({ positions, isLoading: false }); } catch (error) { set({ error: String(error), isLoading: false }); } }, compound: async (positionId: string) => { try { const data = await invoke>('yield_compound', { positionId }); const position = transformPosition(data); set((state) => ({ positions: state.positions.map((p) => (p.id === positionId ? position : p)), })); return position; } catch (error) { set({ error: String(error) }); throw error; } }, clearError: () => set({ error: null }), })); // Helper to format APY export const formatAPY = (apy: number): string => `${apy.toFixed(2)}%`; // Helper to format TVL export const formatTVL = (sompi: number): string => { const syn = sompi / 100_000_000; if (syn >= 1_000_000) return `${(syn / 1_000_000).toFixed(2)}M SYN`; if (syn >= 1_000) return `${(syn / 1_000).toFixed(2)}K SYN`; return `${syn.toFixed(2)} SYN`; }; // Helper to format sompi to SYN export const formatAmount = (sompi: number): string => { const syn = sompi / 100_000_000; return `${syn.toFixed(8)} SYN`; };