High-Level Architecture
The Snapshot X platform consists of three main services plus external dependencies:Core Services
UI - Vue 3 Frontend
Location:apps/ui
Purpose: User interface for governance interactions
Technology Stack:
- Vue 3 with Composition API
- TailwindCSS for styling (custom theme)
- Vite for build tooling
- Pinia for state management
- Vue Query (TanStack Query) for server state
- Auto-imports for components, composables, and APIs
- Display governance data (spaces, proposals, votes)
- Connect user wallets (MetaMask, ArgentX, etc.)
- Create and submit proposals
- Cast votes through various authenticators
- Manage space configurations
- Onchain spaces: GraphQL queries to API
- Offchain spaces: GraphQL queries to snapshot-hub
- Transactions: JSON-RPC calls to Mana for gasless operations
- Direct transactions: Direct blockchain calls for non-gasless operations
API - GraphQL + Checkpoint Indexer
Location:apps/api
Purpose: Index blockchain events and serve governance data
Technology Stack:
- Apollo Server (GraphQL)
- Checkpoint (blockchain indexer)
- MySQL 8.0 (data storage)
- TypeScript
- Index governance events from multiple chains:
- Snapshot X spaces on EVM and Starknet
- Compound Governor contracts
- OpenZeppelin Governor contracts
- Transform blockchain data into queryable format
- Serve unified GraphQL API for spaces, proposals, votes, and users
- Support real-time subscriptions for live updates
- Full mode: Run both indexer and GraphQL API
- Indexer only: Index events without serving API
- API only: Serve API using existing database
Mana - Transaction Relayer
Location:apps/mana
Purpose: Relay transactions for gasless voting and cross-chain execution
Technology Stack:
- Express.js (HTTP server)
- ethers.js (Ethereum interactions)
- starknet.js (Starknet interactions)
- TypeScript
- Gasless voting: Accept signed messages and submit on behalf of users
- Cross-chain messaging: Handle L1↔L2 communication via Starknet messaging
- Automated execution: Execute approved proposals automatically
- Relayer wallet management: Manage hot wallets for transaction submission
SX.js - TypeScript SDK
Location:packages/sx.js
Purpose: Shared SDK for governance interactions
Published Package: @snapshot-labs/sx on npm
Key Exports:
External Services
snapshot-hub
Repository: snapshot-labs/snapshot-hub Purpose: API and data store for offchain Snapshot spaces Integration Point: UI queries snapshot-hub for offchain governance data Data Stored:- Offchain space configurations
- Offchain proposals (ENS-based spaces like
uniswap.eth) - Offchain votes
- User profiles and followers
snapshot-sequencer
Repository: snapshot-labs/snapshot-sequencer Purpose: Receives and validates signed messages for offchain governance Integration Point: UI submits signed proposals, votes, and space updates Message Types:- Proposals
- Votes
- Space settings updates
- User profile updates
Data Flow Examples
Creating an Onchain Proposal
Casting a Vote
Cross-Chain Voting (L1 → L2)
Deployment Architecture
Development Setup
- Docker (for MySQL)
- Node.js >= 22.6
- Yarn 1.22
Production Architecture
Key Design Decisions
Why Separate API and Mana?
Separation of Concerns
Separation of Concerns
API is read-heavy and stateless, making it easy to scale horizontally. Mana manages hot wallets and transaction queues, requiring careful state management and security.
Why Checkpoint for Indexing?
Checkpoint Benefits
Checkpoint Benefits
Checkpoint provides automatic reorg handling, checkpoint/resume functionality, and a unified interface for multiple chains. It reduces boilerplate code for blockchain indexing.
Why Monorepo?
Monorepo Advantages
Monorepo Advantages
- Shared code (sx.js) is easily reused across services
- Coordinated releases and versioning
- Single dependency management
- Easier local development with all services
Why Two Types of Clients?
Signature vs Transaction Clients
Signature vs Transaction Clients
- Signature clients enable gasless voting through Mana relay
- Transaction clients allow direct blockchain interaction when users pay gas
- Flexibility for different governance models and user preferences
Security Considerations
Performance Optimization
API Optimization
- Database Indexing: Index frequently queried columns (space_id, proposal_id, voter)
- Query Batching: Use DataLoader pattern in GraphQL resolvers
- Caching: Cache space configurations and static data
- Pagination: Always paginate large result sets
UI Optimization
- Code Splitting: Lazy-load routes and heavy components
- Vue Query Caching: Leverage stale-while-revalidate pattern
- Auto-imports: Tree-shake unused components and composables
- Image Optimization: Use CDN for user-uploaded images
Mana Optimization
- Transaction Queuing: Queue transactions to avoid nonce conflicts
- Gas Estimation: Cache gas estimates for common operations
- Batch Processing: Batch multiple votes in single transaction where possible
- Retry Logic: Implement exponential backoff for failed transactions
Monitoring and Observability
Key Metrics to Track:API Metrics
API Metrics
- Query response times
- Database connection pool usage
- Indexer sync lag (blocks behind head)
- GraphQL error rates
Mana Metrics
Mana Metrics
- Transaction success/failure rates
- Wallet balance levels
- Transaction queue depth
- Average gas used per operation
UI Metrics
UI Metrics
- Page load times
- Time to interactive (TTI)
- Core Web Vitals (LCP, FID, CLS)
- JavaScript bundle size
Next Steps
Quickstart Guide
Build your first governance integration
SDK Overview
Explore detailed SDK documentation
Contributing
Contribute to the Snapshot X platform
GitHub
View the source code