From f5d112abec272949e070ae438a65a5416bc2626d Mon Sep 17 00:00:00 2001
From: Lulox
Date: Fri, 12 Jan 2024 10:43:01 -0300
Subject: [PATCH] Started simplifying and trying to debug TicTacToeBoard.tsx
---
README.md | 17 +--
packages/hardhat/contracts/TicTacToe.sol | 111 +++++++++++++++---
.../tictactoe/CreateChallengeBox.tsx | 2 +-
.../components/tictactoe/TicTacToeBoard.tsx | 58 ++++-----
.../nextjs/contracts/deployedContracts.ts | 34 +++++-
5 files changed, 155 insertions(+), 67 deletions(-)
diff --git a/README.md b/README.md
index fe8d913..1eb5d14 100644
--- a/README.md
+++ b/README.md
@@ -6,17 +6,12 @@ dApp for betting on the outcome of a Tic Tac Toe game.
- Board (pending development by BuidlGuidl members)
- Game idea by [freeCodeCamp Frontend Web Development Tutorial](https://www.youtube.com/watch?v=MsnQ5uepIaE)
-## How can I contribute?
-
-### Requirements
-
-- 🐣 Make sure you know the ETH Tech Stack and understand [how to make a dApp using Scaffold-ETH 2](https://lulox.notion.site/Newbie-s-Lounge-68ea7c4c5f1a4ec29786be6a76516878).
-
-### How to contribute:
+## How can I contribute to this build?
- 👷♀️ To view current development tasks, [join this Trello board](https://trello.com/invite/b/s0vot1BA/ATTI366c508087a404ccf9343def4d76d1ce6F7899AA/newbies-lounge) and check the list "TicTacToe".
- 🧰 To chat with other buidlers about this project, [join our Telegram group](https://t.me/+FwCZPG51UhwzOTZh)
- 🛠️ To submit a PR (Pull Request), [fork and pull](https://github.com/susam/gitpr) a request to this repo.
+- 🐣 Make sure you know the ETH Tech Stack and understand [how to make a dApp using Scaffold-ETH 2](https://lulox.notion.site/Newbie-s-Lounge-68ea7c4c5f1a4ec29786be6a76516878).
## Quickstart
@@ -95,12 +90,12 @@ Win scenarios:
Run smart contract test with `yarn hardhat:test`
+## About Scaffold-ETH 2
+
+See [SE2-DOCUMENTATION.md](./SE2-DOCUMENTATION.md)
+
### Disabling Github Workflow
We have github workflow setup checkout `.github/workflows/lint.yaml` which runs types and lint error checks every time code is **pushed** to `main` branch or **pull request** is made to `main` branch
To disable it, **delete `.github` directory**
-
-## About Scaffold-ETH 2
-
-See [SE2-DOCUMENTATION.md](./SE2-DOCUMENTATION.md)
diff --git a/packages/hardhat/contracts/TicTacToe.sol b/packages/hardhat/contracts/TicTacToe.sol
index 90732fd..b5748b9 100644
--- a/packages/hardhat/contracts/TicTacToe.sol
+++ b/packages/hardhat/contracts/TicTacToe.sol
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: MIT
-pragma solidity 0.8.19;
+pragma solidity ^0.8.17;
/**
* @title TicTacToe
* @author Lulox
* @notice A betting TicTacToe contract.
* @dev Currently for using with one transaction per move,
- * in a future may be replaced with signatures
+ * in a future may be replaced with signatures
+ or other gas efficient mechanism
*/
contract TicTacToe {
@@ -57,15 +58,6 @@ contract TicTacToe {
/* MODIFIERS */
- modifier onlyPlayers(uint256 gameId) {
- require(
- msg.sender == games[gameId].player1 ||
- msg.sender == games[gameId].player2,
- "Not a player"
- );
- _;
- }
-
modifier onlyValidMove(uint256 _gameId, uint8 position) {
// Store the game in memory to use less storage reads
Game memory game = games[_gameId];
@@ -160,6 +152,55 @@ contract TicTacToe {
checkWin(_gameId, position, msg.sender);
}
+ // Function to withdraw the prize based on game state
+ function withdrawPrize(uint256 _gameId) external {
+ Game storage game = games[_gameId];
+
+ // Ensure the game is in the correct state for prize withdrawal
+ require(
+ game.state == GameState.PLAYER1WON ||
+ game.state == GameState.PLAYER2WON ||
+ game.state == GameState.TIE,
+ "Invalid game state for prize withdrawal"
+ );
+
+ // Ensure the caller is one of the players or has not withdrawn yet
+ require(
+ msg.sender == game.player1 || msg.sender == game.player2,
+ "Not a player"
+ );
+
+ // Ensure the player has not withdrawn yet
+ if (msg.sender == game.player1) {
+ require(
+ game.state == GameState.PLAYER1WON,
+ "You haven't won this game!"
+ );
+ require(
+ !game.player1Withdrawn,
+ "You have already withdrawn the prize!"
+ );
+ game.player1Withdrawn = true;
+ } else {
+ require(
+ game.state == GameState.PLAYER2WON,
+ "You haven't won this game!"
+ );
+ require(
+ !game.player2Withdrawn,
+ "You have already withdrawn the prize!"
+ );
+ game.player2Withdrawn = true;
+ }
+
+ // Calculate and transfer the prize based on the game state
+ uint256 prize = calculatePrize(_gameId);
+ require(prize > 0, "Invalid prize amount");
+
+ // Transfer the prize to the player
+ payable(msg.sender).transfer(prize);
+ }
+
/* INTERNAL FUNCTIONS */
function checkWin(
@@ -215,13 +256,49 @@ contract TicTacToe {
}
function finishGame(uint256 gameId, address winner) internal {
- // Incliude a check for state assuming the winner will be the msg.sender
- // In the case of a tie call with address(0) as the winner, add a condition for that too
+ Game storage game = games[gameId];
- // Add conditions to determine which state will the game be finished with, according to this info ^
- // These come from the enum GameState PLAYER1WON, PLAYER2WON, TIE
- GameState state = games[gameId].state;
- emit GameFinished(gameId, winner, state);
+ // Ensure the game is in the PLAYING state before finishing
+ require(
+ game.state == GameState.PLAYING,
+ "Game is not in PLAYING state"
+ );
+
+ // Determine the result based on the winner and update game state accordingly
+ if (winner == address(0)) {
+ // It's a tie
+ game.state = GameState.TIE;
+ } else if (winner == game.player1) {
+ // Player 1 won
+ game.state = GameState.PLAYER1WON;
+ } else if (winner == game.player2) {
+ // Player 2 won
+ game.state = GameState.PLAYER2WON;
+ } else {
+ // Winner address is not valid
+ revert("Invalid winner address");
+ }
+
+ // Emit GameFinished event
+ emit GameFinished(gameId, winner, game.state);
+ }
+
+ // Function to calculate the prize based on the game state
+ function calculatePrize(uint256 _gameId) internal view returns (uint256) {
+ Game storage game = games[_gameId];
+ uint256 totalBet = game.bet * 2; // Total amount bet in the game
+
+ if (game.state == GameState.PLAYER1WON) {
+ return totalBet;
+ } else if (game.state == GameState.PLAYER2WON) {
+ return totalBet;
+ } else if (game.state == GameState.TIE) {
+ // In the case of a tie, split the total bet equally between players
+ return totalBet / 2;
+ } else {
+ // Invalid game state
+ revert("Invalid game state");
+ }
}
/* VIEW AND PURE FUNCTIONS */
diff --git a/packages/nextjs/components/tictactoe/CreateChallengeBox.tsx b/packages/nextjs/components/tictactoe/CreateChallengeBox.tsx
index 4ecd0b8..48b557b 100755
--- a/packages/nextjs/components/tictactoe/CreateChallengeBox.tsx
+++ b/packages/nextjs/components/tictactoe/CreateChallengeBox.tsx
@@ -16,7 +16,7 @@ const CreateChallengeBox = ({}) => {
value: betAmount ? ethers.parseEther(betAmount) : undefined,
});
- console.log("Bet amount: ", betAmount);
+ // console.log("Bet amount: ", betAmount);
return (
= ({
- game,
- isGameAccepted,
- movesList,
- movesAmount,
- isGameFinished,
-}) => {
+const TicTacToeBoard: React.FC = ({ game, isGameAccepted, movesAmount, isGameFinished }) => {
const [position, setPosition] = useState(0);
- const [betPayment, setBetPayment] = useState(game.bet);
const [board, setBoard] = useState(Array(9).fill(0)); // Initialize an empty board
const { data: getBoard } = useScaffoldContractRead({
@@ -22,42 +15,33 @@ const TicTacToeBoard: React.FC = ({
args: [BigInt(game.gameId)],
});
- console.log("getBoard reads for #", game.gameId, ": ", getBoard);
+ console.log("getBoard reads: ", getBoard);
+
+ useEffect(() => {
+ // Update the local board based on the latest data from the contract
+ if (getBoard) {
+ setBoard(getBoard.map(Number));
+ }
+ }, [getBoard]);
const { writeAsync: makeMove } = useScaffoldContractWrite({
contractName: "TicTacToe",
functionName: "makeMove",
args: [BigInt(game.gameId), position],
- value: BigInt(betPayment),
});
- useEffect(() => {
- // Update the board based on the movesList
- const updatedBoard = Array(9).fill(0);
-
- movesList.forEach((move: MoveMadeProps) => {
- const currentPlayerSymbol = move.player === game.player1 ? 1 : 2;
- updatedBoard[move.position] = currentPlayerSymbol;
- });
-
- setBoard(updatedBoard);
- }, [game.player1, movesList]);
+ const { writeAsync: acceptGame } = useScaffoldContractWrite({
+ contractName: "TicTacToe",
+ functionName: "acceptGame",
+ args: [BigInt(game.gameId)],
+ value: BigInt(game.bet),
+ });
const handleMakeMove = async () => {
try {
- if (movesAmount > 0) {
- setBetPayment(0);
- }
await makeMove();
-
- // Update the local board based on the latest move
- const currentPlayerSymbol = movesAmount % 2 === 0 ? 1 : 2;
- const updatedBoard = [...board];
- updatedBoard[position] = currentPlayerSymbol;
- setBoard(updatedBoard);
} catch (error) {
console.error("Error making move:", error);
- // Handle error as needed
}
};
@@ -74,13 +58,19 @@ const TicTacToeBoard: React.FC = ({
Player 2:
- Bet: {parseFloat(ethers.formatEther(game.bet.toString())).toFixed(4)} ETH
+ Each player bets: {parseFloat(ethers.formatEther(game.bet.toString())).toFixed(4)} ETH