Skip to content

Commit

Permalink
update joingame page
Browse files Browse the repository at this point in the history
  • Loading branch information
arjanjohan committed Apr 25, 2024
1 parent 6076e97 commit ea8655a
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 121 deletions.
53 changes: 1 addition & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,57 +17,6 @@

![Debug Contracts tab](https://github.com/scaffold-eth/scaffold-eth-2/assets/55535804/b237af0c-5027-4849-a5c1-2e31495cccb1)

## Requirements

Before you begin, you need to install the following tools:

- [Node (>= v18.17)](https://nodejs.org/en/download/)
- Yarn ([v1](https://classic.yarnpkg.com/en/docs/install/) or [v2+](https://yarnpkg.com/getting-started/install))
- [Git](https://git-scm.com/downloads)

## Quickstart

To get started with Scaffold-ETH 2, follow the steps below:

1. Clone this repo & install dependencies

```
git clone https://github.com/scaffold-eth/scaffold-eth-2.git
cd scaffold-eth-2
yarn install
```

2. Run a local network in the first terminal:

```
yarn chain
```

This command starts a local Ethereum network using Hardhat. The network runs on your local machine and can be used for testing and development. You can customize the network configuration in `hardhat.config.ts`.

3. On a second terminal, deploy the test contract:

```
yarn deploy
```

This command deploys a test smart contract to the local network. The contract is located in `packages/hardhat/contracts` and can be modified to suit your needs. The `yarn deploy` command uses the deploy script located in `packages/hardhat/deploy` to deploy the contract to the network. You can also customize the deploy script.

4. On a third terminal, start your NextJS app:

```
yarn start
```

Visit your app on: `http://localhost:3000`. You can interact with your smart contract using the `Debug Contracts` page. You can tweak the app config in `packages/nextjs/scaffold.config.ts`.

**What's next**:

- Edit your smart contract `YourContract.sol` in `packages/hardhat/contracts`
- Edit your frontend homepage at `packages/nextjs/app/page.tsx`. For guidance on [routing](https://nextjs.org/docs/app/building-your-application/routing/defining-routes) and configuring [pages/layouts](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts) checkout the Next.js documentation.
- Edit your deployment scripts in `packages/hardhat/deploy`
- Edit your smart contract test in: `packages/hardhat/test`. To run test use `yarn hardhat:test`

## Partner Bounties

### Ankr
Expand Down Expand Up @@ -99,7 +48,7 @@ Create graph to query games

### Verified smart contracts

[ScrollFighter](https://sepolia.scrollscan.com/address/0xD2a3dBEe766c5F77A1cA1368729E27542Ed43790#code)
[ScrollFighter](https://sepolia.scrollscan.com/address/0x4A71867B2739F0976cCC950b643582CA94E6cA28#code)
[FighterCoins](https://sepolia.scrollscan.com/address/0x64CDeB6CD5ecfB002bdaFabc98B5C883C5C06B27#code)
[UltraVerifier](https://sepolia.scrollscan.com/address/0xc15BC025d57bec9FA39e18701b4f0b3b5a067B6C#code)

Expand Down
8 changes: 5 additions & 3 deletions packages/hardhat/contracts/ScrollFighter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,17 @@ contract ScrollFighter {
_opponent != address(0) && _opponent != msg.sender,
"Invalid opponent address"
);
// add 18 decimals
uint amount = _amount * 10 ** 18;
require(
fightingTokens.transferFrom(msg.sender, address(this), _amount),
fightingTokens.transferFrom(msg.sender, address(this), amount),
"Transfer failed"
);

uint gameId = nextGameId++;
games[gameId] = Game({
id: gameId,
wageredAmount: _amount,
wageredAmount: amount,
players: [msg.sender, _opponent],
challengerCommitment: hashCommitment,
fighterIds: [uint(0), uint(0)],
Expand All @@ -114,7 +116,7 @@ contract ScrollFighter {
winner: address(0),
lastActionBlock: block.number
});
emit GameProposed(gameId, msg.sender, _opponent, _amount);
emit GameProposed(gameId, msg.sender, _opponent, amount);
}

function acceptGame(
Expand Down
15 changes: 3 additions & 12 deletions packages/nextjs/app/join/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// import { useState } from "react";
import { SelectGame } from "../../components/SelectGame";
// import { SelectGame } from "../../components/SelectGame";
import { GameForm } from "../../components/GameForm";
import type { NextPage } from "next";
// import { useReadContract } from "wagmi";
// Ensure this is appropriate for your version of wagmi
Expand All @@ -14,17 +15,7 @@ export const metadata = getMetadata({
const Join: NextPage = () => {
return (
<>
<SelectGame />
{/* <div className="text-center mt-8 bg-secondary p-10">
<h1 className="text-4xl my-0">Debug Contracts</h1>
<p className="text-neutral">
You can debug & interact with your deployed contracts here.
<br /> Check{" "}
<code className="italic bg-base-300 text-base font-bold [word-spacing:-0.5rem] px-1">
packages / nextjs / app / debug / page.tsx
</code>{" "}
</p>
</div> */}
<GameForm mode="join" />
</>
);
};
Expand Down
27 changes: 15 additions & 12 deletions packages/nextjs/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,21 @@ const Home: NextPage = () => {
<div className="px-5">
<h1 className="text-center">
<span className="block text-2xl mb-2">Welcome to</span>
<span className="block text-4xl font-bold">Scaffold-ETH 2</span>
<span className="block text-4xl font-bold">Scroll Fighter</span>
</h1>
<div className="flex justify-center items-center space-x-2">
<p className="my-2 font-medium">Connected Address:</p>
<Address address={connectedAddress} />
</div>
<p className="text-center text-lg">
Get started by editing{" "}
<code className="italic bg-base-300 text-base font-bold max-w-full break-words break-all inline-block">
packages/nextjs/app/page.tsx
</code>
<p>
<img
src="/logo.png"
// alt={fighters[0].name}
// style={{ height: "200px" }}
/>
</p>
<br></br>
<p className="text-center text-lg">Fighting is finally on-chain!</p>
<p className="text-center text-lg">
Edit your smart contract{" "}
<code className="italic bg-base-300 text-base font-bold max-w-full break-words break-all inline-block">
Expand All @@ -44,19 +47,19 @@ const Home: NextPage = () => {
<div className="flex flex-col bg-base-100 px-10 py-10 text-center items-center max-w-xs rounded-3xl">
<BugAntIcon className="h-8 w-8 fill-secondary" />
<p>
Tinker with your smart contract using the{" "}
<Link href="/debug" passHref className="link">
Debug Contracts
Start a fight using the{" "}
<Link href="/create" passHref className="link">
Create game
</Link>{" "}
tab.
</p>
</div>
<div className="flex flex-col bg-base-100 px-10 py-10 text-center items-center max-w-xs rounded-3xl">
<MagnifyingGlassIcon className="h-8 w-8 fill-secondary" />
<p>
Explore your local transactions with the{" "}
<Link href="/blockexplorer" passHref className="link">
Block Explorer
Check out previous games on the the{" "}
<Link href="/results" passHref className="link">
Results
</Link>{" "}
tab.
</p>
Expand Down
37 changes: 7 additions & 30 deletions packages/nextjs/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import React from "react";
import Link from "next/link";
import { hardhat } from "viem/chains";
import { CurrencyDollarIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
import { HeartIcon } from "@heroicons/react/24/outline";
import { SwitchTheme } from "~~/components/SwitchTheme";
import { BuidlGuidlLogo } from "~~/components/assets/BuidlGuidlLogo";
import { Faucet } from "~~/components/scaffold-eth";
import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork";
import { useGlobalState } from "~~/services/store/store";

/**
* Site footer
*/
export const Footer = () => {
const nativeCurrencyPrice = useGlobalState(state => state.nativeCurrencyPrice);
const { targetNetwork } = useTargetNetwork();
const isLocalNetwork = targetNetwork.id === hardhat.id;

Expand All @@ -22,23 +16,7 @@ export const Footer = () => {
<div>
<div className="fixed flex justify-between items-center w-full z-10 p-4 bottom-0 left-0 pointer-events-none">
<div className="flex flex-col md:flex-row gap-2 pointer-events-auto">
{nativeCurrencyPrice > 0 && (
<div>
<div className="btn btn-primary btn-sm font-normal gap-1 cursor-auto">
<CurrencyDollarIcon className="h-4 w-4" />
<span>{nativeCurrencyPrice}</span>
</div>
</div>
)}
{isLocalNetwork && (
<>
<Faucet />
<Link href="/blockexplorer" passHref className="btn btn-primary btn-sm font-normal gap-1">
<MagnifyingGlassIcon className="h-4 w-4" />
<span>Block Explorer</span>
</Link>
</>
)}
{/* empty div so the SwitchTheme will be on the right */}
</div>
<SwitchTheme className={`pointer-events-auto ${isLocalNetwork ? "self-end md:self-auto" : ""}`} />
</div>
Expand All @@ -47,29 +25,28 @@ export const Footer = () => {
<ul className="menu menu-horizontal w-full">
<div className="flex justify-center items-center gap-2 text-sm w-full">
<div className="text-center">
<a href="https://github.com/scaffold-eth/se-2" target="_blank" rel="noreferrer" className="link">
<a href="https://github.com/arjanjohan/scroll-fighter" target="_blank" rel="noreferrer" className="link">
Fork me
</a>
</div>
<span>·</span>
<div className="flex justify-center items-center gap-2">
<p className="m-0 text-center">
Built with <HeartIcon className="inline-block h-4 w-4" /> at
Built with <HeartIcon className="inline-block h-4 w-4" /> during
</p>
<a
className="flex justify-center items-center gap-1"
href="https://buidlguidl.com/"
href="https://dorahacks.io/hackathon/v0rtex-01/detail"
target="_blank"
rel="noreferrer"
>
<BuidlGuidlLogo className="w-3 h-5 pb-1" />
<span className="link">BuidlGuidl</span>
<span className="link">Scroll VORTEx 1</span>
</a>
</div>
<span>·</span>
<div className="text-center">
<a href="https://t.me/joinchat/KByvmRe5wkR-8F_zz6AjpA" target="_blank" rel="noreferrer" className="link">
Support
<a href="https://twitter.com/arjanjohan" target="_blank" rel="noreferrer" className="link">
Twitter
</a>
</div>
</div>
Expand Down
72 changes: 60 additions & 12 deletions packages/nextjs/components/GameForm.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
"use client";

// GameForm.tsx
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { Fighter, fighters } from "./Fighters";
import { formatUnits } from "viem";
import { useAccount, useBalance, useWriteContract } from "wagmi";
// import { isAddress } from "web3-validator";
import { useAccount, useBalance, useReadContract, useWriteContract } from "wagmi";
import { useDeployedContractInfo } from "~~/hooks/scaffold-eth";
import { useTransactor } from "~~/hooks/scaffold-eth";
import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork";
Expand All @@ -24,7 +23,7 @@ type Move = (typeof moves)[number];
export const GameForm = ({ mode, initialOpponentAddress, initialAmount }: GameFormProps) => {
const writeTxn = useTransactor();

const [amount, setAmount] = useState<string>(initialAmount || "0");
const [amount, setAmount] = useState<string>(initialAmount || "");
const [opponent, setOpponent] = useState<string>(initialOpponentAddress || "");
const { address, chain } = useAccount();
const contractName = "ScrollFighter";
Expand All @@ -34,7 +33,8 @@ export const GameForm = ({ mode, initialOpponentAddress, initialAmount }: GameFo
const ethBalance = useBalance({ address: address, token: tokenContractAddress }) || 0;
const data = ethBalance.data;
const formattedEthBalance = formatUnits(BigInt(data?.value ?? 0), data?.decimals ?? 18);

// const [gameLoaded, setGameLoaded] = useState<boolean>(false);
const [gameId, setGameId] = useState<string>("");
const [selectedFighter, setSelectedFighter] = useState<Fighter | null>(null);
const [selectedMoves, setSelectedMoves] = useState<Move[]>(["Attack", "Attack", "Attack"]);
const [specialMoveUsed, setSpecialMoveUsed] = useState(false);
Expand Down Expand Up @@ -80,6 +80,27 @@ export const GameForm = ({ mode, initialOpponentAddress, initialAmount }: GameFo
setSelectedFighter(fighter);
};

// Use to fetch game details
const { data: gameData, isLoading: isGameLoading } = useReadContract({
address: deployedContractData?.address || "",
abi: deployedContractData?.abi || [],
functionName: "getGame",
args: [BigInt(gameId)],
});

useEffect(() => {
if (gameData && !isGameLoading) {
setOpponent(gameData.players[0]);
setAmount(formatUnits(BigInt(gameData.wageredAmount), 18));
// setGameLoaded(true);
}
}, [gameData, isGameLoading]);

const handleGameIdChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setGameId(e.target.value);
// setGameLoaded(false); // Reset load state when game ID changes
};

const proposeGame = async () => {
if (writeContractAsync) {
if (!deployedContractData?.abi || !deployedContractData?.address) {
Expand All @@ -105,19 +126,37 @@ export const GameForm = ({ mode, initialOpponentAddress, initialAmount }: GameFo
};

const joinGame = async () => {
// Assuming there's a similar function in your contract for joining a game
if (!deployedContractData?.abi || !deployedContractData?.address) {
console.error("Contract data is not loaded.");
return;
}

if (!selectedFighter) {
console.error("No fighter selected");
return;
}

try {
// await writeContract({
// abi: deployedContractData.abi,
// address: deployedContractData.address,
// functionName: "joinGame",
// args: [opponent, amount], // Your contract's joinGame function might require different parameters.
// });
// Ensure moveIndices always has three elements, each converted to BigInt
const moveIndices = selectedMoves.map(move => BigInt(moves.indexOf(move)));
if (moveIndices.length !== 3) {
console.error("Invalid number of moves selected");
return;
}

// Convert all parts to BigInt for Solidity compatibility
const gameIdBigInt = BigInt(gameId);
const fighterIdBigInt = BigInt(selectedFighter.id);

const makeWriteWithParams = () =>
writeContractAsync({
address: deployedContractData.address,
functionName: "acceptGame",
abi: deployedContractData.abi,
args: [gameIdBigInt, fighterIdBigInt, moveIndices as [bigint, bigint, bigint]], // Cast as a tuple
});

await writeTxn(makeWriteWithParams);
console.log("Game joined successfully!");
} catch (error) {
console.error("Failed to join game:", error);
Expand All @@ -137,12 +176,20 @@ export const GameForm = ({ mode, initialOpponentAddress, initialAmount }: GameFo
</div>
<div className="p-5 divide-y divide-base-300">
<h1 className="text-xl font-bold">Game Setup</h1>
<input
type="text"
placeholder="Enter Game ID to Load"
value={gameId}
onChange={handleGameIdChange}
className="input input-bordered w-full max-w-xs"
/>
<label className="block">
Opponent Address:
<input
type="text"
value={opponent}
onChange={e => setOpponent(e.target.value)}
readOnly={mode === "join"}
className="input input-bordered w-full"
placeholder="Enter ERC20 address"
/>
Expand All @@ -155,6 +202,7 @@ export const GameForm = ({ mode, initialOpponentAddress, initialAmount }: GameFo
max={formattedEthBalance.toString()}
value={amount}
onChange={e => setAmount(e.target.value)}
readOnly={mode === "join"}
className="range range-primary w-full"
/>
<div className="flex justify-between">
Expand Down
Loading

0 comments on commit ea8655a

Please sign in to comment.