Skip to content

Feat/rounds#108

Merged
r4topunk merged 5 commits into
r4topunk:mainfrom
xSatori:feat/rounds
May 28, 2026
Merged

Feat/rounds#108
r4topunk merged 5 commits into
r4topunk:mainfrom
xSatori:feat/rounds

Conversation

@xSatori

@xSatori xSatori commented May 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a full Gnars Rounds experience for community contests, submissions, voting, and awards.
  • Adds public routes for browsing rounds, viewing round details, submitting entries, requesting new rounds, and accessing an admin dashboard.
  • Adds signed wallet-gated API flows for round requests, submissions, and vote allocation.
  • Adds Postgres-backed persistence for rounds, submissions, votes, awards, and round requests.
  • Adds EN/PT-BR nav + metadata copy and exposes Rounds in the DAO header under Money.

Implementation Notes

  • New routes:
    • /rounds
    • /rounds/[slug]
    • /rounds/[slug]/submit
    • /rounds/request
    • /rounds/admin
  • New API endpoints:
    • GET /api/rounds
    • GET /api/rounds/[slug]
    • POST /api/rounds/request
    • POST /api/rounds/[slug]/submit
    • POST /api/rounds/[slug]/vote
  • Uses ROUNDS_DATABASE_URL, falling back to DATABASE_PUBLIC_URL or DATABASE_URL.
  • Wallet signatures bind action, method, path, wallet, payload digest, and issued timestamp.
  • Includes validation/state helpers and focused unit tests for admin access, round state, and validation rules.

Testing

  • pnpm test — 7 test files passed, 70 tests passed, 1 todo.

xSatori added 3 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.
@vercel

vercel Bot commented May 26, 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.

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>
@r4topunk r4topunk merged commit 9ddfbd5 into r4topunk:main May 28, 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