import { useState, useEffect } from "react"; import Web3 from "web3"; import { Button } from "./Button"; import { Input } from "./Input"; interface CommitProps { account: string; contract: any; config: Config | null; web3: Web3 | null; setStatus: (status: string) => void; selectedMove: string | null; setSelectedMove: (move: string | null) => void; secret: string; setSecret: (secret: string) => void; } type Move = "1" | "2" | "3" | null; type MoveName = "Rock" | "Paper" | "Scissors"; const MOVES: Record = { "1": { name: "Rock", icon: "✊" }, "2": { name: "Paper", icon: "✋" }, "3": { name: "Scissors", icon: "✌️" }, }; export default function Commit({ account, contract, config, web3, setStatus, selectedMove, setSelectedMove, secret, setSecret, }: Readonly) { const [loading, setLoading] = useState(false); const [playMove, setPlayMove] = useState(""); const [bothPlayed, setBothPlayed] = useState(""); // Generate random secret on mount if not already set useEffect(() => { if (!secret) { const randomHex = Math.random().toString(16).slice(2, 18); setSecret(randomHex); } }, []); // Update encrypted move when move or secret changes useEffect(() => { if (selectedMove && secret) { const clearMove = `${selectedMove}-${secret}`; // Use keccak256 (Ethereum's standard hash function) const hash = Web3.utils.keccak256(clearMove); setPlayMove(hash); } }, [selectedMove, secret]); // Commit phase read-only handlers const handleBothPlayed = async () => { if (!contract) return; setLoading(true); try { const res = await contract.methods.bothPlayed().call({from : account}); setBothPlayed(res ? "true" : "false"); } catch (err: any) { setStatus("Failed to fetch bothPlayed: " + err.message); } finally { setLoading(false); } }; const handlePlay = async () => { if (!contract || !web3 || !account || !playMove) return; setLoading(true); setStatus(""); try { // playMove should be a hex string (bytes32) const tx = contract.methods.play(playMove); const gas = await tx.estimateGas({ from: account }); const result = await (globalThis as any).ethereum.request({ method: "eth_sendTransaction", params: [ { from: account, to: config?.GAME_CONTRACT_ADDRESS, data: tx.encodeABI(), gas: web3.utils.toHex(gas), chainId: web3.utils.toHex(await web3.eth.net.getId()), }, ], }); setStatus("Play tx sent: " + result); } catch (err: any) { setStatus("Play failed: " + err.message); } finally { setLoading(false); } }; const regenerateSecret = () => { const randomHex = Math.random().toString(16).slice(2, 18); setSecret(randomHex); }; return (

Select Your Move

{/* Move Selection */}

Choose your move:

{(["1", "2", "3"] as const).map((move) => ( ))}
{/* Secret Input */}
setSecret(e.target.value)} placeholder="Your secret passphrase" className="flex-1" />

Keep this secret safe! It's needed to reveal your move later.

{/* Encrypted Move Display */}
{playMove || "Select a move and enter a secret"}
{/* Action Buttons */}
{bothPlayed && ( {bothPlayed === "true" ? "✓ Both players have committed!" : "Waiting for opponent..."} )}
); }