This skill should be used when the user asks about "smart contracts", "GameVault", "ChipToken", "settlement", "EIP-712", "on-chain settlement", "abandonment claims", "disputes", "side pots", "ERC20 permit", or needs to understand how ManaMesh implements blockchain-based game settlement.
The contracts implement on-chain escrow and settlement for poker-style games. Players deposit chips into a GameVault contract, play off-chain (producing signed HandResult messages), then call settleHands to distribute winnings atomically. Disputes and abandonment are handled on-chain with EIP-712 signature verification.
All contracts live in contracts/src/ and use Foundry for development.
contracts/src/GameVault.sol)Central escrow and settlement coordinator. Handles:
joinGame, joinGameWithPermit, withdraw, leaveGamesettleHands(gameId, hands, signatures, folds, foldSigs) — consumes signed messagesHandResultdisputeHand(gameId, betChain, betChainSigs) — replays bet chain, can reverse settlement if fraud detectedclaimAbandonment(gameId, ...) — redistributes escrow after timeoutKey dependencies:
IGameVault interface (structs: HandResult, Bet, FoldAuth, Abandonment)IChipTokenFactory — validates chip tokensSignatureVerifier library — EIP-712 hashing and signature verificationSafeERC20, EIP712State:
mapping(bytes32 => uint256) public escrowedChips;
mapping(bytes32 => bool) public settledHands;
mapping(bytes32 => int256[]) public settledDeltas; // per-player deltas after settlement
contracts/src/ChipToken.sol)ERC-20 chip token backed 1:1 by ETH:
deposit() — deposit ETH, receive chips 1:1withdraw(uint256 amount) — burn chips, receive ETH backERC20 + ERC20Permit (EIP-2612)ethReserve() view — current ETH backingcontracts/src/ChipTokenFactory.sol)Deploys per-underlying chip tokens using Crane's deterministic deploy package:
getChipToken(underlying) → address — get or create chip token for underlyingisChipToken(token) → bool — check if a token is a factory-deployed chipTOKEN_PKG for deterministic deployment with saltcontracts/src/libraries/SignatureVerifier.sol)Centralized EIP-712 type hashes and verification helpers:
hashBet, hashHandResult, hashFoldAuth, hashAbandonment — struct hashingverifyBetChain — replay and verify full bet chainrecoverSigner — EIP-712 signature recoveryverifyMultiple — batch signature verificationcontract GameVault is IGameVault, EIP712("ManaMesh", "1") {
// Domain separator: ManaMesh v1
}
Important: Frontend EIP-712 domain must match on-chain domain (chainId + verifyingContract). See skill:manamesh-eip712.
struct HandResult {
bytes32 gameId;
uint8 round;
address[] players; // player addresses
int256[] deltas; // chip deltas (positive = win, negative = loss)
bytes32 finalBetHash; // hash of final bet state
}
struct Bet {
bytes32 gameId;
uint8 round;
uint8 playerIndex;
BetType betType; // FOLD, CHECK, CALL, BET, RAISE, ALL_IN
uint256 amount;
uint256 potAfter;
}
struct FoldAuth {
bytes32 gameId;
uint8 playerIndex;
uint256 foldAmount;
bytes signature;
}
struct Abandonment {
bytes32 gameId;
address[] remainingPlayers;
uint256[] amounts; // amounts each remaining player claims
bytes[] signatures; // signatures from remaining players
uint256 abandonedAt;
}
Bet messagesHandResult (players, deltas, finalBetHash)HandResult with EIP-712 eth_signTypedDatafunction settleHands(
bytes32 gameId,
HandResult[] calldata hands,
bytes[] calldata signatures,
FoldAuth[] calldata folds,
bytes[] calldata foldSigs
) external {
// 1. Validate fold authorizations (_processFolds)
// 2. Verify hand signatures (SignatureVerifier.recoverSigner)
// 3. Update escrow state (_settleHand)
// 4. Track settled deltas in _settledDeltas
}
function disputeHand(
bytes32 gameId,
Bet[] calldata betChain,
bytes[] calldata betChainSigs
) external {
// 1. Replay bet chain with SignatureVerifier.verifyBetChain
// 2. If fraud detected: _reverseSettlement
// 3. Otherwise: confirm settlement stands
}
function claimAbandonment(
bytes32 gameId,
Abandonment calldata auth
) external {
// 1. Check abandonedAt + abandonmentTimeout passed
// 2. Verify signatures from remaining players
// 3. Redistribute escrowed chips per amounts[]
}
cd contracts
forge build # Compile
forge test # Run tests
forge coverage # Coverage report
Test files:
test/GameVault.t.sol — settlement, disputes, abandonmenttest/ChipToken.t.sol — chip deposit/withdrawtest/Counter.t.sol — basic Foundry testcontracts/lib/openzeppelin-contracts/ # OpenZeppelin (SafeERC20, EIP712, ERC20, etc.)
contracts/lib/forge-std/ # Foundry test helpers
contracts/lib/crane/ # Crane token/DF packages (TOKEN_PKG for ChipTokenFactory)
GameVault stores deltas and settledDeltas, allowing reversals on dispute.disputeHand replays the full bet chain — if any signature fails, fraud is flagged.chipFactory.isChipToken(token) check.ChipTokenFactory uses Crane's deterministic deploy package, not simple new Token(). It requires the TOKEN_PKG for deployment.abandonedAt + abandonmentTimeout before claiming.settleHands and disputeHand.abi.encode-based array hashing. Mismatch is a common bug — see MM-044 task.contracts/src/GameVault.sol # Main escrow/settlement contract
contracts/src/ChipToken.sol # ERC20 chip token (ETH-backed)
contracts/src/ChipTokenFactory.sol # Chip token deployer
contracts/src/libraries/SignatureVerifier.sol # EIP-712 helpers
contracts/src/interfaces/IGameVault.sol # GameVault interface & structs
contracts/src/interfaces/IChipToken.sol # ChipToken interface
contracts/src/interfaces/IChipTokenFactory.sol # Factory interface
contracts/test/GameVault.t.sol # GameVault tests
contracts/test/ChipToken.t.sol # ChipToken tests
contracts/foundry.toml # Foundry configuration
skill:manamesh-p2p — Off-chain gameplay that produces HandResult signaturesskill:manamesh-game-modules — Poker module that generates bets and HandResults