DVM voting
The DVM — Data Verification Mechanism — is OMY's Phase 2 resolver.
Stake $OMY, vote on disputed assertions, earn rewards from slashed bonds.
This page is for stakers (when Phase 2 launches) and for builders who want to
understand the mechanism their disputes will route through.
:::info Phase 2 status
The DVM contract is implemented and tested. The $OMY token has not
launched yet — we gate it on traction metrics (why).
This page describes how it works once it activates.
:::
The flow
Assertion enters Disputed
│
▼
Resolver opens a Case
│
▼
┌─── Round N ──────────────────────────┐
│ Commit window — stakers post a │
│ hashed vote + lock $OMY weight │
├──────────────────────────────────────┤
│ Reveal window — stakers reveal │
│ their plaintext vote │
├──────────────────────────────────────┤
│ Tally: │
│ - quorum (GAT) reached? │
│ - supermajority (SPAT, 65%)? │
│ YES → resolve answer; slash + reward│
│ NO → reopen round (max 3) │
└──────────────────────────────────────┘
Becoming a staker
- Acquire
$OMYfrom a public market. - Send
$OMYto theStakeVoteResolvercontract — the jetton-transfer notification increments your stake. - You can
Unstakeany amount that isn't currently locked in a commit.
Your free balance earns no rewards — it's the locked-on-commit stake that counts for vote weight and that can be slashed.
Voting on a case
When a disputed assertion sends OpenVote to the resolver, a Case is
opened. Stakers have until the commit deadline to:
- Compute a commitment hash =
H(answer || salt || assertion)
answer— the bool you believe is correctsalt— a random uint256 you keep secretassertion— address of the assertion under dispute (anti-collision)
- Send
CommitVote(case, hash, amount)— locksamount$OMYfrom your free balance into this case's escrow.
The locked amount IS your vote weight. You can split your stake across multiple cases if there are several disputes happening simultaneously.
Once the commit window closes, reveal:
- Send
RevealVote(case, answer, salt)— the resolver re-hashes your inputs and verifies against your commitment. If they match, your vote is counted. If you don't reveal, you're slashed.
Tally rules
After the reveal window closes:
| Check | Threshold | If pass | If fail |
|---|---|---|---|
| Quorum (GAT) | total revealed ≥ gatRequired | proceed | reopen round |
| Supermajority (SPAT) | winning side ≥ 65% of revealed | resolve | reopen round |
| Non-tie | winning side > losing side | resolve | reopen round |
If all three pass, the resolver sends Resolve{answer} to the disputed
assertion. The losing side's stake gets slashed; the winning side's stake +
the slashed pot gets distributed pro-rata to winners.
If any check fails, the case reopens for another round (up to 3). Each round has fresh commit/reveal windows; stakers can re-stake or sit it out.
After 3 failed rounds, anyone can call AbandonCase — all locked stake
becomes claimable, the assertion eventually settles via TimeoutRefund.
Rewards & slashing
Conservation: sum(rewards) == sum(slashes). Nothing comes from the
protocol budget; nothing accrues as protocol surplus. The voting pot is
self-funded by losers.
| Outcome | Your stake (committed amount) |
|---|---|
| You revealed + voted with the winning side | Returned + share of slashed pot |
| You revealed + voted with the losing side | Slashed (default 10% — see params) |
| You committed but did not reveal | Slashed (default 100% — punishes spam-commit-and-grief) |
| You did not commit | Nothing — stake stays in your free balance |
Rewards are claim-based — call Claim(case) after the case resolves to
withdraw your principal + reward. No automatic distribution; gas is paid by
the claimant.
Anti-attack properties
Stake locked at commit, not reveal. This kills the "commit cheap, stake big only if winning" attack. Your weight is what you locked at commit time — you can't observe the reveal window and then load up.
Commitment binds to the assertion address. Prevents reusing a hash across cases (defense-in-depth).
No-reveal slashing. Spamming commits is expensive. Real stakers reveal; attackers who commit-then-bail lose 100%.
Reopen cap = 3. Prevents indefinite-dispute DoS. After 3 rounds with no quorum, the case is abandoned; the assertion falls through to TimeoutRefund.
Parameters
These are settable at deploy by governance. The defaults that ship to mainnet will be tuned by an external economist; treat them as illustrative:
| Parameter | Default | Meaning |
|---|---|---|
commitWindow | 4 hours | How long stakers have to commit |
revealWindow | 4 hours | How long stakers have to reveal |
gatRequired | dynamic (snapshot at case open) | Min revealed stake for quorum |
gatFloor | 10 000 $OMY | Absolute minimum GAT |
spatBps | 6500 (65%) | Supermajority threshold |
slashBps | 1000 (10%) | Loser slash % |
noRevealSlashBps | 10000 (100%) | No-reveal slash % |
minCommit | 1 $OMY | Dust-prevention floor |
maxRounds | 3 | Reopen cap |
gatRequired is a snapshot of the dynamic (circulating $OMY × gatBps) at
case open — so it scales with token supply automatically, but is frozen for
the duration of the case.
What stakers should think about
import {DocFeatures, DocFeature} from '@site/src/components/docs/DocFeatures';
Source
The full implementation lives in
StakeVoteResolver.tolk.
It's ~600 lines of Tolk covering commit, reveal, tally, reopen, abandon,
claim, and the escrow accounting that makes it solvent under every input.
Related
- Governance overview — Phase 1 vs Phase 2
- Bonds & fees — how fees flow to stakers in Phase 2