Play poker with frens via ENS names. Zero gas per hand, instant settlement on Yellow Network.
PlayFrens is an on-chain multiplayer game platform that solves one of the biggest UX problems in blockchain gaming — gas fees and latency on every action.
Built on Yellow Network state channels (ERC-7824), PlayFrens lets friends find each other by ENS name, deposit tokens once, and play unlimited poker hands with zero gas fees and instant settlement.
An earlier experimental project was developed within the GetFrens monorepo (https://github.com/getfrens/monorepo), but it was based on a different and more complex concept — a MetaMask-like wallet extension designed to interact with memecoins directly from Twitter posts. Due to technical complexity, unresolved blockers, and reduced team interest, that effort was discontinued.
PlayFrens is a completely new project built independently from scratch by me (Deven Rathod) as a solo developer for this hackathon submission. All gameplay, state channel integration, and architecture described here were implemented specifically for this project. No production code from the earlier repository is reused in this submission.
A 4-player poker game with 100 hands should produce zero on-chain transactions during gameplay.
Only the initial deposit and final withdrawal touch the blockchain.
Everything in between — dealing cards, placing bets, showdowns, and pot distribution — happens off-chain through cryptographically signed state updates on Yellow Network’s Clearnode, giving players:
Result:
No gas. No block confirmations. Just instant poker.
When the session ends:
PlayFrens integrates ENS to make multiplayer discovery seamless:
.eth nameWhile poker is the first game, the platform is designed to support any turn-based game that tracks chip or score balances.
The following components are reusable across games:
PlayFrens does not deploy custom smart contracts.
Instead, it uses Yellow Network’s existing infrastructure:
All deployments currently run on Base Sepolia.
PlayFrens is built as a pnpm monorepo powered by Turborepo, split into three main packages:
The server wraps the poker-ts library inside a PokerRoom class that extends an abstract GameRoom base.
All game logic runs server-side:
Game state is broadcast individually via Socket.io so that:
The server supports deferred player removal:
This is the core infrastructure layer.
The server runs a YellowClient that maintains a persistent WebSocket connection to Clearnode and authenticates using EIP-712 signed challenges.
The server wallet acts as a Trusted Judge with:
This makes the server the sole authority on state updates during gameplay, while still requiring all players to co-sign the initial session creation.
The initial session creation involves a coordinated multi-signature process:
When the host clicks Deal Cards for the first time:
createAppSessionMessage from @erc7824/nitrolite.The server signs the request with its own session key using raw ECDSA (createECDSAMessageSigner, not EIP-191 prefixed).
The unsigned payload is broadcast to each player's browser via Socket.io.
Each browser:
YellowRpcClientThe server’s YellowSessionManager:
The bundled request is submitted to Clearnode.
Clearnode:
After the initial co-sign:
All addresses sent to Clearnode must be EIP-55 checksummed, as Clearnode performs case-sensitive comparisons.
PlayFrens normalizes addresses using getAddress() from viem before any RPC call.
After every hand:
submitAppState with updated chip-to-token allocations:playerChips × chipUnit = ytest.usd amount
When a player cashes out:
closeAppSession sends final allocationswagmi is configured with:
The frontend uses:
useEnsNameuseEnsAvataruseEnsAddressThese enable:
The RainbowKit chain selector is hidden using chainStatus="none" so users are not confused by the dual-chain setup, while mainnet remains enabled for ENS lookups.
@import "tailwindcss" and @theme block syntaxtailwind.config.jsThe app uses state-driven routing:
Views are rendered based on game state rather than URL routing.
Players can obtain testnet tokens via:
approve + Custody.deposit()Contracts and ABIs:
@erc7824/nitroliteWithdrawals use:
Custody.withdraw() to return tokens to the wallet.Frontend hooks:
useCustodyuseYellowThese manage deposit, withdrawal, and balance operations.
The game server is containerized using a multi-stage Dockerfile:
Deployment:

