Skip to content

feat(rounds): gate voting by delegated Gnars votes at a fixed snapshot - #294

Merged
sktbrd merged 2 commits into
r4topunk:mainfrom
sktbrd:feat/rounds-voting-snapshot
Aug 23, 2026
Merged

feat(rounds): gate voting by delegated Gnars votes at a fixed snapshot#294
sktbrd merged 2 commits into
r4topunk:mainfrom
sktbrd:feat/rounds-voting-snapshot

Conversation

@sktbrd

@sktbrd sktbrd commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Supersedes #115, keeping all of @xSatori's structure (route, service, UI states, tests — co-authored in the commit) and adding the one change review demanded: the power is read at a fixed snapshot, not live.

  • The hole live getVotes left open: vote usage is tracked per (round, wallet) in Postgres, and nothing records which delegated power voted. A delegates to B → B votes → A re-delegates to C → C votes: the same Gnars vote once per hop, and on fixed_per_wallet every hop gets the FULL per-wallet allotment — delegation is free, so 10 Gnars + N empty wallets = N ballots. The gate this PR exists to build would leak through the very mechanism it gates on.
  • The fix: getPastVotes(wallet, round.votingStartsAt). The Gnars token runs timestamp clock mode (ERC-6372) — already documented in useCastVote.ts — so the round's opening instant is the timepoint directly; no block derivation, no schema change, same single RPC read. The checkpoint is immutable: re-delegating after voting opens moves nothing.
  • Policy this implements (decided by the operator): delegating transfers the vote — the delegate at the snapshot votes; a holder who has delegated does not. Same model as the DAO's onchain governor.
  • Future votingStartsAt returns 0 without touching the chain (ERC-5805 would revert; an unopened round has no snapshot).

Who can vote, before → after

  • Before this work: any connected wallet could vote in an open round.
  • After: only wallets with delegated Gnars voting power at the round's voting-open instant; weighted strategy uses that power as weight. Enforced server-side at vote submission (castRoundVote), not just in UI.

Test plan

  • Full suite 180 passed — includes new tests pinning the snapshot call (getPastVotes at the exact timestamp) and the future-round guard
  • tsc / eslint / prettier clean
  • Rounds is nav-hidden ("coming soon"), so no live-page capture applies; API + service behavior is test-covered

Generated with Claude Code

xSatori and others added 2 commits August 23, 2026 12:02
Builds on xSatori's r4topunk#115 (all UI/route/service structure is theirs):
rounds voting requires delegated Gnars voting power, enforced server-
side at vote submission.

One change on top: the power is read with getPastVotes at the round's
voting-open instant instead of live getVotes. Live votes let the same
Gnars vote once per re-delegation hop (A delegates to B, B votes, A
re-delegates to C, C votes — usage is tracked per wallet, so every hop
arrives fresh; on fixed_per_wallet each hop gets the FULL per-wallet
allotment). The checkpoint at votingStartsAt is immutable, so those
Gnars sat in exactly one wallet at that instant — the same snapshot
model the onchain governor uses, and the policy that comes with it:
delegating transfers the vote.

The Gnars token runs timestamp clock mode (ERC-6372), so the timepoint
is the round's votingStartsAt directly — no block derivation. A future
timepoint returns 0 without touching the chain (ERC-5805 would revert,
and an unopened round has no snapshot).

Co-authored-by: xSatori <99294685+xSatori@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 23, 2026

Copy link
Copy Markdown

@sktbrd is attempting to deploy a commit to the r4to's projects Team on Vercel.

A member of the Team first needs to authorize it.

@sktbrd
sktbrd merged commit ef464f3 into r4topunk:main Aug 23, 2026
1 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants