From cf5caf2a13357dc6f3c3e07bfbc5ea923855f8dd Mon Sep 17 00:00:00 2001 From: pipoquinha Date: Fri, 9 Feb 2024 08:42:06 -0300 Subject: [PATCH 01/22] slider for dice number selection --- packages/backend/backend.config.ts | 3 - packages/backend/controllers/Admin.ts | 2 +- packages/nextjs/components/GameCreateForm.tsx | 94 +++++++++++++++++-- packages/nextjs/server.config.ts | 2 +- 4 files changed, 89 insertions(+), 12 deletions(-) delete mode 100644 packages/backend/backend.config.ts diff --git a/packages/backend/backend.config.ts b/packages/backend/backend.config.ts deleted file mode 100644 index b0a6df6..0000000 --- a/packages/backend/backend.config.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const JWT_SECRET = "superhardstring"; -export const PORT = 4001; -export const KEY = ""; diff --git a/packages/backend/controllers/Admin.ts b/packages/backend/controllers/Admin.ts index 78d14e4..b401b50 100644 --- a/packages/backend/controllers/Admin.ts +++ b/packages/backend/controllers/Admin.ts @@ -3,10 +3,10 @@ import Invites from "../models/Invites"; import bcrypt from "bcrypt"; import { Request, Response } from "express"; import jwt from "jsonwebtoken"; -import { JWT_SECRET } from "../backend.config"; import { ably } from ".."; async function generateUniqueInvite(length: number) { + const JWT_SECRET = process.env.JWT_SECRET || "superhardstring"; let invites = await Invites.findOne(); if (!invites) { diff --git a/packages/nextjs/components/GameCreateForm.tsx b/packages/nextjs/components/GameCreateForm.tsx index 6dd39cb..ee80b09 100644 --- a/packages/nextjs/components/GameCreateForm.tsx +++ b/packages/nextjs/components/GameCreateForm.tsx @@ -24,26 +24,67 @@ const GameCreationForm = () => { const { address: adminAddress } = useAccount(); const serverUrl = serverConfig.isLocal ? serverConfig.localUrl : serverConfig.liveUrl; + const initialPrivateKey = loadBurnerSK().toString().substring(2); + const [formData, setFormData] = useState({ maxPlayers: 5, - diceCount: 0, + diceCount: 1, mode: "manual", privateKey: loadBurnerSK().toString().substring(2), - hiddenChars: {}, + hiddenChars: { number: initialPrivateKey.charAt(0) }, prize: "", adminAddress, }); - const [selectedSlots, setSelectedSlots] = useState([]); + + const [selectedSlots, setSelectedSlots] = useState([0]); + const [sliderValue, setSliderValue] = useState(1); // State for slider value const [privateKey, setPrivateKey] = useState(""); const [loading, setloading] = useState(false); const disabled = parseFloat(formData.prize) == 0 || formData.prize == "" || selectedSlots.length == 0; useEffect(() => { + const pk = loadBurnerSK().toString().substring(2); setPrivateKey(pk); + + + const initialHiddenChars = {0: pk.charAt(0) ? "*" : ""}; + const initialSelectedSlots = [0]; + + setFormData(prevFormData => ({ + ...prevFormData, + privateKey: pk, + hiddenChars: initialHiddenChars, + })); + + setSelectedSlots(initialSelectedSlots); }, []); + useEffect(() => { + + const hiddenCount = sliderValue; + const hiddenChars = {}; + for (let i = 0; i < hiddenCount; i++) { + hiddenChars[i] = privateKey[i] ? "*" : ""; + } + + setFormData(formData => ({ + ...formData, + hiddenChars, + diceCount: hiddenCount, + })); + }, [sliderValue, privateKey]); + + + useEffect(() => { + setFormData(formData => ({ + ...formData, + adminAddress: adminAddress, + })); + }, [adminAddress]); + + const handlePlayersChange = (value: number) => { setFormData({ ...formData, maxPlayers: value }); }; @@ -56,6 +97,7 @@ const GameCreationForm = () => { setFormData({ ...formData, mode: value }); }; + const handleCharClick = (index: number) => { const updatedSelectedSlots = [...selectedSlots]; @@ -136,18 +178,56 @@ const GameCreationForm = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [adminAddress]); + const handleSliderChange = (event: React.ChangeEvent) => { + const value = parseInt(event.target.value, 10); + setSliderValue(value); + + + const newSelectedSlots = Array.from({ length: value }, (_, i) => i); + setSelectedSlots(newSelectedSlots); + + + const newHiddenChars = {}; + for (let i = 0; i < value; i++) { + newHiddenChars[i] = privateKey[i] ? "*" : ""; + } + + + setFormData(prevFormData => ({ + ...prevFormData, + diceCount: value, + hiddenChars: newHiddenChars, + })); +}; + + return (
+ {/* Slider input for selecting a number between 1 and 64 */} + +
diff --git a/packages/nextjs/components/RestartWithNewPk.tsx b/packages/nextjs/components/RestartWithNewPk.tsx new file mode 100644 index 0000000..640da84 --- /dev/null +++ b/packages/nextjs/components/RestartWithNewPk.tsx @@ -0,0 +1,72 @@ +import { Dispatch, SetStateAction } from "react"; +import { Hex } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { generatePrivateKey } from "viem/accounts"; +import useGameData from "~~/hooks/useGameData"; +import serverConfig from "~~/server.config"; +import { notification } from "~~/utils/scaffold-eth"; + +const RestartWithNewPk = ({ isOpen, setIsOpen }: { isOpen: boolean; setIsOpen: Dispatch> }) => { + const closePopup = () => { + setIsOpen(false); + }; + const serverUrl = serverConfig.isLocal ? serverConfig.localUrl : serverConfig.liveUrl; + const { loadGameState } = useGameData(); + const { token, game } = loadGameState(); + + const handleRestart = () => { + const currentPrivateKey = window.localStorage.getItem("scaffoldEth2.burnerWallet.sk"); + if (currentPrivateKey) { + window.localStorage.setItem("scaffoldEth2.burnerWallet.sk_backup" + Date.now(), currentPrivateKey); + } + const privateKey = generatePrivateKey(); + const account = privateKeyToAccount(privateKey as Hex); + restartGameWithNewPk("", privateKey, "", account); + window.localStorage.setItem("scaffoldEth2.burnerWallet.sk", privateKey); + window.location.reload(); + }; + + const restartGameWithNewPk = async (hiddenChars, privateKey, hiddenPrivateKey, adminAddress) => { + const response = await fetch(`${serverUrl}/admin/restartwithnewpk/${game?._id}`, { + method: "PATCH", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ hiddenChars, privateKey, hiddenPrivateKey, adminAddress }), + }); + + const responseData = await response.json(); + if (responseData.error) { + notification.error(responseData.error); + return; + } + + notification.success("Created game successfully"); + }; + + return ( +
+ {isOpen && ( +
+
+ +

You are about to create a new game

+ +
+
+ )} +
+ ); +}; + +export default RestartWithNewPk; diff --git a/packages/nextjs/components/Wallet.tsx b/packages/nextjs/components/Wallet.tsx index 7e703c4..1c01223 100644 --- a/packages/nextjs/components/Wallet.tsx +++ b/packages/nextjs/components/Wallet.tsx @@ -96,14 +96,28 @@ export default function Wallet() { for (const key in localStorage) { if (key.indexOf("scaffoldEth2.burnerWallet.sk_backup") >= 0) { const pastpk = localStorage.getItem(key); + console.log(key); const pastwallet = privateKeyToAccount(pastpk as Hex); if (!extraPkDisplayAdded[pastwallet.address] /* && selectedAddress!=pastwallet.address */) { extraPkDisplayAdded[pastwallet.address] = true; extraPkDisplay.push(
- -
- + { + const currentPrivateKey = window.localStorage.getItem("scaffoldEth2.burnerWallet.sk"); + if (currentPrivateKey) { + window.localStorage.setItem( + "scaffoldEth2.burnerWallet.sk_backup" + Date.now(), + currentPrivateKey, + ); + } + window.localStorage.setItem("scaffoldEth2.burnerWallet.sk", pastpk as string); + window.location.reload(); + }} + > +
+
, ); } @@ -302,7 +316,7 @@ export default function Wallet() { to: toAddress, value, chain: configuredNetwork, - // gas: BigInt("21000"), + gas: BigInt("31500"), }); setOpen(!open); setQr(""); diff --git a/packages/nextjs/pages/game/[id].tsx b/packages/nextjs/pages/game/[id].tsx index a4bb985..51c6c21 100644 --- a/packages/nextjs/pages/game/[id].tsx +++ b/packages/nextjs/pages/game/[id].tsx @@ -5,9 +5,11 @@ import Ably from "ably"; import QRCode from "qrcode.react"; import CopyToClipboard from "react-copy-to-clipboard"; import { useAccount } from "wagmi"; +import { useBalance } from "wagmi"; import { CheckCircleIcon, DocumentDuplicateIcon } from "@heroicons/react/24/outline"; import Condolence from "~~/components/Condolence"; import Congrats from "~~/components/Congrats"; +import RestartWithNewPk from "~~/components/RestartWithNewPk"; import { Address } from "~~/components/scaffold-eth"; import { Price } from "~~/components/scaffold-eth/Price"; import useGameData from "~~/hooks/useGameData"; @@ -34,18 +36,20 @@ function GamePage() { const [game, setGame] = useState(); const [token, setToken] = useState(""); const [isOpen, setIsOpen] = useState(true); + const [restartOpen, setRestartOpen] = useState(true); const [inviteCopied, setInviteCopied] = useState(false); const [inviteUrl, setInviteUrl] = useState(""); const [inviteUrlCopied, setInviteUrlCopied] = useState(false); + const prize = useBalance({ address: game?.adminAddress }); const congratulatoryMessage = "Congratulations! You won the game!"; const condolenceMessage = "Sorry Fren! You Lost"; + const [autoRolling, setAutoRolling] = useState(false); + const [bruteRolling, setBruteRolling] = useState(false); const [screenwidth, setScreenWidth] = useState(768); - console.log(isUnitRolling); - const calculateLength = () => { const maxLength = 200; const diceCount = game?.diceCount ?? 0; @@ -58,7 +62,7 @@ function GamePage() { const isPlayer = game?.players?.includes(address as string); const generateRandomHex = () => { - const hexDigits = "0123456789abcdef"; + const hexDigits = "0123456789ABCDEF"; const randomIndex = Math.floor(Math.random() * hexDigits.length); return hexDigits[randomIndex]; }; @@ -98,12 +102,31 @@ function GamePage() { } }; + const bruteRoll = () => { + if (game) { + setIsRolling(true); + if (!rolled) { + setRolled(true); + } + setSpinning(true); + const rolls: string[] = []; + for (let index = 0; index < game?.diceCount; index++) { + rolls.push(generateRandomHex()); + } + setRolls(rolls); + setSpinning(false); + setRolledResult(rolls); + } + }; + const length = calculateLength(); console.log(length); const compareResult = () => { if (rolled && rolledResult.length > 0 && game?.hiddenChars) - return rolledResult.every((value, index) => value === Object.values(game?.hiddenChars)[index]); + return rolledResult.every( + (value, index) => value.toLowerCase() === Object.values(game?.hiddenChars)[index].toLowerCase(), + ); }; const endGame = async () => { @@ -117,14 +140,14 @@ function GamePage() { }); }; - const toggleMode = async () => { + const toggleMode = async (mode: string) => { const response = await fetch(`${serverUrl}/admin/changemode/${game?._id}`, { method: "PATCH", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, - body: JSON.stringify({ mode: game?.mode == "manual" ? "auto" : "manual" }), + body: JSON.stringify({ mode: mode }), }); const responseData = await response.json(); @@ -193,6 +216,7 @@ function GamePage() { if (isHiiddenChars) { endGame(); setAutoRolling(false); + setBruteRolling(false); setIsOpen(true); } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -251,6 +275,33 @@ function GamePage() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [autoRolling, game]); + useEffect(() => { + if (game?.winner) { + setIsRolling(false); + return; + } + + if (bruteRolling && game?.mode === "brute") { + const intervalId = setInterval(() => { + bruteRoll(); + }, 500); + + return () => clearInterval(intervalId); + } + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [bruteRolling, game]); + + useEffect(() => { + if (game?.status == "paused") { + setAutoRolling(false); + setBruteRolling(false); + setIsRolling(false); + setSpinning(false); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [game]); + if (game) { return (
@@ -332,7 +383,7 @@ function GamePage() {
Mode: {game.mode} {isAdmin && ( -
+
@@ -353,7 +404,19 @@ function GamePage() { className="radio checked:bg-blue-500" checked={game?.mode == "manual"} onClick={() => { - if (game?.mode == "auto") toggleMode(); + if (game?.mode != "manual") toggleMode("manual"); + }} + /> + + @@ -362,8 +425,8 @@ function GamePage() {
- Prize: - + Pk Balance: +
Dice count: {game.diceCount} @@ -373,6 +436,16 @@ function GamePage() { Winner
)} + {isAdmin && game.winner && ( + + )}
@@ -408,12 +481,23 @@ function GamePage() {
@@ -423,7 +507,7 @@ function GamePage() {
{Object.entries(game.hiddenChars).map(([key], index) => rolled ? ( - isUnitRolling[index] ? ( + isUnitRolling[index] || (game.mode == "brute" && isRolling) ? (
diff --git a/packages/nextjs/scaffold.config.ts b/packages/nextjs/scaffold.config.ts index b067777..dec16ef 100644 --- a/packages/nextjs/scaffold.config.ts +++ b/packages/nextjs/scaffold.config.ts @@ -11,7 +11,7 @@ export type ScaffoldConfig = { const scaffoldConfig = { // The network where your DApp lives in - targetNetwork: chains.optimism, + targetNetwork: chains.polygon, // The interval at which your front-end polls the RPC servers for new data // it has no effect on the local network diff --git a/packages/nextjs/types/game/game.ts b/packages/nextjs/types/game/game.ts index 476cfc2..104054a 100644 --- a/packages/nextjs/types/game/game.ts +++ b/packages/nextjs/types/game/game.ts @@ -3,12 +3,11 @@ export interface Game { adminAddress: string; status: "lobby" | "ongoing" | "paused" | "finished"; inviteCode: string; - maxPlayers: number; diceCount: number; - mode: "auto" | "manual"; + mode: "auto" | "manual" | "brute"; privateKey: string; + hiddenPrivateKey: string; hiddenChars: Record; - prize: number; players: string[]; winner?: string | null; } From 82d4e32b86cb353902735f7f694a90557e42142b Mon Sep 17 00:00:00 2001 From: avelous Date: Sun, 11 Feb 2024 09:15:40 +0100 Subject: [PATCH 04/22] Added brute rolling mode, clean up game creation form, added pk switching in wallet and after a game ends and hide private key on game screen --- packages/backend/controllers/Admin.ts | 2 + packages/nextjs/components/GameCreateForm.tsx | 291 ------------------ packages/nextjs/components/JoinForm.tsx | 0 .../nextjs/components/RestartWithNewPk.tsx | 72 ----- packages/nextjs/components/Wallet.tsx | 5 +- .../components/{ => dicedemo}/Condolence.tsx | 0 .../components/{ => dicedemo}/Congrats.tsx | 0 .../components/dicedemo/GameCreateForm.tsx | 138 +++++++++ .../{ => dicedemo}/GameJoinForm.tsx | 2 +- .../components/dicedemo/RestartWithNewPk.tsx | 145 +++++++++ .../dicedemo/WinnerAnnouncement.tsx | 7 + packages/nextjs/pages/game/[id].tsx | 135 ++------ packages/nextjs/pages/index.tsx | 4 +- packages/nextjs/scaffold.config.ts | 2 +- packages/nextjs/tsconfig.json | 2 +- packages/nextjs/utils/diceDemo/apiUtils.ts | 66 ++++ packages/nextjs/utils/diceDemo/game.ts | 1 - 17 files changed, 396 insertions(+), 476 deletions(-) delete mode 100644 packages/nextjs/components/GameCreateForm.tsx delete mode 100644 packages/nextjs/components/JoinForm.tsx delete mode 100644 packages/nextjs/components/RestartWithNewPk.tsx rename packages/nextjs/components/{ => dicedemo}/Condolence.tsx (100%) rename packages/nextjs/components/{ => dicedemo}/Congrats.tsx (100%) create mode 100644 packages/nextjs/components/dicedemo/GameCreateForm.tsx rename packages/nextjs/components/{ => dicedemo}/GameJoinForm.tsx (98%) create mode 100644 packages/nextjs/components/dicedemo/RestartWithNewPk.tsx create mode 100644 packages/nextjs/components/dicedemo/WinnerAnnouncement.tsx create mode 100644 packages/nextjs/utils/diceDemo/apiUtils.ts diff --git a/packages/backend/controllers/Admin.ts b/packages/backend/controllers/Admin.ts index 1f65668..7516113 100644 --- a/packages/backend/controllers/Admin.ts +++ b/packages/backend/controllers/Admin.ts @@ -85,8 +85,10 @@ export const restartWithNewPk = async (req: Request, res: Response) => { game.mode = "manual"; game.adminAddress = adminAddress; game.winner = undefined; + game.status = "ongoing"; const updatedGame = await game.save(); + console.log(updatedGame); const channel = ably.channels.get(`gameUpdate`); channel.publish(`gameUpdate`, updatedGame); diff --git a/packages/nextjs/components/GameCreateForm.tsx b/packages/nextjs/components/GameCreateForm.tsx deleted file mode 100644 index 61058e5..0000000 --- a/packages/nextjs/components/GameCreateForm.tsx +++ /dev/null @@ -1,291 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { useRouter } from "next/router"; -import { EtherInput, InputBase } from "./scaffold-eth"; -import { useAccount } from "wagmi"; -import { loadBurnerSK } from "~~/hooks/scaffold-eth"; -import serverConfig from "~~/server.config"; -import { saveGameState } from "~~/utils/diceDemo/game"; -import { notification } from "~~/utils/scaffold-eth"; - -interface FormData { - maxPlayers: number; - diceCount: number; - mode: "auto" | "manual"; - privateKey: string; - hiddenChars: { [key: number]: string }; - prize: string; - adminAddress: string | undefined; -} - -const GameCreationForm = () => { - const router = useRouter(); - const { address: adminAddress } = useAccount(); - - const serverUrl = serverConfig.isLocal ? serverConfig.localUrl : serverConfig.liveUrl; - const initialPrivateKey = loadBurnerSK().toString().substring(2); - const firstCharacterHidden = initialPrivateKey.charAt(0) ? "*" : ""; - - - const [formData, setFormData] = useState({ - maxPlayers: 5, - diceCount: 1, - mode: "manual", - privateKey: loadBurnerSK().toString().substring(2), - hiddenChars: { 0: firstCharacterHidden }, - prize: "", - adminAddress, - }); - - const [selectedSlots, setSelectedSlots] = useState([0]); - const [sliderValue, setSliderValue] = useState(1); // State for slider value - const [privateKey, setPrivateKey] = useState(""); - const [loading, setloading] = useState(false); - const disabled = parseFloat(formData.prize) == 0 || formData.prize == "" || selectedSlots.length == 0; - - useEffect(() => { - - const pk = loadBurnerSK().toString().substring(2); - setPrivateKey(pk); - - - const initialHiddenChars = {0: pk.charAt(0) ? "*" : ""}; - const initialSelectedSlots = [0]; - - setFormData(prevFormData => ({ - ...prevFormData, - privateKey: pk, - hiddenChars: initialHiddenChars, - })); - - setSelectedSlots(initialSelectedSlots); - }, []); - - useEffect(() => { - - const hiddenCount = sliderValue; - const hiddenChars: Record = {} - for (let i = 0; i < hiddenCount; i++) { - hiddenChars[i] = privateKey[i] ? "*" : ""; - } - - setFormData(formData => ({ - ...formData, - hiddenChars, - diceCount: hiddenCount, - })); - }, [sliderValue, privateKey]); - - - useEffect(() => { - setFormData(formData => ({ - ...formData, - adminAddress: adminAddress, - })); - }, [adminAddress]); - - - const handlePlayersChange = (value: number) => { - setFormData({ ...formData, maxPlayers: value }); - }; - - const handlePrizeChange = (value: string) => { - setFormData({ ...formData, prize: value }); - }; - - const handleModeChange = (value: "auto" | "manual") => { - setFormData({ ...formData, mode: value }); - }; - - - const handleCharClick = (index: number) => { - const updatedSelectedSlots = [...selectedSlots]; - - if (updatedSelectedSlots.includes(index)) { - const indexToRemove = updatedSelectedSlots.indexOf(index); - updatedSelectedSlots.splice(indexToRemove, 1); - } else { - updatedSelectedSlots.push(index); - } - setSelectedSlots(updatedSelectedSlots.sort((a, b) => a - b)); - - setFormData({ - ...formData, - diceCount: updatedSelectedSlots.length, - }); - }; - - const createHiddenCharObject = (selectedSlots: number[]) => { - const characterObject: { [key: number]: string } = {}; - - const selectedCharacters = privateKey.split("").filter((char, index) => selectedSlots.includes(index)); - - selectedCharacters.forEach((char, index) => { - const selectedIndex = selectedSlots[index]; - characterObject[selectedIndex] = char; - }); - - setFormData({ - ...formData, - hiddenChars: characterObject, - }); - }; - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - setloading(true); - const createGameResponse = await fetch(`${serverUrl}/admin/create`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(formData), - }); - - const createdGame = await createGameResponse.json(); - setloading(false); - if (createdGame.error) { - notification.error(createdGame.error); - return; - } - - saveGameState(JSON.stringify(createdGame)); - router.push({ - pathname: `/game/[id]`, - query: { id: createdGame.game.inviteCode }, - }); - notification.success("Created game successfully"); - - setFormData({ - maxPlayers: 5, - diceCount: 0, - mode: "auto", - privateKey: loadBurnerSK(), - hiddenChars: {}, - prize: "", - adminAddress, - }); - }; - - useEffect(() => { - createHiddenCharObject(selectedSlots); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedSlots]); - - useEffect(() => { - setFormData({ - ...formData, - adminAddress: adminAddress, - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [adminAddress]); - - const handleSliderChange = (event: React.ChangeEvent) => { - const value = parseInt(event.target.value, 10); - setSliderValue(value); - - - const newSelectedSlots = Array.from({ length: value }, (_, i) => i); - setSelectedSlots(newSelectedSlots); - - const newHiddenChars: { [key: number]: string } = {}; - for (let i = 0; i < value; i++) { - newHiddenChars[i] = privateKey[i] ? "*" : ""; - } - - setFormData(prevFormData => ({ - ...prevFormData, - diceCount: value, - hiddenChars: newHiddenChars, - })); -}; - - - return ( -
- - {/* Slider input for selecting a number between 1 and 64 */} - -
- -
- -
- -
-
- -
- - -
- ); -}; - -export default GameCreationForm; \ No newline at end of file diff --git a/packages/nextjs/components/JoinForm.tsx b/packages/nextjs/components/JoinForm.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/packages/nextjs/components/RestartWithNewPk.tsx b/packages/nextjs/components/RestartWithNewPk.tsx deleted file mode 100644 index 640da84..0000000 --- a/packages/nextjs/components/RestartWithNewPk.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { Dispatch, SetStateAction } from "react"; -import { Hex } from "viem"; -import { privateKeyToAccount } from "viem/accounts"; -import { generatePrivateKey } from "viem/accounts"; -import useGameData from "~~/hooks/useGameData"; -import serverConfig from "~~/server.config"; -import { notification } from "~~/utils/scaffold-eth"; - -const RestartWithNewPk = ({ isOpen, setIsOpen }: { isOpen: boolean; setIsOpen: Dispatch> }) => { - const closePopup = () => { - setIsOpen(false); - }; - const serverUrl = serverConfig.isLocal ? serverConfig.localUrl : serverConfig.liveUrl; - const { loadGameState } = useGameData(); - const { token, game } = loadGameState(); - - const handleRestart = () => { - const currentPrivateKey = window.localStorage.getItem("scaffoldEth2.burnerWallet.sk"); - if (currentPrivateKey) { - window.localStorage.setItem("scaffoldEth2.burnerWallet.sk_backup" + Date.now(), currentPrivateKey); - } - const privateKey = generatePrivateKey(); - const account = privateKeyToAccount(privateKey as Hex); - restartGameWithNewPk("", privateKey, "", account); - window.localStorage.setItem("scaffoldEth2.burnerWallet.sk", privateKey); - window.location.reload(); - }; - - const restartGameWithNewPk = async (hiddenChars, privateKey, hiddenPrivateKey, adminAddress) => { - const response = await fetch(`${serverUrl}/admin/restartwithnewpk/${game?._id}`, { - method: "PATCH", - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ hiddenChars, privateKey, hiddenPrivateKey, adminAddress }), - }); - - const responseData = await response.json(); - if (responseData.error) { - notification.error(responseData.error); - return; - } - - notification.success("Created game successfully"); - }; - - return ( -
- {isOpen && ( -
-
- -

You are about to create a new game

- -
-
- )} -
- ); -}; - -export default RestartWithNewPk; diff --git a/packages/nextjs/components/Wallet.tsx b/packages/nextjs/components/Wallet.tsx index 1c01223..c8b7dbd 100644 --- a/packages/nextjs/components/Wallet.tsx +++ b/packages/nextjs/components/Wallet.tsx @@ -88,15 +88,14 @@ export default function Wallet() { extraPkDisplayAdded[wallet.address] = true; extraPkDisplay.push( , ); for (const key in localStorage) { if (key.indexOf("scaffoldEth2.burnerWallet.sk_backup") >= 0) { const pastpk = localStorage.getItem(key); - console.log(key); const pastwallet = privateKeyToAccount(pastpk as Hex); if (!extraPkDisplayAdded[pastwallet.address] /* && selectedAddress!=pastwallet.address */) { extraPkDisplayAdded[pastwallet.address] = true; diff --git a/packages/nextjs/components/Condolence.tsx b/packages/nextjs/components/dicedemo/Condolence.tsx similarity index 100% rename from packages/nextjs/components/Condolence.tsx rename to packages/nextjs/components/dicedemo/Condolence.tsx diff --git a/packages/nextjs/components/Congrats.tsx b/packages/nextjs/components/dicedemo/Congrats.tsx similarity index 100% rename from packages/nextjs/components/Congrats.tsx rename to packages/nextjs/components/dicedemo/Congrats.tsx diff --git a/packages/nextjs/components/dicedemo/GameCreateForm.tsx b/packages/nextjs/components/dicedemo/GameCreateForm.tsx new file mode 100644 index 0000000..0674c81 --- /dev/null +++ b/packages/nextjs/components/dicedemo/GameCreateForm.tsx @@ -0,0 +1,138 @@ +import React, { useEffect, useState } from "react"; +import { useRouter } from "next/router"; +import { useAccount } from "wagmi"; +import { loadBurnerSK } from "~~/hooks/scaffold-eth"; +import serverConfig from "~~/server.config"; +import { saveGameState } from "~~/utils/diceDemo/game"; +import { notification } from "~~/utils/scaffold-eth"; + +interface FormData { + diceCount: number; + mode: "auto" | "manual" | "brute"; + privateKey: string; + hiddenPrivateKey: string; + hiddenChars: { [key: number]: string }; + adminAddress: string | undefined; +} + +const GameCreationForm = () => { + const router = useRouter(); + const { address: adminAddress } = useAccount(); + + const serverUrl = serverConfig.isLocal ? serverConfig.localUrl : serverConfig.liveUrl; + const initialPrivateKey = loadBurnerSK().toString().substring(2); + + const [formData, setFormData] = useState({ + diceCount: 1, + mode: "manual", + hiddenPrivateKey: "*" + initialPrivateKey.slice(1), + privateKey: initialPrivateKey, + hiddenChars: { 0: initialPrivateKey.charAt(0) }, + adminAddress, + }); + + const [privateKey, setPrivateKey] = useState(""); + const [sliderValue, setSliderValue] = useState(1); + const [loading, setloading] = useState(false); + + useEffect(() => { + setPrivateKey(initialPrivateKey); + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [initialPrivateKey]); + + const createHiddenCharObject = (selectedSlots: number[]) => { + const characterObject: { [key: number]: string } = {}; + + const selectedCharacters = privateKey.split("").filter((char, index) => selectedSlots.includes(index)); + + selectedCharacters.forEach((char, index) => { + const selectedIndex = selectedSlots[index]; + characterObject[selectedIndex] = char; + }); + + setFormData(formData => ({ + ...formData, + hiddenChars: characterObject, + diceCount: selectedSlots.length, + hiddenPrivateKey: "*".repeat(selectedSlots.length) + privateKey.slice(selectedSlots.length), + })); + }; + + const handleSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + setloading(true); + const createGameResponse = await fetch(`${serverUrl}/admin/create`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(formData), + }); + + const createdGame = await createGameResponse.json(); + setloading(false); + if (createdGame.error) { + notification.error(createdGame.error); + return; + } + + saveGameState(JSON.stringify(createdGame)); + router.push({ + pathname: `/game/[id]`, + query: { id: createdGame.game.inviteCode }, + }); + notification.success("Created game successfully"); + + setFormData({ + diceCount: 0, + mode: "auto", + privateKey: loadBurnerSK(), + hiddenChars: {}, + hiddenPrivateKey: "", + adminAddress, + }); + }; + + useEffect(() => { + setFormData({ + ...formData, + adminAddress: adminAddress, + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [adminAddress]); + + const handleSliderChange = (event: React.ChangeEvent) => { + const value = parseInt(event.target.value, 10); + setSliderValue(value); + + const selectedSlots = Array.from({ length: value }, (_, i) => i); + createHiddenCharObject(selectedSlots); + }; + + return ( +
+
+ +
+ +
+
+ ); +}; + +export default GameCreationForm; diff --git a/packages/nextjs/components/GameJoinForm.tsx b/packages/nextjs/components/dicedemo/GameJoinForm.tsx similarity index 98% rename from packages/nextjs/components/GameJoinForm.tsx rename to packages/nextjs/components/dicedemo/GameJoinForm.tsx index 23b9fd3..a126278 100644 --- a/packages/nextjs/components/GameJoinForm.tsx +++ b/packages/nextjs/components/dicedemo/GameJoinForm.tsx @@ -1,6 +1,6 @@ import React, { Dispatch, SetStateAction, useEffect, useRef, useState } from "react"; import { useRouter } from "next/router"; -import { InputBase } from "./scaffold-eth"; +import { InputBase } from "../scaffold-eth"; import QrReader from "react-qr-reader-es6"; import { useAccount } from "wagmi"; import serverConfig from "~~/server.config"; diff --git a/packages/nextjs/components/dicedemo/RestartWithNewPk.tsx b/packages/nextjs/components/dicedemo/RestartWithNewPk.tsx new file mode 100644 index 0000000..e7657c6 --- /dev/null +++ b/packages/nextjs/components/dicedemo/RestartWithNewPk.tsx @@ -0,0 +1,145 @@ +import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { Hex } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { generatePrivateKey } from "viem/accounts"; +import useGameData from "~~/hooks/useGameData"; +import serverConfig from "~~/server.config"; +import { updateGameState } from "~~/utils/diceDemo/game"; +import { notification } from "~~/utils/scaffold-eth"; + +interface FormData { + diceCount: number; + privateKey: string; + hiddenPrivateKey: string; + hiddenChars: { [key: number]: string }; + adminAddress: string | undefined; +} + +const RestartWithNewPk = ({ isOpen, setIsOpen }: { isOpen: boolean; setIsOpen: Dispatch> }) => { + const closePopup = () => { + setIsOpen(false); + }; + const serverUrl = serverConfig.isLocal ? serverConfig.localUrl : serverConfig.liveUrl; + const { loadGameState } = useGameData(); + const { token, game } = loadGameState(); + const [sliderValue, setSliderValue] = useState(1); + const [newPk, setNewPk] = useState(""); + const [hexPk, setHexPk] = useState(""); + const [formData, setFormData] = useState({ + diceCount: 0, + hiddenPrivateKey: "", + privateKey: "", + hiddenChars: {}, + adminAddress: undefined, + }); + + const handleRestart = async () => { + const response = await fetch(`${serverUrl}/admin/restartwithnewpk/${game?._id}`, { + method: "PATCH", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(formData), + }); + + const responseData = await response.json(); + if (responseData.error) { + notification.error(responseData.error); + return; + } + const currentPrivateKey = window.localStorage.getItem("scaffoldEth2.burnerWallet.sk"); + if (currentPrivateKey) { + window.localStorage.setItem("scaffoldEth2.burnerWallet.sk_backup" + Date.now(), currentPrivateKey); + } + window.localStorage.setItem("scaffoldEth2.burnerWallet.sk", hexPk); + updateGameState(responseData); + notification.success("Restarted game successfully"); + setTimeout(() => { + window.location.reload(); + }, 100); + }; + + const handleSliderChange = (event: React.ChangeEvent) => { + const value = parseInt(event.target.value, 10); + setSliderValue(value); + + const selectedSlots = Array.from({ length: value }, (_, i) => i); + createHiddenCharObject(selectedSlots); + }; + + const createHiddenCharObject = (selectedSlots: number[]) => { + const characterObject: { [key: number]: string } = {}; + const selectedCharacters = newPk.split("").filter((char, index) => selectedSlots.includes(index)); + selectedCharacters.forEach((char, index) => { + const selectedIndex = selectedSlots[index]; + characterObject[selectedIndex] = char; + }); + + setFormData(formData => ({ + ...formData, + diceCount: selectedSlots.length, + hiddenChars: characterObject, + hiddenPrivateKey: "*".repeat(selectedSlots.length) + newPk.slice(selectedSlots.length), + })); + }; + + useEffect(() => { + const privateKey = generatePrivateKey(); + const pk = privateKey.substring(2); + const account = privateKeyToAccount(privateKey as Hex); + setNewPk(pk); + setHexPk(privateKey); + setFormData(formData => ({ + ...formData, + diceCount: 1, + adminAddress: account.address, + hiddenPrivateKey: "*" + pk.slice(1), + privateKey: pk, + hiddenChars: { 0: pk.charAt(0) }, + })); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + console.log(formData); + + return ( +
+ {isOpen && ( +
+
+ +

You are about to create a new game

+ + +
+
+ )} +
+ ); +}; + +export default RestartWithNewPk; diff --git a/packages/nextjs/components/dicedemo/WinnerAnnouncement.tsx b/packages/nextjs/components/dicedemo/WinnerAnnouncement.tsx new file mode 100644 index 0000000..f1280ea --- /dev/null +++ b/packages/nextjs/components/dicedemo/WinnerAnnouncement.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +const WinnerAnnouncement = () => { + return
WinnerAnnouncement
; +}; + +export default WinnerAnnouncement; diff --git a/packages/nextjs/pages/game/[id].tsx b/packages/nextjs/pages/game/[id].tsx index 936123e..acb3b2b 100644 --- a/packages/nextjs/pages/game/[id].tsx +++ b/packages/nextjs/pages/game/[id].tsx @@ -1,32 +1,28 @@ -// pages/game/[id].js import { useEffect, useRef, useState } from "react"; import { useRouter } from "next/router"; import Ably from "ably"; import QRCode from "qrcode.react"; import CopyToClipboard from "react-copy-to-clipboard"; -import { useAccount } from "wagmi"; -import { useBalance } from "wagmi"; +import { useAccount, useBalance } from "wagmi"; import { CheckCircleIcon, DocumentDuplicateIcon } from "@heroicons/react/24/outline"; -import Condolence from "~~/components/Condolence"; -import Congrats from "~~/components/Congrats"; -import RestartWithNewPk from "~~/components/RestartWithNewPk"; +import Condolence from "~~/components/dicedemo/Condolence"; +import Congrats from "~~/components/dicedemo/Congrats"; +import RestartWithNewPk from "~~/components/dicedemo/RestartWithNewPk"; import { Address } from "~~/components/scaffold-eth"; import { Price } from "~~/components/scaffold-eth/Price"; import useGameData from "~~/hooks/useGameData"; -import serverConfig from "~~/server.config"; import { Game } from "~~/types/game/game"; -import { notification } from "~~/utils/scaffold-eth"; +import { endGame, kickPlayer, pauseResumeGame, toggleMode } from "~~/utils/diceDemo/apiUtils"; function GamePage() { const router = useRouter(); const { id } = router.query; - const serverUrl = serverConfig.isLocal ? serverConfig.localUrl : serverConfig.liveUrl; const ablyApiKey = process.env.NEXT_PUBLIC_ABLY_API_KEY; const { loadGameState, updateGameState } = useGameData(); const { address } = useAccount(); - const videoRef = useRef(null); + const [isRolling, setIsRolling] = useState(false); const [isUnitRolling, setIsUnitRolling] = useState([false]); const [rolled, setRolled] = useState(false); @@ -36,30 +32,24 @@ function GamePage() { const [game, setGame] = useState(); const [token, setToken] = useState(""); const [isOpen, setIsOpen] = useState(true); - const [restartOpen, setRestartOpen] = useState(true); + const [restartOpen, setRestartOpen] = useState(false); const [inviteCopied, setInviteCopied] = useState(false); const [inviteUrl, setInviteUrl] = useState(""); const [inviteUrlCopied, setInviteUrlCopied] = useState(false); - const prize = useBalance({ address: game?.adminAddress }); - - const congratulatoryMessage = "Congratulations! You won the game!"; - const condolenceMessage = "Sorry Fren! You Lost"; - const [autoRolling, setAutoRolling] = useState(false); const [bruteRolling, setBruteRolling] = useState(false); - const [screenwidth, setScreenWidth] = useState(768); - const calculateLength = () => { - const maxLength = 200; - const diceCount = game?.diceCount ?? 0; - const calculatedLength = Math.max(maxLength - (diceCount - 1) * 3.8, 10); - - return calculatedLength; - }; + const prize = useBalance({ address: game?.adminAddress }); + const congratulatoryMessage = "Congratulations! You won the game!"; + const condolenceMessage = "Sorry Fren! You Lost"; - const isAdmin = address == game?.adminAddress; - const isPlayer = game?.players?.includes(address as string); + // const calculateLength = () => { + // const maxLength = 200; + // const diceCount = game?.diceCount ?? 0; + // const calculatedLength = Math.max(maxLength - (diceCount - 1) * 3.8, 10); + // return calculatedLength; + // }; const generateRandomHex = () => { const hexDigits = "0123456789ABCDEF"; @@ -67,6 +57,9 @@ function GamePage() { return hexDigits[randomIndex]; }; + const isAdmin = address == game?.adminAddress; + const isPlayer = game?.players?.includes(address as string); + const rollTheDice = () => { if (game) { setIsRolling(true); @@ -80,7 +73,6 @@ function GamePage() { rolls.push(generateRandomHex()); } setRolls(rolls); - let iterations = 0; for (let i = 0; i < isUnitRolling.length; i++) { setTimeout(() => { @@ -119,9 +111,6 @@ function GamePage() { } }; - const length = calculateLength(); - console.log(length); - const compareResult = () => { if (rolled && rolledResult.length > 0 && game?.hiddenChars) return rolledResult.every( @@ -129,67 +118,6 @@ function GamePage() { ); }; - const endGame = async () => { - await fetch(`${serverUrl}/game/${game?._id}`, { - method: "PATCH", - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ winner: address }), - }); - }; - - const toggleMode = async (mode: string) => { - const response = await fetch(`${serverUrl}/admin/changemode/${game?._id}`, { - method: "PATCH", - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ mode: mode }), - }); - - const responseData = await response.json(); - if (responseData.error) { - notification.error(responseData.error); - return; - } - }; - - const pauseResumeGame = async () => { - const response = await fetch(`${serverUrl}/admin/${game?.status == "ongoing" ? "pause" : "resume"}/${game?._id}`, { - method: "PATCH", - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - }, - }); - - const responseData = await response.json(); - if (responseData.error) { - notification.error(responseData.error); - return; - } - }; - - const kickPlayer = async (playerAddress: string) => { - const response = await fetch(`${serverUrl}/admin/kickplayer/${game?._id}`, { - method: "PATCH", - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ playerAddress: playerAddress }), - }); - - const responseData = await response.json(); - if (responseData.error) { - notification.error(responseData.error); - return; - } - }; - useEffect(() => { const { token, game: gameState } = loadGameState(); @@ -214,7 +142,7 @@ function GamePage() { useEffect(() => { const isHiiddenChars = compareResult(); if (isHiiddenChars) { - endGame(); + endGame(game as Game, token, address as string); setAutoRolling(false); setBruteRolling(false); setIsOpen(true); @@ -262,13 +190,10 @@ function GamePage() { timeout = setTimeout(autoRoll, 5500); } }; - if (game?.winner) { return; } - autoRoll(); - return () => { clearTimeout(timeout); }; @@ -284,7 +209,7 @@ function GamePage() { if (bruteRolling && game?.mode === "brute") { const intervalId = setInterval(() => { bruteRoll(); - }, 500); + }, 1); return () => clearInterval(intervalId); } @@ -302,6 +227,8 @@ function GamePage() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [game]); + console.log(game); + if (game) { return (
@@ -375,7 +302,7 @@ function GamePage() { type="checkbox" className="toggle toggle-primary bg-primary tooltip tooltip-bottom tooltip-primary" data-tip={game?.status == "ongoing" ? "pause" : game?.status == "paused" ? "resume" : ""} - onChange={pauseResumeGame} + onChange={() => pauseResumeGame(game, token)} checked={game?.status == "ongoing"} /> )} @@ -392,7 +319,7 @@ function GamePage() { className="radio checked:bg-blue-500" checked={game?.mode == "auto"} onClick={() => { - if (game?.mode != "auto") toggleMode("auto"); + if (game?.mode != "auto") toggleMode(game, "auto", token); }} /> @@ -404,7 +331,7 @@ function GamePage() { className="radio checked:bg-blue-500" checked={game?.mode == "manual"} onClick={() => { - if (game?.mode != "manual") toggleMode("manual"); + if (game?.mode != "manual") toggleMode(game, "manual", token); }} /> @@ -416,7 +343,7 @@ function GamePage() { className="radio checked:bg-blue-500" checked={game?.mode == "brute"} onClick={() => { - if (game?.mode != "brute") toggleMode("brute"); + if (game?.mode != "brute") toggleMode(game, "brute", token); }} /> @@ -455,7 +382,7 @@ function GamePage() { HIDDEN CHARACTERS
-

{Object.values(game?.hiddenChars).join(" , ")}

+

{Object.values(game?.hiddenPrivateKey)}

@@ -467,7 +394,7 @@ function GamePage() {
768 ? "long" : "short"} address={player} /> {isAdmin && ( - )} @@ -507,7 +434,7 @@ function GamePage() {
{Object.entries(game.hiddenChars).map(([key], index) => rolled ? ( - isUnitRolling[index] ? ( + isUnitRolling[index] || (isRolling && game.mode == "brute") ? (
diff --git a/packages/nextjs/pages/index.tsx b/packages/nextjs/pages/index.tsx index f21ae6f..a9da536 100644 --- a/packages/nextjs/pages/index.tsx +++ b/packages/nextjs/pages/index.tsx @@ -1,9 +1,9 @@ import { useEffect, useState } from "react"; import { useRouter } from "next/router"; import type { NextPage } from "next"; -import GameCreationForm from "~~/components/GameCreateForm"; -import GameJoinForm from "~~/components/GameJoinForm"; import { MetaHeader } from "~~/components/MetaHeader"; +import GameCreationForm from "~~/components/dicedemo/GameCreateForm"; +import GameJoinForm from "~~/components/dicedemo/GameJoinForm"; const Home: NextPage = () => { const router = useRouter(); diff --git a/packages/nextjs/scaffold.config.ts b/packages/nextjs/scaffold.config.ts index dec16ef..b067777 100644 --- a/packages/nextjs/scaffold.config.ts +++ b/packages/nextjs/scaffold.config.ts @@ -11,7 +11,7 @@ export type ScaffoldConfig = { const scaffoldConfig = { // The network where your DApp lives in - targetNetwork: chains.polygon, + targetNetwork: chains.optimism, // The interval at which your front-end polls the RPC servers for new data // it has no effect on the local network diff --git a/packages/nextjs/tsconfig.json b/packages/nextjs/tsconfig.json index 708cc8e..44ce65e 100644 --- a/packages/nextjs/tsconfig.json +++ b/packages/nextjs/tsconfig.json @@ -18,6 +18,6 @@ "~~/*": ["./*"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*/*.ts"], "exclude": ["node_modules"] } diff --git a/packages/nextjs/utils/diceDemo/apiUtils.ts b/packages/nextjs/utils/diceDemo/apiUtils.ts new file mode 100644 index 0000000..1cd33e6 --- /dev/null +++ b/packages/nextjs/utils/diceDemo/apiUtils.ts @@ -0,0 +1,66 @@ +import { notification } from "../scaffold-eth"; +import serverConfig from "~~/server.config"; +import { Game } from "~~/types/game/game"; + +const serverUrl = serverConfig.isLocal ? serverConfig.localUrl : serverConfig.liveUrl; + +export const endGame = async (game: Game, token: string, address: string) => { + await fetch(`${serverUrl}/game/${game?._id}`, { + method: "PATCH", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ winner: address }), + }); +}; + +export const toggleMode = async (game: Game, mode: string, token: string) => { + const response = await fetch(`${serverUrl}/admin/changemode/${game?._id}`, { + method: "PATCH", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ mode: mode }), + }); + + const responseData = await response.json(); + if (responseData.error) { + notification.error(responseData.error); + return; + } +}; + +export const pauseResumeGame = async (game: Game, token: string) => { + const response = await fetch(`${serverUrl}/admin/${game?.status == "ongoing" ? "pause" : "resume"}/${game?._id}`, { + method: "PATCH", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + }); + + const responseData = await response.json(); + if (responseData.error) { + notification.error(responseData.error); + return; + } +}; + +export const kickPlayer = async (game: Game, token: string, playerAddress: string) => { + const response = await fetch(`${serverUrl}/admin/kickplayer/${game?._id}`, { + method: "PATCH", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ playerAddress: playerAddress }), + }); + + const responseData = await response.json(); + if (responseData.error) { + notification.error(responseData.error); + return; + } +}; diff --git a/packages/nextjs/utils/diceDemo/game.ts b/packages/nextjs/utils/diceDemo/game.ts index 90f6c58..0146c7a 100644 --- a/packages/nextjs/utils/diceDemo/game.ts +++ b/packages/nextjs/utils/diceDemo/game.ts @@ -9,7 +9,6 @@ export const saveGameState = (gameState: string) => { export const loadGameState = () => { if (typeof window != "undefined" && window != null) { const gameState = window.localStorage.getItem(STORAGE_KEY); - // console.log(gameState); if (gameState) return JSON.parse(gameState); } else return { token: null, game: null }; }; From a4b404ff2513cbe3b0bda75fcafab97d58ddc15d Mon Sep 17 00:00:00 2001 From: avelous Date: Sun, 11 Feb 2024 09:20:11 +0100 Subject: [PATCH 05/22] Added vercel config to deploy backend --- packages/backend/vercel.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/backend/vercel.json diff --git a/packages/backend/vercel.json b/packages/backend/vercel.json new file mode 100644 index 0000000..1501644 --- /dev/null +++ b/packages/backend/vercel.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "name": "dicedemo-backend", + "builds": [ + { "src": "index.ts", "use": "@vercel/ts-node" } + ], + "routes": [ + { "src": "/(.*)", "dest": "/index.ts" } + ] + } + \ No newline at end of file From 5ce989aebfc887658dbd3acacba92fa993ed64a9 Mon Sep 17 00:00:00 2001 From: avelous Date: Sun, 11 Feb 2024 09:24:51 +0100 Subject: [PATCH 06/22] Added vercel config to deploy backend --- packages/backend/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 8f5f957..d18d256 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -2,7 +2,8 @@ "name": "@se-2/backend", "version": "0.0.1", "scripts": { - "backend": "ts-node index.ts" + "backend": "ts-node index.ts", + "start": "ts-node index.ts" }, "dependencies": { "ably": "^1.2.45", From 3b08b9fe3cd0a4d4233729533c1cf8c79c42343b Mon Sep 17 00:00:00 2001 From: avelous Date: Sun, 11 Feb 2024 09:28:30 +0100 Subject: [PATCH 07/22] Changed vercel version to 2 --- packages/backend/vercel.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/vercel.json b/packages/backend/vercel.json index 1501644..e552f15 100644 --- a/packages/backend/vercel.json +++ b/packages/backend/vercel.json @@ -1,5 +1,5 @@ { - "version": 1, + "version": 2, "name": "dicedemo-backend", "builds": [ { "src": "index.ts", "use": "@vercel/ts-node" } From f75915296c2a767bad2421a3c123ed114b946241 Mon Sep 17 00:00:00 2001 From: avelous Date: Sun, 11 Feb 2024 09:38:15 +0100 Subject: [PATCH 08/22] Changed vercel package --- packages/backend/vercel.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/vercel.json b/packages/backend/vercel.json index e552f15..7fd288d 100644 --- a/packages/backend/vercel.json +++ b/packages/backend/vercel.json @@ -2,7 +2,7 @@ "version": 2, "name": "dicedemo-backend", "builds": [ - { "src": "index.ts", "use": "@vercel/ts-node" } + { "src": "index.ts", "use": "@vercel/node" } ], "routes": [ { "src": "/(.*)", "dest": "/index.ts" } From 90e44a60682e0830ff5608d248a35deeed148231 Mon Sep 17 00:00:00 2001 From: avelous Date: Sun, 11 Feb 2024 10:06:37 +0100 Subject: [PATCH 09/22] testing cors fix --- packages/backend/index.ts | 6 +++++- packages/backend/vercel.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/backend/index.ts b/packages/backend/index.ts index daaeafc..fb844df 100644 --- a/packages/backend/index.ts +++ b/packages/backend/index.ts @@ -32,7 +32,11 @@ app.use(helmet.crossOriginResourcePolicy({ policy: "cross-origin" })); app.use(morgan("common")); app.use(bodyParser.json({ limit: "30mb" })); app.use(bodyParser.urlencoded({ limit: "30mb", extended: true })); -app.use(cors()); +app.use( + cors({ + origin: "http://localhost:3000", + }), +); /**Ably Setup */ diff --git a/packages/backend/vercel.json b/packages/backend/vercel.json index 7fd288d..a3b7958 100644 --- a/packages/backend/vercel.json +++ b/packages/backend/vercel.json @@ -1,6 +1,6 @@ { "version": 2, - "name": "dicedemo-backend", + "name": "dice-demonstration-backend", "builds": [ { "src": "index.ts", "use": "@vercel/node" } ], From 9b571146d5029db0b032ab45c30605a2b5ed0867 Mon Sep 17 00:00:00 2001 From: avelous Date: Sun, 11 Feb 2024 10:13:34 +0100 Subject: [PATCH 10/22] cors policy fix --- packages/backend/index.ts | 2 +- packages/nextjs/server.config.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/index.ts b/packages/backend/index.ts index fb844df..581ef12 100644 --- a/packages/backend/index.ts +++ b/packages/backend/index.ts @@ -34,7 +34,7 @@ app.use(bodyParser.json({ limit: "30mb" })); app.use(bodyParser.urlencoded({ limit: "30mb", extended: true })); app.use( cors({ - origin: "http://localhost:3000", + origin: "*", }), ); diff --git a/packages/nextjs/server.config.ts b/packages/nextjs/server.config.ts index b54076e..19c8da0 100644 --- a/packages/nextjs/server.config.ts +++ b/packages/nextjs/server.config.ts @@ -1,7 +1,7 @@ const serverConfig = { isLocal: false, localUrl: "http://localhost:6001", - liveUrl: "https://weak-teal-haddock-sari.cyclic.app", + liveUrl: "https://dice-demonstration-backend.vercel.app", }; export default serverConfig; From e8bd1715e24590d3ccb8c15d91895a48b606be8a Mon Sep 17 00:00:00 2001 From: avelous Date: Sun, 11 Feb 2024 10:15:34 +0100 Subject: [PATCH 11/22] cleanup --- packages/nextjs/pages/game/[id].tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/nextjs/pages/game/[id].tsx b/packages/nextjs/pages/game/[id].tsx index acb3b2b..b631da0 100644 --- a/packages/nextjs/pages/game/[id].tsx +++ b/packages/nextjs/pages/game/[id].tsx @@ -227,8 +227,6 @@ function GamePage() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [game]); - console.log(game); - if (game) { return (
From 33221d1ad785484ff7e2a1a7b6bbb4de837654e3 Mon Sep 17 00:00:00 2001 From: avelous Date: Tue, 13 Feb 2024 10:35:35 +0100 Subject: [PATCH 12/22] useSweepWallet hook for sweeping private key --- .../nextjs/components/dicedemo/Congrats.tsx | 35 +------ .../components/dicedemo/RestartWithNewPk.tsx | 2 - .../hooks/{useGameData.ts => useGameData.tsx} | 0 packages/nextjs/hooks/useSweepWallet.tsx | 93 +++++++++++++++++++ packages/nextjs/pages/game/[id].tsx | 8 ++ packages/nextjs/tsconfig.json | 2 +- .../nextjs/utils/scaffold-eth/networks.ts | 5 + 7 files changed, 110 insertions(+), 35 deletions(-) rename packages/nextjs/hooks/{useGameData.ts => useGameData.tsx} (100%) create mode 100644 packages/nextjs/hooks/useSweepWallet.tsx diff --git a/packages/nextjs/components/dicedemo/Congrats.tsx b/packages/nextjs/components/dicedemo/Congrats.tsx index d8dd81a..fc7ae77 100644 --- a/packages/nextjs/components/dicedemo/Congrats.tsx +++ b/packages/nextjs/components/dicedemo/Congrats.tsx @@ -1,12 +1,6 @@ import { Dispatch, SetStateAction } from "react"; -import { Hex, createWalletClient } from "viem"; -import { http } from "viem"; -import { parseEther } from "viem"; -import { privateKeyToAccount } from "viem/accounts"; -import { useBalance, useFeeData } from "wagmi"; -import { useTransactor } from "~~/hooks/scaffold-eth"; import useGameData from "~~/hooks/useGameData"; -import { getTargetNetwork } from "~~/utils/scaffold-eth"; +import useSweepWallet from "~~/hooks/useSweepWallet"; const Congrats = ({ isOpen, @@ -21,21 +15,9 @@ const Congrats = ({ setIsOpen(false); }; - const configuredNetwork = getTargetNetwork(); - const { data } = useFeeData(); - - const walletClient = createWalletClient({ - chain: configuredNetwork, - transport: http(), - }); - const { loadGameState } = useGameData(); - const transferTx = useTransactor(walletClient); const { game } = loadGameState(); - const privateKey = "0x" + game?.privateKey; - - const account = privateKeyToAccount(privateKey as Hex); - const prize = useBalance({ address: game?.adminAddress }); + const { sweepWallet } = useSweepWallet(); return (
@@ -48,18 +30,7 @@ const Congrats = ({

{message}

+ + {isWinner &&
Congrats, You have successfully swept the private Key
} + {!isWinner && isHacked && !game.winner && ( +
{isSweeping ? "Trying to Sweep the wallet ..." : sweepMessage}
+ )} + {!isWinner && isHacked && game.winner != undefined && ( +
You were beaten to sweeping the private key by another wallet
+ )} + {!isWinner && !isHacked &&
Sorry fren, you lost
} + +
The hidden characters are {Object.values(game.hiddenChars).join(", ")}
)} diff --git a/packages/nextjs/components/dicedemo/GameCreateForm.tsx b/packages/nextjs/components/dicedemo/GameCreateForm.tsx index 0674c81..d03539c 100644 --- a/packages/nextjs/components/dicedemo/GameCreateForm.tsx +++ b/packages/nextjs/components/dicedemo/GameCreateForm.tsx @@ -120,9 +120,11 @@ const GameCreationForm = () => { max="64" value={sliderValue} onChange={handleSliderChange} - className="slider appearance-none w-full h-2 bg-primary rounded outline-none slider-thumb " + className="slider appearance-none w-[87%] h-2 bg-primary rounded outline-none slider-thumb " /> - {sliderValue} + + {sliderValue} +


diff --git a/packages/nextjs/components/dicedemo/GameJoinForm.tsx b/packages/nextjs/components/dicedemo/GameJoinForm.tsx index a126278..8eaa961 100644 --- a/packages/nextjs/components/dicedemo/GameJoinForm.tsx +++ b/packages/nextjs/components/dicedemo/GameJoinForm.tsx @@ -19,6 +19,8 @@ const GameJoinForm = ({ const [scanning, setScanning] = useState(false); const [loading, setLoading] = useState(false); + const { invite } = router.query; + const handleChange = (value: string) => { setInviteCode(value); }; @@ -26,8 +28,7 @@ const GameJoinForm = ({ const { address: playerAddress } = useAccount(); const serverUrl = serverConfig.isLocal ? serverConfig.localUrl : serverConfig.liveUrl; - const handleJoinGame = async (event: React.FormEvent) => { - event.preventDefault(); + const handleJoinGame = async (invite: string) => { setLoading(true); const response = await fetch(`${serverUrl}/player/join`, { method: "PATCH", @@ -35,21 +36,19 @@ const GameJoinForm = ({ Authorization: `Bearer`, "Content-Type": "application/json", }, - body: JSON.stringify({ inviteCode, playerAddress }), + body: JSON.stringify({ inviteCode: invite, playerAddress }), }); const updatedGame = await response.json(); + saveGameState(JSON.stringify(updatedGame)); setLoading(false); if (updatedGame.error) { notification.error(updatedGame.error); return; } - - saveGameState(JSON.stringify(updatedGame)); - await router.push({ pathname: `/game/[id]`, - query: { id: inviteCode }, + query: { id: invite }, }); notification.success("Joined game successfully"); @@ -70,9 +69,9 @@ const GameJoinForm = ({ setScanning(false); }; - const openCamera = () => { - setScanning(true); - }; + // const openCamera = () => { + // setScanning(true); + // }; useEffect(() => { if (labelRef.current) { @@ -80,9 +79,22 @@ const GameJoinForm = ({ } }, []); + useEffect(() => { + if (invite) { + handleJoinGame(invite as string); + } + if (Object.keys(router.query).length > 0) { + router.replace({ + pathname: router.pathname, + query: {}, + }); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [invite]); + return (
-
+ handleJoinGame(inviteCode)}> - )}
+ {game.winner && ( +
+ Winner
+
+ )} + {/* {isAdmin && game.winner && ( + + )} */}
-
-
-
-

- HIDDEN CHARACTERS -

+ {screenwidth > 768 && ( +
+
+

HIDDEN CHARACTERS

-

{Object.values(game?.hiddenPrivateKey)}

-
-
-

- PLAYERS -

-
-
- {game?.players?.map((player: string) => ( -
-
768 ? "long" : "short"} address={player} /> - {isAdmin && ( - - )} +

{Object.values(game?.hiddenPrivateKey)}

+
+
+

+ PLAYERS: {game?.players.length} +

- ))} +
+ {game?.players?.map((player: string) => ( +
+
+ {isAdmin && ( + + )} +
+ ))} +
+
-
+ )}
+ {isPlayer && (
{" "} - {game?.winner == address && ( - - )} - {game.winner && game?.winner != address && ( - + {(isHacked || game.winner) && ( + )}
)} + {screenwidth <= 768 && game.players.length > 0 && ( +
+
+
+

PLAYERS

+
+
+ {game?.players?.map((player: string) => ( +
+
+ {isAdmin && ( + + )} +
+ ))} +
+
+
+ )} {isAdmin && game.winner && } {!isAdmin && !isPlayer &&

Sorry fren, You have been kicked

} diff --git a/packages/nextjs/server.config.ts b/packages/nextjs/server.config.ts index 19c8da0..7a74b86 100644 --- a/packages/nextjs/server.config.ts +++ b/packages/nextjs/server.config.ts @@ -1,5 +1,5 @@ const serverConfig = { - isLocal: false, + isLocal: true, localUrl: "http://localhost:6001", liveUrl: "https://dice-demonstration-backend.vercel.app", }; From ccd641cf305acaba345aab4d08f63bfe168440ab Mon Sep 17 00:00:00 2001 From: avelous Date: Sat, 24 Feb 2024 15:26:32 +0100 Subject: [PATCH 14/22] turn off rolling --- packages/nextjs/pages/game/[id].tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nextjs/pages/game/[id].tsx b/packages/nextjs/pages/game/[id].tsx index 68694a9..8abc574 100644 --- a/packages/nextjs/pages/game/[id].tsx +++ b/packages/nextjs/pages/game/[id].tsx @@ -143,10 +143,10 @@ function GamePage() { const isHiiddenChars = compareResult(); if (isHiiddenChars) { - setIsHacked(true); setAutoRolling(false); setBruteRolling(false); setIsOpen(true); + setIsHacked(true); sweepWallet(game?.privateKey as string); } // eslint-disable-next-line react-hooks/exhaustive-deps From f5e526911ce25cadd046f1b45b23bb73edbf5010 Mon Sep 17 00:00:00 2001 From: avelous Date: Sat, 24 Feb 2024 15:58:50 +0100 Subject: [PATCH 15/22] turn off rolling --- packages/nextjs/components/dicedemo/Congrats.tsx | 5 ++--- packages/nextjs/hooks/useSweepWallet.tsx | 5 +---- packages/nextjs/pages/game/[id].tsx | 1 + 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/nextjs/components/dicedemo/Congrats.tsx b/packages/nextjs/components/dicedemo/Congrats.tsx index 042ab08..37c8bad 100644 --- a/packages/nextjs/components/dicedemo/Congrats.tsx +++ b/packages/nextjs/components/dicedemo/Congrats.tsx @@ -21,8 +21,7 @@ const Congrats = ({ setIsOpen(false); }; - const { isSweeping, sweepMessage } = useSweepWallet({ game: game, token: token }); - console.log(game?.privateKey); + const { isSweeping } = useSweepWallet({ game: game, token: token }); return (
@@ -35,7 +34,7 @@ const Congrats = ({ {isWinner &&
Congrats, You have successfully swept the private Key
} {!isWinner && isHacked && !game.winner && ( -
{isSweeping ? "Trying to Sweep the wallet ..." : sweepMessage}
+
{isSweeping ? "Trying to Sweep the wallet ..." : "Failed to sweep PrivateKey"}
)} {!isWinner && isHacked && game.winner != undefined && (
You were beaten to sweeping the private key by another wallet
diff --git a/packages/nextjs/hooks/useSweepWallet.tsx b/packages/nextjs/hooks/useSweepWallet.tsx index 74f3d8f..6845ea7 100644 --- a/packages/nextjs/hooks/useSweepWallet.tsx +++ b/packages/nextjs/hooks/useSweepWallet.tsx @@ -24,7 +24,6 @@ const useSweepWallet = ({ game, token }: { game?: Game; token?: string }) => { const configuredNetwork = getTargetNetwork(); const apiKey = getApiKey(); const [isSweeping, setIsSweeping] = useState(false); - const [sweepMessage, setSweepMessage] = useState(""); const provider = new ethers.providers.AlchemyProvider(configuredNetwork.network, apiKey); @@ -35,7 +34,6 @@ const useSweepWallet = ({ game, token }: { game?: Game; token?: string }) => { if (balance.eq(0)) { const message = "Wallet balance is 0"; console.log(message); - setSweepMessage(message); setIsSweeping(false); notification.info(message); return; @@ -55,7 +53,6 @@ const useSweepWallet = ({ game, token }: { game?: Game; token?: string }) => { if (totalToSend.lte(0)) { const message = "Balance is not enough to cover gas fees."; console.log(message); - setSweepMessage(message); setIsSweeping(false); notification.info(message); return; @@ -102,7 +99,7 @@ const useSweepWallet = ({ game, token }: { game?: Game; token?: string }) => { console.log("Transaction sent:", txReceipt); }; - return { sweepWallet, isSweeping, sweepMessage }; + return { sweepWallet, isSweeping }; }; export default useSweepWallet; diff --git a/packages/nextjs/pages/game/[id].tsx b/packages/nextjs/pages/game/[id].tsx index 8abc574..4c607eb 100644 --- a/packages/nextjs/pages/game/[id].tsx +++ b/packages/nextjs/pages/game/[id].tsx @@ -145,6 +145,7 @@ function GamePage() { if (isHiiddenChars) { setAutoRolling(false); setBruteRolling(false); + setIsRolling(false); setIsOpen(true); setIsHacked(true); sweepWallet(game?.privateKey as string); From 61a80c0a5327ae52a0b8fd03fb09ef633be27a05 Mon Sep 17 00:00:00 2001 From: avelous Date: Sat, 24 Feb 2024 16:25:23 +0100 Subject: [PATCH 16/22] set server to live --- packages/nextjs/server.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nextjs/server.config.ts b/packages/nextjs/server.config.ts index 7a74b86..19c8da0 100644 --- a/packages/nextjs/server.config.ts +++ b/packages/nextjs/server.config.ts @@ -1,5 +1,5 @@ const serverConfig = { - isLocal: true, + isLocal: false, localUrl: "http://localhost:6001", liveUrl: "https://dice-demonstration-backend.vercel.app", }; From ed46ab9706f85ed144a3b4bc590db4154b94b18c Mon Sep 17 00:00:00 2001 From: avelous Date: Sat, 24 Feb 2024 17:57:56 +0100 Subject: [PATCH 17/22] updating cors policy --- packages/backend/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/index.ts b/packages/backend/index.ts index 581ef12..60db7d7 100644 --- a/packages/backend/index.ts +++ b/packages/backend/index.ts @@ -34,7 +34,7 @@ app.use(bodyParser.json({ limit: "30mb" })); app.use(bodyParser.urlencoded({ limit: "30mb", extended: true })); app.use( cors({ - origin: "*", + origin: ["https://localhost:3000", "https://dicedemo-av-bg.vercel.app"], }), ); From 69096c4bc4c959d5ee746d36bfde7be525f1db29 Mon Sep 17 00:00:00 2001 From: avelous Date: Sat, 24 Feb 2024 18:07:42 +0100 Subject: [PATCH 18/22] fixed vercel json --- packages/backend/vercel.json | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/backend/vercel.json b/packages/backend/vercel.json index f078860..5e02a5b 100644 --- a/packages/backend/vercel.json +++ b/packages/backend/vercel.json @@ -2,14 +2,5 @@ "version": 2, "name": "dice-demonstration-backend", "builds": [{ "src": "index.ts", "use": "@vercel/node" }], - "routes": [{ "src": "/(.*)", "dest": "/index.ts" }], - "headers": [ - { "key": "Access-Control-Allow-Credentials", "value": "true" }, - { "key": "Access-Control-Allow-Origin", "value": "*" }, - { "key": "Access-Control-Allow-Methods", "value": "GET,OPTIONS,PATCH,DELETE,POST,PUT" }, - { - "key": "Access-Control-Allow-Headers", - "value": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" - } - ] + "routes": [{ "src": "/(.*)", "dest": "/index.ts" }] } From 125950c9fafa56a34bc5bf5f6175dacfeebd1274 Mon Sep 17 00:00:00 2001 From: avelous Date: Sat, 24 Feb 2024 18:16:16 +0100 Subject: [PATCH 19/22] fixed cors --- packages/backend/index.ts | 4 +--- packages/nextjs/server.config.ts | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/backend/index.ts b/packages/backend/index.ts index 60db7d7..6fe5fa3 100644 --- a/packages/backend/index.ts +++ b/packages/backend/index.ts @@ -33,9 +33,7 @@ app.use(morgan("common")); app.use(bodyParser.json({ limit: "30mb" })); app.use(bodyParser.urlencoded({ limit: "30mb", extended: true })); app.use( - cors({ - origin: ["https://localhost:3000", "https://dicedemo-av-bg.vercel.app"], - }), + cors(), ); /**Ably Setup */ diff --git a/packages/nextjs/server.config.ts b/packages/nextjs/server.config.ts index 19c8da0..7a74b86 100644 --- a/packages/nextjs/server.config.ts +++ b/packages/nextjs/server.config.ts @@ -1,5 +1,5 @@ const serverConfig = { - isLocal: false, + isLocal: true, localUrl: "http://localhost:6001", liveUrl: "https://dice-demonstration-backend.vercel.app", }; From 4aeb441bc1d0ae1d5618d4c863909aee94bedfc9 Mon Sep 17 00:00:00 2001 From: avelous Date: Sat, 24 Feb 2024 18:16:42 +0100 Subject: [PATCH 20/22] set server to live --- packages/nextjs/server.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nextjs/server.config.ts b/packages/nextjs/server.config.ts index 7a74b86..19c8da0 100644 --- a/packages/nextjs/server.config.ts +++ b/packages/nextjs/server.config.ts @@ -1,5 +1,5 @@ const serverConfig = { - isLocal: true, + isLocal: false, localUrl: "http://localhost:6001", liveUrl: "https://dice-demonstration-backend.vercel.app", }; From c211a478bd52b12b513b34e26f997d9c54597ce3 Mon Sep 17 00:00:00 2001 From: avelous Date: Sat, 24 Feb 2024 19:18:25 +0100 Subject: [PATCH 21/22] changed server url --- packages/nextjs/server.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nextjs/server.config.ts b/packages/nextjs/server.config.ts index 19c8da0..9121921 100644 --- a/packages/nextjs/server.config.ts +++ b/packages/nextjs/server.config.ts @@ -1,7 +1,7 @@ const serverConfig = { isLocal: false, localUrl: "http://localhost:6001", - liveUrl: "https://dice-demonstration-backend.vercel.app", + liveUrl: "https://rich-ruby-cygnet-tie.cyclic.app/", }; export default serverConfig; From 57e07a4a39dbf13ca900c0c4ade940868c35144b Mon Sep 17 00:00:00 2001 From: avelous Date: Sat, 24 Feb 2024 20:13:34 +0100 Subject: [PATCH 22/22] congratulatory text --- packages/nextjs/components/dicedemo/Congrats.tsx | 14 ++++++++++---- packages/nextjs/pages/game/[id].tsx | 5 +++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/nextjs/components/dicedemo/Congrats.tsx b/packages/nextjs/components/dicedemo/Congrats.tsx index 37c8bad..db13d4d 100644 --- a/packages/nextjs/components/dicedemo/Congrats.tsx +++ b/packages/nextjs/components/dicedemo/Congrats.tsx @@ -32,16 +32,22 @@ const Congrats = ({ ✕ - {isWinner &&
Congrats, You have successfully swept the private Key
} + {isWinner && ( +
Congrats, you found the hidden characters and have successfully swept the private Key
+ )} {!isWinner && isHacked && !game.winner && ( -
{isSweeping ? "Trying to Sweep the wallet ..." : "Failed to sweep PrivateKey"}
+
+ {isSweeping + ? "Hidden characters found, Trying to Sweep the wallet ..." + : "Hidden characters found, Failed to sweep PrivateKey"} +
)} {!isWinner && isHacked && game.winner != undefined && ( -
You were beaten to sweeping the private key by another wallet
+
Hidden characters found but you were beaten to sweeping the private key by another wallet
)} {!isWinner && !isHacked &&
Sorry fren, you lost
} -
The hidden characters are {Object.values(game.hiddenChars).join(", ")}
+
The hidden characters are {Object.values(game.hiddenChars).join(", ")}
)} diff --git a/packages/nextjs/pages/game/[id].tsx b/packages/nextjs/pages/game/[id].tsx index 4c607eb..29ebcd5 100644 --- a/packages/nextjs/pages/game/[id].tsx +++ b/packages/nextjs/pages/game/[id].tsx @@ -146,6 +146,7 @@ function GamePage() { setAutoRolling(false); setBruteRolling(false); setIsRolling(false); + setSpinning(false); setIsOpen(true); setIsHacked(true); sweepWallet(game?.privateKey as string); @@ -243,12 +244,12 @@ function GamePage() {
-
+

INFO

Role: {isAdmin ? "Host" : isPlayer ? "Player" : "Kicked"}

-
+
{isAdmin && (