This implementation replaces the localStorage-based position tracking with a persistent Supabase database. This ensures users can access their positions and markets from any browser or device by connecting their wallet.
✅ Cross-Device Persistence - Users can see their positions anywhere they connect their wallet
✅ No API Key Hardcoding - All credentials stored in .env.local
✅ Automatic Fallback - Falls back to localStorage if Supabase is not configured
✅ Transaction Tracking - Stores Solana transaction signatures with each position
✅ Market History - Tracks all markets a user has entered
lib/database/supabase.ts- Supabase client initializationlib/database/types.ts- TypeScript type definitions for database tableslib/database/positions-service.ts- Service layer for position CRUD operationslib/database/migrations/001_initial_schema.sql- SQL migration for table creation
hooks/use-positions.ts- Now fetches positions from Supabase (with localStorage fallback)hooks/use-deposit.ts- Automatically saves positions to database after successful deposits
components/deposit-modal.tsx- Passes required parameters to save positions
- Go to https://supabase.com and sign up/log in
- Create a new project
- Wait for the project to finish provisioning
- Navigate to your Supabase project dashboard
- Go to SQL Editor (in the left sidebar)
- Click New Query
- Copy the contents of
lib/database/migrations/001_initial_schema.sql - Paste into the SQL Editor
- Click Run to execute the migration
This will create:
user_positionstable with proper indexes- Automatic
updated_attimestamp triggers - Row Level Security policies
- In your Supabase project, go to Settings > API
- Copy your Project URL and anon/public key
- Create a
.env.localfile in the project root:
# Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=https://your-project-id.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here- Important: Never commit
.env.localto version control (it's already in.gitignore)
pnpm dev| Column | Type | Description |
|---|---|---|
id |
UUID | Primary key (auto-generated) |
wallet_address |
TEXT | User's Solana wallet address |
market_id |
TEXT | Unique market identifier |
market_question |
TEXT | The market's question/title |
position |
TEXT | 'YES' or 'NO' |
amount |
DECIMAL(20,6) | Deposit amount in USDC |
transaction_signature |
TEXT | Solana transaction signature |
timestamp |
TIMESTAMPTZ | When the position was created |
expiry_timestamp |
TIMESTAMPTZ | When the market expires |
status |
TEXT | 'active', 'claimed', or 'refunded' |
created_at |
TIMESTAMPTZ | Database record creation time |
updated_at |
TIMESTAMPTZ | Last update time |
idx_user_positions_wallet_address- Fast lookup by walletidx_user_positions_market_id- Fast lookup by marketidx_user_positions_status- Filter by statusidx_user_positions_wallet_status- Combined wallet + status queries
The service layer provides several convenience functions:
// Get all positions for a wallet
const positions = await getPositionsByWallet(walletAddress)
// Get only active positions
const activePositions = await getActivePositions(walletAddress)
// Get positions for a specific market
const marketPositions = await getPositionsByMarket(marketId)Positions are automatically created when users make deposits through the deposit-modal.tsx component:
await createPosition({
walletAddress: publicKey.toBase58(),
marketId,
marketQuestion,
position,
amount,
transactionSignature: signature,
timestamp: Date.now(),
expiryTimestamp,
})When a market is resolved, you can update position statuses:
await updatePositionStatus(positionId, "claimed")
// or
await updatePositionStatus(positionId, "refunded")If Supabase is not configured (missing environment variables), the system automatically falls back to localStorage:
- Positions are stored per wallet address in browser storage
- Data persists only on the same browser/device
- No cross-device synchronization
- Console warnings will indicate fallback mode
To check configuration status:
import { isSupabaseConfigured } from '@/lib/database/positions-service'
if (isSupabaseConfigured()) {
// Using Supabase
} else {
// Using localStorage fallback
}The database has RLS enabled with a permissive policy. For production, consider implementing wallet-based authentication:
-- Example: Restrict to authenticated users
CREATE POLICY "Users can only view their own positions"
ON user_positions
FOR SELECT
USING (wallet_address = auth.jwt() ->> 'wallet_address');- The
NEXT_PUBLIC_SUPABASE_ANON_KEYis safe to expose in the browser - It only has permissions you configure in Supabase RLS policies
- Never expose your service role key or other sensitive credentials
- Ensure
.env.localexists in the project root - Verify the file contains valid
NEXT_PUBLIC_SUPABASE_URLandNEXT_PUBLIC_SUPABASE_ANON_KEY - Restart your development server after adding environment variables
- Check browser console for errors
- Verify the SQL migration ran successfully in Supabase
- Check Supabase logs for any RLS policy issues
- Ensure wallet is connected
- Verify your Supabase project is running
- Check your internet connection
- Verify the project URL in
.env.localis correct - Check Supabase dashboard for any service issues
Existing positions stored in localStorage will not automatically migrate to the database. Users will need to:
- View their positions one final time (they'll load from localStorage)
- After Supabase is configured, new deposits will save to the database
- Old positions will remain in localStorage but won't appear after clearing browser data
To implement a migration script, you could:
// Example migration (run once per user)
function migrateLocalStorageToSupabase(walletAddress: string) {
const stored = localStorage.getItem(`poly_yield_positions_${walletAddress}`)
if (stored) {
const positions = JSON.parse(stored)
// Batch insert to Supabase
positions.forEach(pos => createPosition({...pos, walletAddress}))
// Optionally clear localStorage after successful migration
}
}- Implement wallet-based authentication for RLS
- Add position update endpoints for claiming/refunding
- Create admin dashboard for market resolution
- Implement real-time subscriptions for live position updates
- Add analytics and reporting queries
For issues or questions:
- Check the Supabase Documentation
- Review the
SUPABASE_SETUP.mdguide - Check Supabase project logs in the dashboard