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 (
- Bet:
{parseFloat(ethers.formatEther(game.bet.toString())).toFixed(4)} ETH
+ Each player bets:
{parseFloat(ethers.formatEther(game.bet.toString())).toFixed(4)} ETH
Is game accepted?:
- {isGameAccepted ? "Yes" : "No"}
+ {isGameAccepted ? (
+ "Yes"
+ ) : (
+
+ )}
# of moves made:
diff --git a/packages/nextjs/contracts/deployedContracts.ts b/packages/nextjs/contracts/deployedContracts.ts
index edaf47f..0aeebd6 100644
--- a/packages/nextjs/contracts/deployedContracts.ts
+++ b/packages/nextjs/contracts/deployedContracts.ts
@@ -7,7 +7,7 @@ import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract";
const deployedContracts = {
31337: {
TicTacToe: {
- address: "0x5FbDB2315678afecb367f032d93F642f64180aa3",
+ address: "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707",
abi: [
{
anonymous: false,
@@ -115,6 +115,19 @@ const deployedContracts = {
name: "MoveMade",
type: "event",
},
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_gameId",
+ type: "uint256",
+ },
+ ],
+ name: "acceptGame",
+ outputs: [],
+ stateMutability: "payable",
+ type: "function",
+ },
{
inputs: [
{
@@ -220,9 +233,9 @@ const deployedContracts = {
name: "getCurrentPlayer",
outputs: [
{
- internalType: "uint256",
+ internalType: "uint8",
name: "",
- type: "uint256",
+ type: "uint8",
},
],
stateMutability: "view",
@@ -243,7 +256,20 @@ const deployedContracts = {
],
name: "makeMove",
outputs: [],
- stateMutability: "payable",
+ stateMutability: "nonpayable",
+ type: "function",
+ },
+ {
+ inputs: [
+ {
+ internalType: "uint256",
+ name: "_gameId",
+ type: "uint256",
+ },
+ ],
+ name: "withdrawPrize",
+ outputs: [],
+ stateMutability: "nonpayable",
type: "function",
},
],