Table Smart Contract
The Table Contract is the core of Purr Poker's security model. It serves as a trustless escrow for player funds while ensuring only authorized settlement operations can modify player balances.
Contract Overview
Each poker table in Purr Poker is represented by a unique smart contract deployed on the Hyperliquid blockchain. This contract handles all financial aspects of the game, including:
- Managing player deposits and withdrawals through a request-approval system
- Holding player funds in escrow during gameplay
- Settling balances after each hand based on game results
- Collecting and distributing rake based on pot size
- Enforcing table-specific rules (buy-in limits, max players, etc.)
- Managing player seating at the table
Security Model
Access Control
Critical functions are restricted to the designated operator address using the onlyOperator modifier. This ensures that only authorized entities can perform actions like settling hands and kicking players.
Mathematical Validation
The contract enforces mathematical invariants, such as requiring balance adjustments to sum to zero during hand settlement, ensuring the game remains a zero-sum system (minus the rake).
Key Contract Methods
| Method | Description | Access |
|---|---|---|
| requestToJoin() | Players can request to join a table by sending funds as a buy-in | Public |
| approvePlayerWithSeat(address player, uint8 seatNumber) | Operator approves a player's join request and assigns them to a specific seat | Operator Only |
| requestToLeave() | Players request to leave the table and withdraw their funds | Public |
| approveLeaveRequest(address player) | Operator approves a player's request to leave and returns their funds | Operator Only |
| settleHand(address[] memory players, int256[] memory adjustments, uint256 totalPot) | Updates player balances after a hand, calculating and collecting rake. Adjustments must sum to zero. | Operator Only |
| kickPlayer(address player) | Forcibly removes a player from the table and returns their funds, without requiring them to make a request | Operator Only |
| withdrawRake() | Withdraws accumulated rake to the designated rake receiver address | Operator Only |
| updateTableParameters() | Updates table parameters like buy-in limits and rake percentage | Operator Only |
| emergencyWithdraw() | Allows players to withdraw their funds if the operator has been inactive for the timeout period | Public (after timeout) |
How Settlement Works
Hand Completion
When a hand completes, the server calculates the balance adjustments for each player and the total pot size.
Zero-Sum Validation
The contract verifies that the sum of all balance adjustments equals zero, ensuring that the game remains a zero-sum system where money cannot be created or destroyed (excluding rake).
Rake Calculation
Based on the total pot size, the contract calculates the rake amount using the configured rake percentage. The rake is proportionally deducted from the winner's profits.
Balance Updates
The contract updates each player's balance according to their adjustment, minus their share of the rake if they won. The total rake is accumulated for later withdrawal by the rake receiver.
Security Measures
Reentrancy Protection
The contract uses OpenZeppelin's ReentrancyGuard to prevent reentrancy attacks during fund transfers, ensuring that critical operations cannot be exploited through callback functions.
Request-Approval Flow
Players must request to join or leave the table, with the operator explicitly approving these requests. This provides an additional layer of security and allows for validation before executing critical operations.
Emergency Timeout System
The contract includes a timeout mechanism that allows players to withdraw their funds if the operator has been inactive for an extended period (4 hours), preventing funds from being permanently locked.