尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗A daily typing competition living inside MiniPay (Opera's wallet) on Celo — race a 45-second passage, get ranked by speed and accuracy, and the daily #1 wins the USDT prize pool, paid on-chain.
Live: typerush.fun
Built in Colombia
TypeRush is a casual mobile typing game with real stablecoin prizes, running inside MiniPay
on Celo mainnet. From a home lobby the player picks a mode (es/en) and a daily challenge,
then types a passage against a 45-second timer. The app measures WPM, accuracy, errors,
corrections and a final score, and ranks every player against everyone else who raced the same
mode that day.
The whole interface is bilingual (Spanish/English) and independent from the typing mode: you can read the app in English while typing a Spanish passage, or vice versa.
window.ethereum, alongside external wallets
(RainbowKit/wagmi) and an optional embedded wallet via Privy.Each mode (es/en) has a set of challenges built from curated passages. A race lasts 45 seconds;
per-character feedback marks correct/incorrect input live. Score is computed as:
mistakePenalty = Math.max(0.7, 1 - mistakeCount * 0.03) // soft penalty, up to −30%
score = Math.round(wpm * accuracy * progress * mistakePenalty * 100) // wpm = (correctChars / 5) / minute
The player's best score per challenge is kept in localStorage; every ranked race is also
persisted to Supabase for the leaderboard and profile history.
The entry fee, the pool and the payout are handled entirely on-chain by TypeRushGameV3,
deployed and verified on Celo mainnet (chainId 42220).
| Contract | TypeRushGameV3 |
| Address | 0xD8287809e0D68E7e50D0D962f11Eb72150F48d39 |
| Network | Celo mainnet · chainId 42220 |
| Entry token | USDT (0.10 per paid play) |
| Protocol fee | 20% of each entry (the rest funds the pool) |
| Payout model | Push — the operator calls settle(day, mode, winner, tokens) and the prize leaves for the winner's wallet in that same transaction. There is no separate claim step. |
settle only pays a wallet that actually has a recorded play for that day/mode on-chain
(played[day][mode][winner]), and rollover moves an unplayed pool forward untouched so a quiet
day never drains the prize. A seeding job tops each mode's pool up to a floor of 0.30 USDT so
the lobby never shows an empty pot.
Contract source lives in contracts/src/TypeRushGameV3.sol; see contracts/README.md for the
Foundry build/test/deploy workflow.
The live ranking for the open round is read from the same table the settlement robot uses
(v3_results, filtered by the contract's own currentDay()), so what the UI shows and what the
contract will actually pay always agree. Each player is ranked by their best race of the day; no
wallet address is ever sent to the browser — only an opaque per-round identifier, since who played
is already public on-chain. Historial and Perfil also show past rounds and a wallet's own results
history.
NEXT_PUBLIC_PRIVY_APP_ID is configured; without
it the app simply runs on MiniPay + external wallets.Every race, free or paid, is backed by a signed on-chain transaction, and scoring is fully server-authoritative:
play(mode, token) on the contract./api/plays reads the transaction receipt and only accepts a PlayRecorded log emitted by the
game contract itself — player, day, mode and free/paid all come from that log, never from the
client. Only after that check does the server hand back the passage to type./api/results recomputes WPM/accuracy/score from the stored passage, with plausibility clamps
(WPM ceiling, typed length can't exceed the passage, elapsed time is clamped to the race length,
plays expire).lib/settleV3.ts, invoked by /api/cron/settle-v3 on a Vercel cron
(00:10 / 00:25 / 00:45 UTC — 7:10 / 7:25 / 7:45 p.m. Colombia) and mirrored by a GitHub Actions
backup (settle-v3.yml, scripts/settle-v3.mjs). It picks the day's #1 per mode from
v3_results, calls settle() (or rollover() if nobody played), and tracks each attempt's state
(pending/processing/broadcast/paid/failed/rollover) so a transaction that was sent but not yet
confirmed is never retried as if it failed.scripts/seed-v3.mjs (GitHub Actions workflow seed-v3.yml, hourly) tops up
each mode's USDT pool to the floor once the previous day is settled. It only ever tops up — running
it more than once cannot add money twice.contracts/)next/fontnpm install # first time only
npm run dev # http://localhost:3000
By default the app is fail-closed like production: it expects a real wallet signature and a
configured Supabase project. To try a race locally without either, copy .env.example to
.env.local and set NEXT_PUBLIC_APP_ENV=development — races then run with no charge, no
ranking and no signing (lib/devPractice.ts). Never set this in a deployed environment: it would
let anyone play for free.
Build / type-check:
npm run build
Lint:
npm run lint
Unit tests (no external dependencies) and end-to-end checks:
npm test
npm run test:e2e
MiniPay requires HTTPS and a real device (emulators don't work). Expose your local server:
npx ngrok http 3000
Open the HTTPS ngrok URL on a phone with MiniPay installed, in Developer Mode → Use Testnet/Load
Test Page — the wallet injects window.ethereum automatically.
app/
layout.tsx — fonts, metadata, viewport
page.tsx — lobby + game states (idle → countdown → racing → finished)
historial/ — past rounds + winners history
perfil/ — wallet, alias, preferences, personal results
api/ — plays, results, ranking, history, settlement cron, welcome gas
components/
lobby/ — daily challenge card, leaderboard preview, how-to-play
profile/ — profile card, wallet balances, prizes, activity
CountdownScreen · RaceScreen · TypeField · Track · StatBlock · ResultScreen
RoundRanking · FullRanking · PlayV3Button · ClaimBanner · AppShell · BottomNav
hooks/
useTypeRush.ts — game state machine
useModeRanking.ts — live ranking of the open round
usePrizePools.ts — on-chain pool amounts + countdown to the daily close
lib/
i18n/ — UI language (independent from the typing mode)
game.ts — pure scoring logic + local best-score storage
passages.ts — modes, challenges and passage text
contractsV3.ts · playV3.ts · poolsV3.ts · settleV3.ts — GameV3 wiring
gamePeriod.ts — the daily reset window
winners.ts · leaderboard.ts · history.ts · roundRanking.ts
wallet.ts · walletSession.ts · operator.ts · supabase.ts
scripts/
settle-v3.mjs · seed-v3.mjs — the settlement and seeding robots
contracts/ — Foundry project: TypeRushGameV3 (active contract)
supabase/ — SQL schema, applied by hand in the Supabase SQL editor
Made with 💚 for the Celo / MiniPay ecosystem.