Skip to content

Gate rounds voting by delegated Gnars votes#114

Closed
xSatori wants to merge 6 commits into
r4topunk:mainfrom
xSatori:feat/rounds
Closed

Gate rounds voting by delegated Gnars votes#114
xSatori wants to merge 6 commits into
r4topunk:mainfrom
xSatori:feat/rounds

Conversation

@xSatori

@xSatori xSatori commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

What this addresses

This PR upgrades rounds voting so future round votes are gated by delegated Gnars DAO governance voting power. A connected wallet now needs at least 1 delegated Gnars DAO vote from the Gnars token contract before it can vote in any rounds strategy.

Code to review

  • src/services/round-voting-power.ts

    • Adds the server-only delegated voting-power helper.
    • Reads DAO_ADDRESSES.token with serverPublicClient.readContract.
    • Uses getVotes(address) rather than balanceOf.
    • Validates and normalizes wallet addresses with Viem.
    • Returns 0 on RPC/read failure so voting is blocked instead of granted.
  • src/services/rounds.ts

    • Updates getRoundVotingPower to gate every strategy behind delegated Gnars votes.
    • one_per_wallet returns 1 only when delegated voting power is positive.
    • fixed_per_wallet returns round.votesPerWallet only when delegated voting power is positive.
    • one_per_nft now returns delegated governance voting power.
  • src/app/api/rounds/[slug]/voting-power/route.ts

    • Adds GET /api/rounds/[slug]/voting-power?wallet=....
    • Validates slug and wallet.
    • Returns walletAddress, votingPower, usedVotes, and remainingVotes.
  • src/components/rounds/RoundDetailView.tsx

    • Fetches voting power while voting is open and a wallet is connected.
    • Uses remainingVotes for allocation limits and submit enablement.
    • Shows clear copy when the wallet has no delegated Gnars voting power.
    • Hides voting controls for wallets with 0 voting power.
    • Refetches voting power and refreshes the route after successful submit.
  • Regression coverage

    • src/services/round-voting-power.test.ts
    • src/app/api/rounds/[slug]/voting-power/route.test.ts
    • src/components/rounds/RoundDetailView.test.tsx

Test plan

  • pnpm test
    • 11 test files passed
    • 86 tests passed
    • 1 todo
  • pnpm lint
    • passed with 0 errors
    • existing warnings remain for <img> usage outside the rounds files

Review notes

The main behavior to review is the mapping between delegated governance votes and each rounds voting strategy, especially one_per_nft, which now uses delegated Gnars DAO voting power directly instead of the previous safe one-wallet fallback.

xSatori and others added 6 commits May 26, 2026 15:26
Align timeline markers and progress, move winner count into the awards section, and refine winner and prize presentation on round detail pages.
Blocker fixes for the Rounds feature (stacked on feat/rounds):

#1 Signature verification — the write path (request/submit/vote) was
non-functional for all users. The client signs via thirdweb
account.signMessage, which returns an ERC-1271/6492 smart-account
signature (every wallet is AA-wrapped, sponsorGas:true), but the server
verified with viem's offline EOA-only verifyMessage utility (no client),
which can't validate contract signatures. Move verification to a
server-only module using viem's public-client verifyMessage Action with
the Base serverPublicClient. Forms now bind the signed message to the
active (smart) account address (the actual signer) instead of the EOA
view address, so the embedded wallet matches the signature.

r4topunk#2 Admin PII leak — /rounds/admin was an ungated Server Component that
fetched round requests (requester name + email) and passed them as props
to a client component whose isAdmin check only hides DOM, so the RSC
payload shipped emails to every visitor. Requests now load client-side
from a new signature-gated POST /api/rounds/admin/requests route that
verifies an approved-admin signature before returning PII. The admin
dashboard signs with the admin EOA (allowlist is EOA-keyed) when
available.

r4topunk#4 Typecheck — annotate the implicit-any row mapper in services/rounds.ts
(now tsc-clean once pg is installed).

Also: document ROUNDS_DATABASE_URL / DATABASE_URL in env.example, and add
unit tests covering the signing-message/digest contract that keeps client
and server in agreement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes the missing admin write path (review finding r4topunk#3): nothing wrote the
`rounds` table, so listPublicRounds always returned empty and the
submit/vote loop was unreachable. Now an approved admin can turn a pending
round request into a live round directly from the dashboard.

- services/rounds.ts: approveRoundRequest() — transactional; builds a
  published+active round (and round_awards) from the request's already-
  validated fields, marks the request approved. Slug collisions resolve to
  the next free `${slug}-${n}`. rejectRoundRequest() marks it rejected.
- validation.ts: resolveRoundSlug() — pure, unit-tested slug de-duplication.
- POST /api/rounds/admin/request-review — admin-gated (isRoundAdminAddress +
  signature whose payload binds requestId + decision, so an admin
  list/auth signature can't be replayed as an approval).
- RoundsAdminDashboard: Approve/Reject buttons on pending requests, shared
  signed-auth helper, refresh after approve.
- Tests: resolveRoundSlug (base/collision/fallback). 78 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 5, 2026

Copy link
Copy Markdown

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

A member of the Team first needs to authorize it.

xSatori commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

Closing this PR because the branch included the earlier rounds commit stack after upstream merged rounds via a squash commit. Reopened as a clean PR based on current main with only the delegated voting-power gate change: #115.

@xSatori xSatori closed this Jun 5, 2026
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