Show up. Play. Earn. Playces turns real-world venues into interactive social arenas — geofenced check-ins, embedded wallets, onchain mini-games (like the 67), chain/product airdrops, and collectible onchain rewards on Base.
Attendees check in at a venue, onboard with email (embedded wallet via Privy), play sponsor-skinned mini-games head-to-head, rep their favorite chain, and collect a memorable onchain reward. The reward reveal shows a 3D collectible artifact.
Be there. Play. Earn your moment.
| What | Network | Transaction |
|---|---|---|
| Cross-chain win badge over Chainlink CCIP | Arbitrum Sepolia → Ethereum Sepolia | CCIP message |
ENS subname ticket btcvibhav-ethglobal-nyc.playce.eth |
Sepolia | Registration tx |
Production contracts live in contracts/ (Foundry), verified on
Sourcify and browsable on Blockscout.
Machine-readable manifest: contracts/deployments/production.json.
Deployer: 0x88cb5e1fAee0798E2780618CF4fD12933E385426
| Network | Contract | Address (Blockscout) | Role |
|---|---|---|---|
| Base mainnet (8453) | PlaycesPass |
0xC1eF…50FC |
Soulbound memory / proof-of-presence mint |
| Base mainnet (8453) | StakeEscrow |
0x01D5…0823 |
Blink USDC stake escrow + winner settlement |
| Arbitrum Sepolia (421614) | ProofSender |
0xC1eF…50FC |
Chainlink CCIP sender → Ethereum Sepolia |
| Arbitrum Sepolia (421614) | PlaycesPass |
0x6847…7904 |
Direct win badge mint (Arbitrum-repped battles) |
| Ethereum Sepolia (11155111) | ProofReceiverPass |
0x6847…7904 |
CCIP receiver — win badge mint (Ethereum-repped battles) |
CCIP lane: Arbitrum Sepolia → Ethereum Sepolia. ProofSender must hold LINK
on Arbitrum Sepolia for cross-chain sends (~4 LINK per message at current fees).
- Gamified venue experience — bold arcade UX, mobile-first, light & dark.
- Email onboarding via Privy — embedded wallets created instantly, no seed
phrases. Attendees fund USDC on the settlement chain through Privy's
useFundWallet(card / exchange onramp), then stake a match via Blink. - ENS subname tickets — attendees pick a custom label (e.g.
alice) and claim an event-scoped ENSv2 subname (alice-ethglobal-nyc.playce.eth) on Sepolia. The backendregisters it on the Permissioned Registry (with Enhanced Access Control roles for renew / resolver / subregistry) and writesaddr,tier,event,description, andurlon the Permissioned Resolver. Gas is sponsored; there is no Preview mock when minting is disabled. - Geofenced check-in — location permission → "inside / outside zone" → check in, with clear fallback states.
- Mini-games hub — including the 67: two players stake p2p, the camera opens with a sponsor AR skin (Chainlink / Pyth / Blink), and they throw the 67 — best score wins the pot.
- Rep your chain + airdrops — sponsors drop rewards to attendees at the venue.
- Onchain reward mint — viem/wagmi-shaped states (preparing → signing → submitting → confirming → success).
- 3D reward reveal + shareable collectible page + rewards gallery.
| Area | Choice | Source |
|---|---|---|
| Framework | Next.js (App Router) + TypeScript | src/app/layout.tsx |
| Styling | Tailwind CSS v4 + shadcn-style UI primitives | src/app/globals.css |
| Motion | Framer Motion | src/components/hero.tsx |
| Auth/Wallet | Privy embedded wallets (@privy-io/react-auth, @privy-io/wagmi) |
src/lib/auth/privy-auth.tsx |
| Identity | ENS v2 subname tickets on Sepolia — custom labels, Permissioned Registry register + Permissioned Resolver records, resolved via viem's Universal Resolver |
src/lib/ens.ts, src/lib/server/ens-subname.ts |
| Chain | viem + wagmi — Base mainnet (8453) for proofs & staking; Arbitrum Sepolia + Ethereum Sepolia for chain-battle CCIP badges | src/components/providers.tsx, contracts/ |
| 3D | Three.js via React Three Fiber + drei | src/components/three/collectible-scene.tsx |
| State | Zustand (persisted rewards) | src/lib/store.ts |
# 1. Install dependencies
npm install
# 2. Configure Privy
cp .env.example .env.local
# then set NEXT_PUBLIC_PRIVY_APP_ID=... from https://dashboard.privy.io
# 3. Run the dev server
npm run devOpen http://localhost:3000.
Claim lives on /event/[slug] (catalog events). Attendees pick a custom label;
the server calls Permissioned Registry register then Permissioned Resolver
multicall on Sepolia. Requires all of:
ENS_SUBNAME_ENABLED=true
ENS_REGISTRY_ADDRESS=...
ENS_RESOLVER_ADDRESS=...
ENS_CHAIN_ID=11155111
ENS_PARENT_NAME=playce.eth
NEXT_PUBLIC_ENS_ENABLED=true
NEXT_PUBLIC_ENS_PARENT_NAME=playce.eth
MINTER_PRIVATE_KEY=... # must own playce.eth in the registry
SEPOLIA_RPC_URL=... # or NEXT_PUBLIC_SEPOLIA_RPC_URL
If minting is not configured, /api/ens/ticket returns 503 (no Preview
ticket). Demo registration: btcvibhav-ethglobal-nyc.playce.eth.
Sign in with email/Google → Privy creates an embedded wallet → Fund USDC
opens Privy's funding modal (useFundWallet) onto Base USDC → stake a chess
or 67 match via Blink. The fund button lives on the profile wallet card, account
menu, and both stake screens.
| Route | Description |
|---|---|
/ |
Hero, featured venues, how it works, why Playces |
/event/[slug] |
Venue hero, schedule, games, airdrops, venue map, check-in rail |
/play/67 |
The 67 game — lobby, stake, camera + AR sponsor skin, scoring |
/claim |
Check-in eligibility, geofence, wallet status, reward mint, 3D preview |
/collectible/[id] |
3D reward hero, NFT metadata, tx hash, share card |
/profile |
Collected rewards, history, wallet & email |
Deployed addresses and demo transactions are listed above. The sections below cover each contract's role, source verification, and local/testnet deploys.
- ERC-721 (
ERC721URIStorage+AccessControl). - One claim per
(eventId, wallet)— enforced onchain. - Soulbound — non-transferable proof you were there.
mintClaim(to, eventId, uri)gated byMINTER_ROLE.
Used on Base mainnet for geofenced memory clips and on Arbitrum Sepolia for direct chain-battle win badges.
- Holds Blink-deposited USDC on Base mainnet.
- Credits stakes per battle room;
settle(roomId, winner)pays the pot to the winner when they claim via/api/reward/claim.
- Chainlink CCIP cross-chain mint path for Ethereum-repped chain-battle wins.
- Backend holds
SENDER_ROLEonProofSender; receiver mints soulbound badges on Ethereum Sepolia when the CCIP message arrives.
cd contracts
forge testRe-submit or refresh Sourcify verification (syncs to Blockscout):
bash contracts/verify-all.shOr verify one contract manually:
cd contracts
forge verify-contract 0xC1eF7A81195538bc529b8Ed42182eC73764450FC \
src/PlaycesPass.sol:PlaycesPass \
--chain base \
--verifier sourcify \
--constructor-args $(cast abi-encode "constructor(address,address)" \
0x88cb5e1fAee0798E2780618CF4fD12933E385426 \
0x88cb5e1fAee0798E2780618CF4fD12933E385426)# Deploy PlaycesPass + StakeEscrow to Base Sepolia (dev)
bash contracts/deploy.sh
# Deploy CCIP sender/receiver + badge contracts (testnets)
bash contracts/deploy-ccip.sh
bash contracts/deploy-badge.shWire addresses into .env.local (see .env.example) and restart the dev server.
/play/67 is a full chain-battle mini-game: event-gated lobby, Blink USDC
staking, sponsor AR skins (Chainlink / Pyth / Arbitrum / Ethereum), camera-based
scoring, solo high-score mode, and onchain win badges + pot settlement via
/api/reward/claim.
Show up. Play. Earn.