Tic-Tac-Toe Demo
This repository demonstrates account abstraction on Sonic using both EIP-7702 and ERC-4337 standards through a fully functional on-chain tic-tac-toe game.
It showcases how Sonic is upgrading its infrastructure to support Ethereum's account abstraction features, enabling gasless transactions, smart account capabilities, and enhanced user experiences.
Quick Start
Sonic Testnet Deploy your own contracts using Hardhat Ignition (chain ID 14601)
Frontend Demo Requires a running bundler for UserOperation submission
Bot Demo Interacts directly with deployed contracts
Table of Contents
Key Features
🎮 On-Chain Tic-Tac-Toe Game
Fully decentralized 5x5 tic-tac-toe game with 4-in-a-row win condition
Prize token rewards (10 tokens for winners, one token for draws)
Time-limited moves (24-hour timeout protection)
Upgradeable smart contract using UUPS proxy pattern
🔐 EIP-7702 Account Abstraction
Transform regular EOAs into smart accounts without changing addresses
Enable transaction batching and gas sponsorship for existing wallets
Demonstrate SET_CODE_TX_TYPE transaction format
📦 ERC-4337 UserOperations
Complete implementation of UserOperation flow
EntryPoint interaction for validation and execution
Support for both MetaMask integration and programmatic signing
Gas estimation and fee management
💰 Paymaster Infrastructure
TargetCheckingPaymaster: Sponsors gas for whitelisted contract interactions
SignatureCheckingPaymaster: Validates authorized transactions with signature verification
Gas-free gameplay for users
🤖 AI Game Bot
Automated tic-tac-toe player using min-max algorithm
Monitors blockchain events and responds to game moves
Configurable joining delay and strategy selection
Complete event subscription and game state management
🌐 Frontend Demo
Vue.js web interface for game interaction
Two authentication methods:
MetaMask integration (requires pre-configured delegation)
Private key input (sets up delegation automatically)
Real-time UserOperation construction and submission
Architecture Overview

