Problem
AnonVote's public verifiability guarantee is the feature that
differentiates it from every other voting tool — and it does
not exist yet. The results page renders hardcoded placeholder
data. The tally engine is not implemented. The Soroban
finalise_result contract is never called from core. There
is no self-verification flow for voters. There is no audit
export for organisations that need a record of the election
for compliance or governance purposes. The results page
requires a login to view which defeats the purpose of
public verifiability entirely.
These gaps mean AnonVote currently cannot deliver on its
core value proposition after a ballot closes.
Solution
Implement the full post-ballot flow — tally computation,
on-chain finalisation, public results display, voter
self-verification, and audit export — so the outcome of
every AnonVote election is independently verifiable by
anyone.
Backend
- Implement the tally engine — fetch all encrypted vote
payloads for a closed ballot, decrypt each via decryptVote
from @anonvote/crypto using the per-ballot encryption key,
count by option, produce a final tally map
- Add POST /admin/ballots/:id/finalise route — run the tally
engine, call finalise_result on the Soroban contract, store
the transaction ID, mark the ballot as finalised — make
this fully idempotent so calling it twice returns the
existing result without a duplicate on-chain write
- Add GET /ballots/:id/results public route — returns tally,
total vote count, Stellar transaction ID, and direct
explorer link — no authentication required, accessible
by anyone
- Add POST /ballots/:id/verify route — accepts a raw token,
hashes it server side, checks whether that hash exists
in the votes table for this ballot — returns a boolean
confirmed field only, no vote option, no other voter data
- Add GET /admin/ballots/:id/audit route — returns a
structured audit export with event log, vote count
timeline, token issuance summary, and Stellar transaction
IDs for all on-chain events — exportable as JSON and CSV
Frontend
- Remove the login requirement from the results page —
it must be publicly accessible via a shareable URL
- Build the public results page — option breakdown with
vote counts and percentages, total participation rate,
ballot metadata, Stellar transaction ID with explorer
link, and a copy link button for sharing
- Add a self-verification widget — token input field,
submit button, clear yes/no confirmation display —
no additional data shown beyond the boolean result
- Show a pre-results state when a ballot is still active
— display a live countdown to the deadline
- Build the audit export panel in the admin dashboard —
summary stats, downloadable JSON and CSV export buttons
Tests
- Unit test for tally engine — correct count per option,
handles empty ballot, handles single vote, handles
maximum voter count
- Unit test for idempotent finalisation — second call
returns existing result without triggering a second
Soroban write
- Unit test for self-verification — correct true for
a token that voted, correct false for a token that
did not vote, no vote option data in response
- Unit test confirming results route requires no
authentication — request without token returns 200
- Component test for self-verification widget — correct
confirmation display for true and false responses
- E2E test covering full post-ballot flow from finalisation
trigger to public results page with working Stellar link
Acceptance Criteria
Note for contributors
The self-verification endpoint is a privacy boundary. It must
return only a boolean. Do not return the vote option, the
voter's identifier hash, the token hash, or any aggregate
data about the ballot that is not already on the public
results page. If in doubt, return less.
Problem
AnonVote's public verifiability guarantee is the feature that
differentiates it from every other voting tool — and it does
not exist yet. The results page renders hardcoded placeholder
data. The tally engine is not implemented. The Soroban
finalise_result contract is never called from core. There
is no self-verification flow for voters. There is no audit
export for organisations that need a record of the election
for compliance or governance purposes. The results page
requires a login to view which defeats the purpose of
public verifiability entirely.
These gaps mean AnonVote currently cannot deliver on its
core value proposition after a ballot closes.
Solution
Implement the full post-ballot flow — tally computation,
on-chain finalisation, public results display, voter
self-verification, and audit export — so the outcome of
every AnonVote election is independently verifiable by
anyone.
Backend
payloads for a closed ballot, decrypt each via decryptVote
from @anonvote/crypto using the per-ballot encryption key,
count by option, produce a final tally map
engine, call finalise_result on the Soroban contract, store
the transaction ID, mark the ballot as finalised — make
this fully idempotent so calling it twice returns the
existing result without a duplicate on-chain write
total vote count, Stellar transaction ID, and direct
explorer link — no authentication required, accessible
by anyone
hashes it server side, checks whether that hash exists
in the votes table for this ballot — returns a boolean
confirmed field only, no vote option, no other voter data
structured audit export with event log, vote count
timeline, token issuance summary, and Stellar transaction
IDs for all on-chain events — exportable as JSON and CSV
Frontend
it must be publicly accessible via a shareable URL
vote counts and percentages, total participation rate,
ballot metadata, Stellar transaction ID with explorer
link, and a copy link button for sharing
submit button, clear yes/no confirmation display —
no additional data shown beyond the boolean result
— display a live countdown to the deadline
summary stats, downloadable JSON and CSV export buttons
Tests
handles empty ballot, handles single vote, handles
maximum voter count
returns existing result without triggering a second
Soroban write
a token that voted, correct false for a token that
did not vote, no vote option data in response
authentication — request without token returns 200
confirmation display for true and false responses
trigger to public results page with working Stellar link
Acceptance Criteria
or other voter data exposed
as JSON and CSV
Note for contributors
The self-verification endpoint is a privacy boundary. It must
return only a boolean. Do not return the vote option, the
voter's identifier hash, the token hash, or any aggregate
data about the ballot that is not already on the public
results page. If in doubt, return less.