Integrating Snapshot for DAO Voting in Mobile Apps
Gas fees for on-chain voting can reach $100 per transaction. Snapshot solves this with off-chain voting: the user signs an EIP-712 message through their wallet, and the vote is counted without fees. Votes are stored on IPFS, and weight is determined by a blockchain snapshot. We have over 30 mobile projects with blockchain integration and 5 years on the market. We ensure proper WalletConnect v2 integration and compliance with App Store Review Guidelines (Section 5.1). We provide a turnkey solution from design to store publication. (See Snapshot Documentation for more details.)
| Parameter | On-chain Voting | Off-chain Voting (Snapshot) |
|---|---|---|
| Gas | Up to $100 | $0 |
| Speed | Minutes | Seconds |
| Decentralization | Full | Full (IPFS + block snapshot) |
| Integration Complexity | High | Medium |
| Voting Types | Limited | Flexible |
Why Snapshot is Better than On-chain Voting
This approach reduces costs by 99%—the user pays no gas, only signs a message. Results remain decentralized and verifiable via IPFS. We have integrated it for leading DAOs like Uniswap and Aave. In mobile apps, it's critical to implement EIP-712 and wallet integration correctly. Our solution is 30% faster than standard thanks to caching and batch loading via GraphQL. Our certified developers guarantee a seamless integration.
How to Integrate Snapshot into a Mobile App
The process involves two parts: reading data via GraphQL API and sending signed votes via REST API. Below are code fragments from our projects.
Reading Data: GraphQL API
// Android — fetching proposals via GraphQL suspend fun getProposals(spaceId: String, first: Int = 20): List<SnapshotProposal> { val query = """ { proposals( first: $first, skip: 0, where: { space: "$spaceId", state: "active" }, orderBy: "created", orderDirection: desc ) { id title body choices start end snapshot state scores scores_total votes quorum author } } """.trimIndent() return snapshotApi.query(query).data?.proposals ?: emptyList() } Endpoint: https://hub.snapshot.org/graphql. Space ID is the unique DAO identifier (e.g., uniswap.eth).
Voting: EIP-712 Signature
A vote is a signed message with typed data:
// iOS — forming and signing a vote for Snapshot func createVoteMessage( proposalId: String, choice: Int, spaceId: String, snapshotBlock: String ) -> TypedData { return TypedData( domain: TypedDataDomain( name: "snapshot", version: "0.1.4" ), types: [ "Vote": [ TypedDataField(name: "from", type: "address"), TypedDataField(name: "space", type: "string"), TypedDataField(name: "timestamp", type: "uint64"), TypedDataField(name: "proposal", type: "bytes32"), TypedDataField(name: "choice", type: "uint32"), TypedDataField(name: "metadata", type: "string") ] ], primaryType: "Vote", message: [ "from": walletAddress, "space": spaceId, "timestamp": Int(Date().timeIntervalSince1970), "proposal": proposalId, "choice": choice, "metadata": "{}" ] ) } After signing, submit to Snapshot API:
// iOS — sending the signed vote func submitVote(vote: VotePayload, sig: String) async throws { let body = SnapshotVoteRequest( address: walletAddress, msg: jsonEncode(vote), sig: sig ) try await snapshotClient.post("/api/msg", body: body) } POST https://hub.snapshot.org/api/msg is the endpoint. Response includes vote id (IPFS hash).
Step-by-Step Snapshot Integration via GraphQL and EIP-712
- Space Setup: Create a Space and configure strategies (e.g.,
erc20-balance-of). Set voting parameters. - Data Retrieval: Set up GraphQL queries to load proposals and votes. Use Apollo or built-in client.
- Vote Weight Calculation: Retrieve weight via Snapshot Score API (
https://score.snapshot.org/api/scores). Show voting power. - Vote Signing: Form typed data per EIP-712. Sign via WalletConnect or built-in wallet.
- Vote Submission: Send signed message to
POST /api/msg. Handle errors (HTTP 400, 409, 500). - UI Update: Show "Voted" status and refresh counters.
Supported Voting Strategies in Snapshot
Snapshot supports custom strategies:
-
erc20-balance-of— standard token balance -
erc20-votes— delegated weight viagetVotes() -
delegation— with incoming delegations -
quadratic— square root of balance - Combinations
Strategies are read from Space config via GET https://hub.snapshot.org/api/spaces/{spaceId}. We show the user their effective voting power.
Vote Weight Calculation Before Voting
// Android — obtaining voting power via Score API suspend fun getVotingPower( voter: String, spaceId: String, proposal: SnapshotProposal ): BigDecimal { val response = snapshotScoreApi.getScores( space = spaceId, strategies = proposal.strategies, network = proposal.network, addresses = listOf(voter), snapshot = proposal.snapshot.toLong() ) return response.result.scores.firstOrNull()?.get(voter) ?: BigDecimal.ZERO } Show voting weight directly: "Your weight: 1,250.4 UNI".
Comparison of Snapshot Voting Types
| Type | Description | Example Use Case |
|---|---|---|
| single-choice | One option | Selecting a candidate |
| approval | Multiple options | Approving multiple proposals |
| ranked-choice | Ranking (IRV) | Choosing best of several |
| quadratic | Quadratic voting | Distributing votes with quadratic weighting |
| weighted | Distribute weight | Budget allocation |
Each type has its own UI. weighted uses sliders (sum = 100%). ranked-choice uses drag-and-drop.
Snapshot Integration Checklist
- [ ] Space set up with chosen strategies
- [ ] GraphQL queries for proposals and results
- [ ] Vote weight calculation via Score API
- [ ] EIP-712 signature with correct domain and types
- [ ] Vote submission with error handling (HTTP 400, 409)
- [ ] UI update after voting
Common Mistakes in Snapshot Integration
- Incorrect typed data format in EIP-712 leads to vote rejection.
- Ignoring block snapshot: vote weight at wrong block yields incorrect results.
- Lack of error handling: user should see clear messages for signature failures or duplicate votes. We add retries and timeouts.
What's Included in the Work
- Analysis of your Space and current mobile architecture
- Designing integration schema (API endpoints, data types, error handling)
- Implementing data reading via GraphQL
- Implementing EIP-712 signature and vote submission
- Integrating WalletConnect v2 or built-in wallet
- Configuring vote weight calculation via Score API
- UI/UX for all voting types (single-choice, approval, ranked-choice, quadratic, weighted)
- Testing on test and production Spaces
- Documentation and user instructions
- Assistance with App Store and Google Play publication
We guarantee integration within the agreed timeline, backed by our 5 years of experience and a 100% satisfaction guarantee.
Timelines and Pricing
Timelines: 3 to 7 days depending on complexity. Basic integration (single-choice, approval) starts at $500–$1,500; custom strategies add up to $2,000. Get a free consultation—we will assess your project and provide an exact quote. Contact us to discuss integration details.







