documentation

How GitGrid works.

Connect GitHub, your verified contributions become a sybil-resistant grid score, seasonal leaderboards rank devs, and the top grids split the $GITGRID pool on Base. Here's every moving part.

product

Overview

The GitHub contribution graph is the most recognizable image in software. GitGrid turns it into a game. You connect GitHub and a Base wallet; your verified contribution activity becomes your grid score (“grid”). Seasonal leaderboards rank devs by grid, and top grids split a $GITGRID reward pool.

Honest framing: the value here is the narrative and the meme, not deep utility — and that's the point. It's a tight first launch and a beachhead for sister concepts. The token stays dumb; all game logic lives off-chain so scoring can iterate without redeploying contracts.

  • $GITGRID
  • Base L2
  • prove your grid
  • commit · rank · earn
product

The game loop

Five steps, one grind:

  1. 1 · Sync — pull your contribution calendar + repo metadata from GitHub's GraphQL + REST APIs for the active season window.
  2. 2 · Score — compute a sybil-resistant grid score. Daily activity maintains a streak.
  3. 3 · Rank — global + seasonal leaderboards, recomputed on a cron (every ~15 min) and cached in Redis.
  4. 4 · Reward — at season close, top grids claim $GITGRID through a Merkle distributor on Base.
  5. 5 · Flex — mint your grid as an NFT snapshot, the shareable artifact that pulls the next dev in.
product

Grid score

Raw commit count is trivially farmable, so the score rewards real work. The MVP formula weights contributions by repo reputation, then caps by account age and multiplies by a streak bonus:

gridScore =
  ( Σ commit · repoWeight
  + Σ pr     · repoWeight · prToOthersBonus
  + reviews  · reviewWeight )
  × accountAgeFactor
  × streakBonus

repoWeight grows with a repo's stars (logarithmically) and craters for the things farmers abuse:

  • forks → near-zero weight
  • brand-new repos (< 30 days) → heavily penalized
  • private repos → discounted (can't be verified publicly)
  • your own 0-star repos → clamped to a spam floor, regardless of commit volume

accountAgeFactor ramps from a floor up to full credit at ~90 days, capping week-old accounts. streakBonus rewards consecutive-day activity up to a cap. Every weight lives in a tunable ScoringConfig so the rules tighten season over season without touching the formula.

product

Anti-sybil — the grid never lies

Treat scoring as adversarial from day one — it's the difference between “fun” and “farmed to zero in 48h.” The quality signals come straight from GitHub:

  • Contribution calendar — the green-squares daily counts.
  • Repo reputation — stars, forks, and age of the repos commits land in.
  • PRs into others' repos — merged PRs to repos you don't own count heavily; they're hard to fake.
  • Account age — caps the score of fresh accounts.

The result: a bot with 12,400 raw commits across 50 fresh 0-star repos scores a 41, while a real dev with merged PRs into popular repos scores 1,842. More commits, lower score.

product

Seasons & rewards

A season is a fixed time window with a $GITGRID pool. Scores accrue during the window; a cron job recomputes ranks continuously. At endsAt the worker finalizes the season:

  1. 1 — freeze scores and assign final ranks
  2. 2 — allocate the pool across the top N grids, proportional to grid score, in exact integer wei (no dust lost)
  3. 3 — open the next season automatically (idempotent)
  4. 4 — an admin script builds a Merkle tree of (address, amount) and publishes the root on-chain; users then claim

Claims are trustless: a GridRewardsDistributor contract verifies a Merkle proof and transfers $GITGRID, marking the season claimed per address.

engineering

Architecture

Two long-running services (web + worker), Postgres, and Redis — all on Railway. Contracts live on Base, deployed separately with Foundry.

Browser ──OAuth──▶ Next.js (web)  ◀── RainbowKit / wagmi
                     │ Prisma
                     ▼
                 PostgreSQL ◀──────┐
                     ▲             │ BullMQ
                     │         ┌───┴────┐
   GitHub GraphQL ◀──┼─────────│ worker │  sync + scoring
   + REST            │         │  + cron │  + season rollover
                     ▼         └────────┘
                   Redis (jobs + leaderboard cache)
                     │ publishes Merkle root each season
                     ▼
   Base L2: $GITGRID ERC-20 · GridRewardsDistributor · GridSnapshot (v2)
engineering

Data model

Prisma + PostgreSQL. The core entities:

User          githubId, githubLogin, avatarUrl,
              walletAddress?, accountAgeAt
SeasonScore   userId, seasonId, gridScore, rawCommits,
              streakDays, rank?, rewardWei?, claimed
Season        index, startsAt, endsAt, poolWei, merkleRoot?
SyncRun       userId, startedAt, status
GridSnapshot  userId, year, svg, tokenId?   (v2 NFT)

rewardWei and poolWei are stringified bigints. A wallet is linked only after the user signs a nonce message proving ownership — the address is never trusted blindly.

engineering

Tech stack

Web + API
Next.js 15 (App Router, TS)
Auth
Auth.js (NextAuth) — GitHub provider
ORM / DB
Prisma + PostgreSQL
Jobs / cache
BullMQ + Redis
Wallet
wagmi + viem + RainbowKit (Base)
UI
Tailwind v4 + shadcn/ui + custom canvas
Contracts
Foundry + OpenZeppelin
Host
Railway (web + worker + Postgres + Redis)
engineering

Smart contracts

On-chain surface is deliberately tiny — token + claims + (later) NFT. Everything else stays off-chain.

  • $GITGRID ERC-20 — standard fixed-supply token (or a fair launch via a Base launcher).
  • GridRewardsDistributor — owner sets a Merkle root per season; claim(seasonIndex, amount, proof) transfers $GITGRID and marks claimed via a per-season bitmap (OpenZeppelin MerkleProof).
  • GridSnapshot ERC-721 (v2) — mints a rendered grid, tokenURI → IPFS.

The Merkle root is published from a controlled admin script — the distributor owner key is never in the running app.

engineering

Deployment

One Railway project, four components: web (public domain), worker (no port), plus Postgres and Redis plugins that inject DATABASE_URL / REDIS_URL. Migrations run via prisma migrate deploy.

GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET   # OAuth
AUTH_SECRET                                # NextAuth
DATABASE_URL / REDIS_URL                   # Railway plugins
NEXT_PUBLIC_CHAIN_ID=8453                  # Base mainnet
NEXT_PUBLIC_BASE_RPC
NEXT_PUBLIC_WALLETCONNECT_ID
GITHUB_SYNC_TOKEN                          # worker, higher limits
DISTRIBUTOR_OWNER_PK                       # admin script ONLY
more

Roadmap

MVP: GitHub OAuth + wallet link · contribution sync + grid score · global + season-1 leaderboard · branded grid UI · $GITGRID on Base with a season-1 Merkle claim.

v2+: grid-snapshot NFT mint · $GITGRID staking → score multiplier · cosmetic grid themes (token sink) · tighter anti-sybil (signed-commit requirement, anomaly detection) · team / org grids.