Appearance
Chain of Custody Phase 1
Date: 2026-04-15 Status: Implemented
Decision
Align all three layers (contract, admin-server, game-server) around a single unit: integer NUMERO. Eliminate conversion layers, game-specific settlement, and fire-and-forget patterns on fund paths.
The Token
NUMERO is a zero-decimal ERC-20 with ERC-2612 Permit. 1 NUMERO = 1 chip. No conversion anywhere.
The Table Pool
Contract tracks one total per table (pools[tableId][token]), not per-player. Game-server tracks the per-player split via PlayerLedger. Deposits are admin-only via depositFor with ERC-2612 permit.
The Settlement
Single SettlementFacet replaces per-game functions:
settle(receipt, signature)— verify signer, record PnL + noncewithdrawFor(wallet, player, tableId, amount, historyHash)— transfer from pool to walletsettleAndWithdraw(receipt, signature, amount)— both in one call
gameId in the EIP-712 receipt distinguishes games. The contract has no game-specific logic.
The Boundary
- Game-server = the table. Manages chips (integers). Zero blockchain awareness.
- Admin-server = the cage (the money-only bank, now called evm-bank). Manages money (all on-chain ops). Looks up
gameIdandtokenfrom table config byroomCode. - gameType never crosses the boundary. It's a game-server routing concept.
Sequential Operations
Every fund-affecting operation is awaited. No .catch(() => {}) on money paths:
- Session recovery completes before accepting connections
- Deposit verified before first
game_state - Concurrent sit-down attempts rejected
- Runtime config loaded before server starts
Tradeoffs
- Per-player on-chain tracking lost — can't query per-player balance on-chain. Admin-server tracks deposits in its own DB.
- Token migration — zero-decimal requires redeployment. Manageable on testnet.
- Admin-server API breaking change — no
gameType, integer chips instead of wei.
Key Files
packages/contracts/contracts/facets/TableFacet.sol—registerTable,depositForpackages/contracts/contracts/facets/SettlementFacet.sol— unified settlementapps/admin-server/src/routes/settlement.ts— integer passthrough, table config lookupapps/game-server/src/shared/player-ledger.ts— pure integer counterapps/game-server/src/shared/settlement.ts— sends chip integers
Full ADR
The full ADR is retained in the project's internal planning archive.