Stores¶
This directory contains Pinia stores for state management in the Mentat Protocol Vue 3 application.
Available Stores¶
1. Auth Store (auth.ts)¶
Status: ✅ Complete (M2)
Manages user authentication state including: - JWT token management - User session - Login/logout operations - Email/password and wallet authentication
Usage:
import { useAuthStore } from '@/stores/auth';
const authStore = useAuthStore();
// Check authentication
if (authStore.isAuthenticated) {
console.log('User:', authStore.user);
}
// Login
await authStore.login(email, password);
// Logout
authStore.logout();
2. Wallet Store (wallet.ts)¶
Status: ✅ Complete (M3 Phase 3)
Manages Solana wallet connection state including: - Multi-wallet support (Phantom, Solflare) - Connection/disconnection - Auto-connect on page load - Transaction signing (single & batch) - Message signing - LocalStorage persistence
Usage:
import { useWalletStore } from '@/stores/wallet';
const walletStore = useWalletStore();
// Check connection
if (walletStore.connected) {
console.log('Address:', walletStore.publicKeyBase58);
console.log('Short:', walletStore.shortAddress);
}
// Connect wallet
await walletStore.connect(walletAdapter);
// Disconnect
await walletStore.disconnect();
// Sign transaction
const signed = await walletStore.signTransaction(transaction);
// Sign message
const signature = await walletStore.signMessage(message);
// Open wallet modal
walletStore.openWalletModal();
State:
- wallet - Current wallet adapter
- publicKey - User's Solana public key
- connected - Connection status
- connecting - Connection in progress
- disconnecting - Disconnection in progress
- walletModalOpen - Modal visibility
- autoConnect - Auto-connect preference
Computed:
- walletName - Current wallet name
- walletIcon - Wallet icon URL
- publicKeyBase58 - Public key as base58 string
- shortAddress - Truncated address (e.g., "Abc1...Xyz9")
Actions:
- connect(wallet) - Connect to wallet
- disconnect() - Disconnect wallet
- signTransaction(tx) - Sign single transaction
- signAllTransactions(txs) - Sign multiple transactions
- signMessage(message) - Sign arbitrary message
- openWalletModal() - Open wallet selection modal
- closeWalletModal() - Close modal
- setAutoConnect(enabled) - Enable/disable auto-connect
3. Trading Store (trading.ts)¶
Status: 🏗️ Skeleton (M3 Phase 4)
Manages trading state and operations including: - Position management - Liquidity positions - Trade execution - Transaction tracking - Portfolio summary
Usage (once implemented):
import { useTradingStore } from '@/stores/trading';
const tradingStore = useTradingStore();
// Execute trade
const result = await tradingStore.executeTrade({
marketId: 'market-123',
marketPublicKey: new PublicKey('...'),
outcomeIndex: 0,
isBuy: true,
amount: BigInt(10 * LAMPORTS_PER_USDC),
maxSlippage: 1,
});
// Load positions
await tradingStore.loadPositions(walletPublicKey);
// Get portfolio summary
const summary = await tradingStore.getPositionSummary(walletPublicKey);
console.log('Total value:', summary.totalValue);
console.log('Total PnL:', summary.totalUnrealizedPnL);
// Add liquidity
await tradingStore.addLiquidity({
marketId: 'market-123',
marketPublicKey: new PublicKey('...'),
amount: BigInt(100 * LAMPORTS_PER_USDC),
});
// Set active market
tradingStore.setActiveMarket('market-123');
// Refresh all data
await tradingStore.refresh(walletPublicKey);
State:
- activeMarket - Currently active market ID
- positions - User positions across all markets
- liquidityPositions - User liquidity positions
- recentTrades - Recent trades for active market
- pendingTransactions - Pending transaction tracking
- loading - Loading state
- error - Error state
- lastRefresh - Last refresh timestamp
Computed:
- hasOpenPositions - Whether user has positions
- hasLiquidityPositions - Whether user has LP positions
- totalPortfolioValue - Total value across all positions
- totalUnrealizedPnL - Total unrealized profit/loss
- totalUnrealizedPnLPercentage - PnL percentage
- numActiveMarkets - Number of markets with positions
- activeMarketPositions - Positions for active market
- activeMarketLiquidityPosition - LP position for active market
- hasPendingTransactions - Whether there are pending txs
- pendingTransactionsArray - Pending txs as array
Actions:
- executeTrade(params) - Execute buy/sell trade
- addLiquidity(params) - Add liquidity to market
- removeLiquidity(params) - Remove liquidity from market
- loadPositions(wallet) - Load user positions
- loadRecentTrades(marketId) - Load recent trades
- getPositionSummary(wallet) - Get portfolio summary
- setActiveMarket(marketId) - Set active market
- addPendingTransaction(...) - Track pending transaction
- updateTransactionStatus(...) - Update transaction status
- clearPositions() - Clear all positions
- clearError() - Clear error state
- refresh(wallet) - Refresh all data
Implementation Status: - ✅ Complete type-safe API - ✅ Full reactive state management - ✅ Transaction tracking - ✅ Error handling - ⏳ TODO: Implement with SolanaProgramService once programs deployed
Store Architecture¶
┌─────────────────────────────────────────────────────┐
│ Vue 3 Components │
│ ┌────────────────┐ ┌──────────────────────────┐ │
│ │ AuthModal │ │ WalletConnectButton │ │
│ │ UserProfile │ │ WalletModal │ │
│ └────────┬───────┘ └──────────┬───────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────┐ ┌────────────────────────┐ │
│ │ Auth Store │ │ Wallet Store │ │
│ │ (Pinia) │ │ (Pinia) │ │
│ └────────────────┘ └────────┬───────────────┘ │
│ │ │
│ ┌────────────────┐ │ │
│ │ Trading │◄────────────┘ │
│ │ Components │ │
│ └────────┬───────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────┐│
│ │ Trading Store (Pinia) ││
│ │ - Uses Wallet Store for signing ││
│ │ - Manages positions and trades ││
│ └────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────┘
Usage Patterns¶
1. Store Composition¶
Stores can use other stores:
import { useWalletStore } from './wallet';
export const useTradingStore = defineStore('trading', () => {
const walletStore = useWalletStore();
async function executeTrade(params) {
// Check wallet connected
if (!walletStore.connected) {
throw new Error('Wallet not connected');
}
// Use wallet to sign transaction
const signed = await walletStore.signTransaction(tx);
// ...
}
return { executeTrade };
});
2. Reactive State in Components¶
<script setup lang="ts">
import { useWalletStore } from '@/stores/wallet';
const walletStore = useWalletStore();
// Reactive - auto-updates when store changes
const isConnected = computed(() => walletStore.connected);
const address = computed(() => walletStore.shortAddress);
</script>
<template>
<div v-if="isConnected">
Connected: {{ address }}
</div>
<button v-else @click="walletStore.openWalletModal()">
Connect Wallet
</button>
</template>
3. Error Handling¶
const tradingStore = useTradingStore();
try {
await tradingStore.executeTrade(params);
} catch (error) {
if (tradingStore.error) {
console.error('Error code:', tradingStore.error.code);
console.error('Error message:', tradingStore.error.message);
// Handle specific errors
switch (tradingStore.error.code) {
case TradingErrorCode.WALLET_NOT_CONNECTED:
walletStore.openWalletModal();
break;
case TradingErrorCode.INSUFFICIENT_BALANCE:
// Show insufficient balance error
break;
// ...
}
}
}
4. State Persistence¶
The wallet store automatically persists to LocalStorage:
// Stored in localStorage:
// - walletName: Last connected wallet
// - autoConnect: Auto-connect preference
// Automatically restored on page load
const walletStore = useWalletStore();
// If previously connected, will auto-reconnect
Best Practices¶
1. Keep Stores Focused¶
Each store should have a single responsibility: - Auth Store: User authentication only - Wallet Store: Wallet connection only - Trading Store: Trading operations only
2. Use Computed Properties¶
Don't duplicate logic in components:
// ❌ Bad - logic in component
const portfolioValue = computed(() => {
return positions.value.reduce((sum, p) => sum + p.value, 0);
});
// ✅ Good - logic in store
const portfolioValue = computed(() => tradingStore.totalPortfolioValue);
3. Handle Errors Properly¶
Always handle errors from store actions:
// ❌ Bad
await tradingStore.executeTrade(params);
// ✅ Good
try {
await tradingStore.executeTrade(params);
} catch (error) {
// Handle error
showNotification('Trade failed', 'error');
}
4. Clear State When Appropriate¶
// When user disconnects wallet
walletStore.$patch({
wallet: null,
publicKey: null,
connected: false,
});
// Clear trading state
tradingStore.clearPositions();
Testing Stores¶
Unit Testing¶
import { setActivePinia, createPinia } from 'pinia';
import { useWalletStore } from '@/stores/wallet';
describe('Wallet Store', () => {
beforeEach(() => {
setActivePinia(createPinia());
});
it('should initialize with disconnected state', () => {
const store = useWalletStore();
expect(store.connected).toBe(false);
expect(store.publicKey).toBeNull();
});
it('should connect to wallet', async () => {
const store = useWalletStore();
const mockWallet = createMockWallet();
await store.connect(mockWallet);
expect(store.connected).toBe(true);
expect(store.wallet).toBe(mockWallet);
});
});
Migration Guide¶
From Local State to Store¶
Before (local component state):
<script setup>
const wallet = ref(null);
const connected = ref(false);
async function connect() {
// connection logic
connected.value = true;
}
</script>
After (using store):
<script setup>
import { useWalletStore } from '@/stores/wallet';
const walletStore = useWalletStore();
async function connect() {
await walletStore.connect(walletAdapter);
}
</script>
Documentation¶
For detailed documentation on each store:
- Wallet Store: See docs/WALLET-INTEGRATION-IMPLEMENTATION.md
- Trading Store: See docs/PHASE-4-TRADING-INTERFACE-PLAN.md
- Auth Store: See docs/INTEGRATION.md (M2)
Last Updated: November 24, 2025