Soroban smart contracts for on-chain audit and verification of AnonVote ballots.
This repo contains all Stellar/Soroban contract code for the AnonVote ecosystem. Contracts provide on-chain queryable state that complements the off-chain privacy engine — giving anyone the ability to verify ballot integrity directly on the Stellar ledger without trusting AnonVote's servers.
| Repo | Relationship |
|---|---|
| AnonVote/core | Backend calls sorobanService.ts which invokes these contracts |
| AnonVote/js | No dependency — contracts are Rust, not JS |
| AnonVote/protocol | Whitepaper references contract audit model |
The primary Soroban contract. Records immutable audit events on-chain with public read access.
| Function | Description |
|---|---|
initialize(admin) |
One-time setup after deployment. Sets the admin address. |
record_ballot(ballot_id_hash) |
Register a ballot on-chain. Input is SHA-256 hex of the ballot UUID. |
record_token(ballot_id_hash) |
Increment the token-issued count for a ballot. |
record_vote(ballot_id_hash) |
Increment the vote-cast count for a ballot. |
record_result(ballot_id_hash, result_hash) |
Publish the result hash (SHA-256 of tally JSON). Immutable once set. |
get_tokens_issued(ballot_id_hash) |
Read token count (view call). |
get_votes_cast(ballot_id_hash) |
Read vote count (view call). |
get_result_hash(ballot_id_hash) |
Read result hash (view call). |
ballot_exists(ballot_id_hash) |
Check if a ballot has been recorded on-chain. |
is_consistent(ballot_id_hash) |
Returns true if tokens_issued == votes_cast. |
Privacy guarantees:
- No voter identifiers stored
- No token values stored
- No vote content stored
- Only counts and hashes — same privacy model as the off-chain system
A fully-typed TypeScript wrapper around the Soroban contract, ready to wire into AnonVote/core. Uses stellar-sdk v12 with correct RPC, simulation, and assembly APIs.
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Add WASM target
rustup target add wasm32-unknown-unknown
# Install Stellar CLI
cargo install --locked stellar-cli --features optcd contracts/anonvote
cargo build --target wasm32-unknown-unknown --releaseOutput: target/wasm32-unknown-unknown/release/anonvote.wasm
cd contracts/anonvote
cargo testAll tests run in the Soroban native test environment — no network required.
# Deploy the contract WASM
stellar contract deploy \
--wasm contracts/anonvote/target/wasm32-unknown-unknown/release/anonvote.wasm \
--source <YOUR_SECRET_KEY> \
--network testnet
# Output: CONTRACT_ID (e.g. CABC123...)
# Initialize with your admin public key
stellar contract invoke \
--id <CONTRACT_ID> \
--source <YOUR_SECRET_KEY> \
--network testnet \
-- initialize \
--admin <YOUR_PUBLIC_KEY>Then add to core's backend/.env:
SOROBAN_CONTRACT_ID=<CONTRACT_ID>Once deployed, the sorobanService.ts helpers are called from these locations in AnonVote/core:
| Core file | Contract call |
|---|---|
services/ballotEngine.ts |
sorobanRecordBallot(ballotIdHash) |
services/identityManager.ts |
sorobanRecordToken(ballotIdHash) |
services/privacyEngine.ts |
sorobanRecordVote(ballotIdHash) |
services/resultEngine.ts |
sorobanRecordResult(ballotIdHash, resultHash) |
The ballot_id_hash argument is hashIdentifier(ballotId) from @anonvote/crypto.
contracts/
├── contracts/
│ └── anonvote/
│ ├── src/
│ │ └── lib.rs # Soroban contract implementation
│ ├── Cargo.toml
│ └── README.md
├── service/
│ └── sorobanService.ts # TypeScript service stub for core
└── README.md