PlayFrens

Play poker with frens via ENS names. Zero gas per hand, instant settlement on Yellow Network.

PlayFrens

Created At

HackMoney 2026

Project Description

PlayFrens — On-Chain Multiplayer Gaming Without Gas Fees

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.


Judge Clarification

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.

Core Insight

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:

  • The speed of a centralized server
  • The security of on-chain funds

How a Typical Session Works

  1. Players connect their wallet and authorize with Yellow Network.
  2. They create or join a poker table.
  3. The host sets the buy-in, blinds, and chip denominations.
  4. When the first hand is dealt, all players co-sign a multi-party app session that locks their buy-in from their Unified Balance on Clearnode.
  5. Gameplay happens in real-time via Socket.io:
    • Check
    • Bet
    • Fold
    • Raise
  6. The server computes updated chip allocations and submits signed state updates to Clearnode after each hand.

Result:
No gas. No block confirmations. Just instant poker.

When the session ends:

  • Funds return to each player’s Unified Balance proportional to their chip count.
  • Players can withdraw back to their wallet at any time.

Social Layer (ENS Integration)

PlayFrens integrates ENS to make multiplayer discovery seamless:

  • Search for friends by their .eth name
  • Display ENS avatars at the poker table
  • Invite friends directly to rooms

Game-Agnostic Architecture

While 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:

  • Fund flow
  • Session management
  • Settlement layer

Smart Contract Usage

PlayFrens does not deploy custom smart contracts.

Instead, it uses Yellow Network’s existing infrastructure:

  • Custody Contract — fund security
  • Adjudicator Contract — dispute resolution
  • ytest.usd — game token

All deployments currently run on Base Sepolia.

How it's Made

PlayFrens Technical Architecture

PlayFrens is built as a pnpm monorepo powered by Turborepo, split into three main packages:

  • Frontend — React 19 + Vite
  • Game Server — Node.js
  • Shared Package — Types and constants compiled with tsup

Poker Engine & Real-Time Layer

The server wraps the poker-ts library inside a PokerRoom class that extends an abstract GameRoom base.

All game logic runs server-side:

  • The poker-ts engine handles:
    • Card dealing
    • Betting rounds
    • Showdowns
    • Pot calculation

Game state is broadcast individually via Socket.io so that:

  • Each player only sees their own hole cards
  • Opponents’ cards remain hidden until showdown

Fault Tolerance

The server supports deferred player removal:

  • If a player disconnects mid-hand:
    • They are automatically folded when their turn arrives
    • They are cleanly removed once the hand completes

Yellow Network Integration

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:

  • weight = 100
  • quorum = 100

This makes the server the sole authority on state updates during gameplay, while still requiring all players to co-sign the initial session creation.


Multi-Party Signing Flow

The initial session creation involves a coordinated multi-signature process:

  1. When the host clicks Deal Cards for the first time:

    • The server prepares an app session request using createAppSessionMessage from @erc7824/nitrolite.
  2. The server signs the request with its own session key using raw ECDSA (createECDSAMessageSigner, not EIP-191 prefixed).

  3. The unsigned payload is broadcast to each player's browser via Socket.io.

  4. Each browser:

    • Uses its own YellowRpcClient
    • Authenticates independently with Clearnode using an ephemeral session key
    • Signs the payload locally
  5. The server’s YellowSessionManager:

    • Collects all player signatures
    • Bundles them into a single multi-sig message containing the request and all signatures
  6. The bundled request is submitted to Clearnode.

  7. Clearnode:

    • Recovers each signer
    • Maps session keys to wallet addresses
    • Verifies all required signatures
    • Creates the app session

After the initial co-sign:

  • Subsequent hands start instantly
  • The server submits state updates unilaterally as the Trusted Judge

Important Implementation Detail

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.


State Updates & Settlement

After every hand:

  • The server calls submitAppState with updated chip-to-token allocations:

playerChips × chipUnit = ytest.usd amount

When a player cashes out:

  • closeAppSession sends final allocations
  • Funds return to each player's Unified Balance

ENS Integration

wagmi is configured with:

  • Base Sepolia (gameplay)
  • Ethereum Mainnet (ENS resolution)

The frontend uses:

  • useEnsName
  • useEnsAvatar
  • useEnsAddress

These enable:

  • Friend search by ENS
  • Player identity display

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.


Frontend Stack

  • React 19
  • Tailwind CSS v4
    • Uses @import "tailwindcss" and @theme block syntax
    • No tailwind.config.js
  • Motion (Framer Motion v11+) for animations
  • RainbowKit v2 + wagmi v2 for wallet connectivity

The app uses state-driven routing:

  • Lobby
  • Room
  • Game

Views are rendered based on game state rather than URL routing.


Deposit & Withdrawal Flow

Players can obtain testnet tokens via:

  • Clearnode faucet endpoint
  • Or a real on-chain deposit using ERC20 approve + Custody.deposit()

Contracts and ABIs:

  • CustodyAbi
  • Erc20Abi
  • Exported from @erc7824/nitrolite

Withdrawals use:

  • Custody.withdraw() to return tokens to the wallet.

Frontend hooks:

  • useCustody
  • useYellow

These manage deposit, withdrawal, and balance operations.


Deployment

The game server is containerized using a multi-stage Dockerfile:

  • Builds shared and server packages with tsup
  • Produces a slim production image

Deployment:

  • Hosted on Fly.io
  • WebSocket support enabled
  • Auto-scaling configured
background image mobile

Join the mailing list

Get the latest news and updates