ChainRPS is a React frontend for a Sepolia Rock Paper Scissors smart contract. The app uses a commit-reveal flow so players choose a move privately, join with matching bets, then reveal the original move and secret to resolve the game on-chain.
- Network: Sepolia
- Contract address:
0x83D917b606fE4C89ff178A5fd9d7D05Ca8605f38 - Wallet: MetaMask
- Web3 library:
ethers@6
The ABI used by the frontend is defined directly in src/App.js.
- React app created with Create React App
- Dark ChainRPS UI with indigo and teal accents
- MetaMask connection and Sepolia switching
- Game creation with ETH bet
- Game joining with matching bet
- Commit hash generation through the contract, with a local ethers fallback
- Move reveal flow for both players
- Pot display, phase tracker, player status, win streak, recent games, and timeout buttons
- Saved game ID after refresh
- Saved move and secret per wallet/game so a player can return and reveal
Load Gamebutton for resuming a game instead of trying to join it againLogoutbutton that clears the local wallet session while keeping the saved game ID
- src/App.js: wallet logic, contract calls, game state, and UI
- src/App.css: dark theme styling
- src/App.test.js: basic render and saved-game tests
- contracts/RockPaperScissors.sol: commit-reveal game contract
- test/RockPaperScissors.test.js: Hardhat unit tests for the contract
- hardhat.config.js: local Hardhat test configuration
- package.json: scripts and dependencies
Install dependencies:
npm installStart the development server:
npm startBy default the app opens at:
http://localhost:3000
If port 3000 is busy, use another port:
set PORT=3005&&npm startThen open:
http://localhost:3005
Use two different MetaMask accounts on Sepolia. Both accounts need Sepolia ETH.
- Connect account 1.
- Choose Rock, Paper, or Scissors.
- Enter a secret phrase. Save or remember it.
- Set a bet amount.
- Click
Create Game. - Copy the game ID.
- Click
Logoutor switch MetaMask to account 2. - Connect account 2.
- Choose a move and enter a secret phrase.
- Confirm the saved game ID is in the join field.
- Click
Join Game. - Click
Reveal Movewith account 2. - Log out or switch back to account 1.
- Click
Load Gameif the app does not auto-load it. - Click
Reveal Movewith account 1. - The contract resolves the winner or refunds on a draw.
Game IDs are simple numbers. If the copied ID is 1, that is normal: it means contract game number 1.
Failed to join game: execution reverted: "Not open" means the game cannot accept another player. This usually happens when:
- player 2 already joined
- the game was cancelled
- the game was resolved
- you are clicking
Join Gamewhen you should clickLoad Game
After a game has two players, use Load Game to resume it and Reveal Move to continue. Do not click Join Game again for that same game.
The Logout button clears the app's local wallet state and tries to revoke MetaMask account permission with wallet_revokePermissions. Some wallets may ignore that method. Even then, the app still returns to the disconnected screen.
Logout keeps the saved game ID so it is easier to reconnect with the next account and continue testing.
Run a production build:
npm run buildRun tests once:
npx react-scripts test --watchAll=false --runInBandRun the smart contract unit tests:
npm run test:hardhat