Understanding Account Abstraction
EIP-7702: Protocol-Level Account Abstraction
EIP-7702 introduces a new transaction type that allows EOAs to delegate their execution logic to smart contracts:
No Address Change EOAs maintain their original addresses
Code Delegation EOA delegates code execution to a specified smart contract
Native Batching Execute multiple operations in a single transaction
Backward Compatible Works with existing infrastructure
Persistent Until Changed Delegation remains active until explicitly updated
Key Innovation: The SET_CODE_TX_TYPE transaction format with authorization lists enables EOAs to act as smart accounts without permanent migration.
ERC-4337: Smart Account Framework
ERC-4337 provides a complete account abstraction solution without protocol changes:
UserOperations Pseudo-transactions that encapsulate user intent
Bundlers Aggregate and submit UserOps to the blockchain
EntryPoint Singleton contract for validation and execution
Paymasters Services that sponsor gas fees
Key components:
Sender ERC-4337 compatible smart contract wallet
UserOperation Contains nonce, calldata, gas limits, and signatures
Bundler Collects UserOps and submits them on-chain
Paymaster Covers transaction fees on behalf of users
How They Work Together
EIP-7702 and ERC-4337 are complementary, not competing standards:
EIP-7702 upgrades an EOA to execute smart contract code
The upgraded EOA implements ERC-4337's IAccount interface
The account can now receive UserOperations through EntryPoint
Paymasters can sponsor gas for the upgraded account
Users benefit from both simple EOA interactions AND smart account features
Project Components
Smart Contracts (/contracts)
TicTacToe.sol: Main game contract with UUPS upgradeability
PrizeToken.sol: ERC20 token for game rewards
Simple7702Account.sol: EIP-7702 compatible account implementation (in /contracts/testing)
TargetCheckingPaymaster.sol: Paymaster that sponsors specific contract calls
SignatureCheckingPaymaster.sol: Paymaster with signature validation
Note: EntryPoint contract is imported from @account-abstraction/contracts
Backend Services (/cmd)
senduserop
Demonstrates UserOperation creation and submission
EIP-7702 authorization signing
Gas estimation and fee calculation
Direct EntryPoint interaction
tictactoebot
Automated game player with an AI strategy
Event monitoring and subscription
Minimax algorithm implementation
Keystore management
Frontend (/frontenddemo)
Vue.js single-page application
UserOperation construction in the browser
MetaMask and private key support
Real-time game interaction
Testing (/test)
Comprehensive contract testing
Paymaster validation tests
Game logic verification
Gas usage optimization
Installation & Setup
Prerequisites
Node.js 18+ and npm
Go 1.24+ (yes, 1.24 is correct - see go.mod)
Git
A funded wallet for deploying contracts and running the bundler
Clone Repository
git clone <repository-url>
cd TicTacToeDemo
Install Dependencies
# Install Node.js dependencies
npm install
# Install Go dependencies
go mod download
# Install frontend dependencies
cd frontenddemo
npm install
cd ..
Environment Configuration
Create a .env file in the root directory:
# Required for deployment
PRIVATE_KEY=your_private_key_here_without_0x_prefix
Notes:
Private key should be without the '0x' prefix
Sonic RPC URL is already configured in hardhat.config.ts
Deployment
Compile Contracts
npx hardhat compile
Deploy Contracts
Deploy to Sonic testnet (chain ID 14601):
# Deploy complete TicTacToe system
npx hardhat ignition deploy ./ignition/modules/TicTacToe.ts --network sonic-testnet
# Deploy paymasters separately (if needed)
npx hardhat ignition deploy ./ignition/modules/TargetCheckingPaymaster.ts --network sonic-testnet
npx hardhat ignition deploy ./ignition/modules/SignatureCheckingPaymaster.ts --network sonic-testnet
Verify Contracts
# For Sonic testnet
npx hardhat ignition verify --network sonic-testnet
Running the Demo
1. Start the Bundler
The bundler aggregates UserOperations and submits them to the EntryPoint:
# Clone the bundler (if not already done)
git clone https://github.com/eth-infinitism/bundler
cd bundler
# Configure and run
yarn install
yarn run bundler --network https://rpc.soniclabs.com/ \
--mnemonic path/to/mnemonic.txt \
--entryPoint 0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108 \
--unsafe
The bundler RPC will be exposed at: http://localhost:3000/rpc
Notes:
Use --unsafe flag for RPCs that don't support debug_traceCall (most public RPCs)
The mnemonic account needs sufficient balance to send transactions (0.1 S recommended)
2. Start the TicTacToe Bot
The bot automatically plays games and demonstrates event monitoring:
# Build the bot
cd cmd/tictactoebot
go build
# Run with configuration
./tictactoebot \
--rpcUrl https://rpc.soniclabs.com/ \
--gameAddress 0xYourGameAddress \
--keystore path/to/keystore.json \
--joiningDelay 30s
Bot flags:
--gameAddress
: TicTacToe contract address--startBlock
: Block number to start event scanning (default: 1)--joiningDelay
: Time to wait before joining new games (default: 1 minute)--blocksPerQuery
: Max block range for event queries (default: 10000)--keystore
: Path to keystore JSON file--keystorePass
: Path to keystore passphrase file (optional)
3. Launch Frontend
cd frontenddemo
npm run dev
Open http://localhost:5173 in your browser.
Testing
Run the comprehensive test suite:
# Run all tests
npx hardhat test
# Run with gas reporting
REPORT_GAS=true npx hardhat test
# Run with detailed traces
npx hardhat test --fulltrace
# Run specific test file
npx hardhat test test/TicTacToe.ts
Technical Deep Dive
UserOperation Structure
struct PackedUserOperation {
address sender; // Smart account address
uint256 nonce; // Anti-replay parameter
bytes initCode; // Account creation code (if needed)
bytes callData; // Execution calldata
bytes32 accountGasLimits; // Verification and call gas limits
uint256 preVerificationGas; // Gas for bundler overhead
bytes32 gasFees; // maxPriorityFee and maxFeePerGas
bytes paymasterAndData; // Paymaster address and data
bytes signature; // Account signature
}
EIP-7702 Authorization
auth := types.SetCodeAuthorization{
ChainID: chainId,
Address: accountImplementation, // Smart account code
Nonce: accountNonce,
}
signedAuth := SignSetCode(privateKey, auth)
Paymaster Validation
The TargetCheckingPaymaster validates:
Account code hash matches whitelist
The target contract is approved
Gas fees are within limits
Game Mechanics
Board Size: 5x5 grid
Win Condition: 4 stones in a row
Rewards: 10 tokens for the winner, one token each for the draw
Timeout: 24 hours per move
Storage: Packed uint256 for efficient gas usage
Developer Resources
Key Concepts
Account abstraction benefits:
🔒 Enhanced security with smart account features
⛽ Gas sponsorship for better UX
📦 Transaction batching for efficiency
🔑 Flexible authentication methods
🔄 Social recovery and multi-sig support
Implementation patterns:
Delegation Pattern EOA delegates to smart contract logic
Validation Pattern Custom signature validation in accounts
Sponsorship Pattern Paymasters cover gas costs
Batching Pattern Multiple operations in a single transaction
API References
Smart account interface:
interface IAccount {
function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256 validationData);
}
Paymaster interface:
interface IPaymaster {
function validatePaymasterUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 maxCost
) external returns (bytes memory context, uint256 validationData);
}
Troubleshooting
Common issues and solutions:
"AA25 invalid account nonce": Account nonce mismatch - check EntryPoint.getNonce()
"AA33 reverted": Paymaster validation failed - check gas limits
"AA51 prefund too low": Insufficient paymaster deposit
"Not from self or EntryPoint": Invalid caller for account execution
Additional setup issues:
Frontend bundler connection: Update bundler URL in Vue components if not using default
Go version error: Ensure Go 1.24+ is installed (check with go version)
Contract deployment fails: Ensure wallet has sufficient funds and correct network is selected
Bot can't join games: Check keystore file permissions and passphrase
Bundler errors: Ensure the mnemonic account has funds for gas
Further Reading
Last updated