bet creation
This commit is contained in:
parent
ac8cc4db9e
commit
98d6c3bd80
124
package-lock.json
generated
124
package-lock.json
generated
|
|
@ -8,6 +8,7 @@
|
||||||
"name": "duelfi",
|
"name": "duelfi",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@coral-xyz/anchor": "^0.31.0",
|
||||||
"@fontsource/manrope": "^5.2.5",
|
"@fontsource/manrope": "^5.2.5",
|
||||||
"@privy-io/react-auth": "^2.7.2",
|
"@privy-io/react-auth": "^2.7.2",
|
||||||
"@solana/web3.js": "^1.98.0",
|
"@solana/web3.js": "^1.98.0",
|
||||||
|
|
@ -19,6 +20,7 @@
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-toastify": "^11.0.5",
|
"react-toastify": "^11.0.5",
|
||||||
|
"sonner": "^2.0.3",
|
||||||
"viem": "^2.24.2"
|
"viem": "^2.24.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -76,6 +78,97 @@
|
||||||
"preact": "^10.24.2"
|
"preact": "^10.24.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@coral-xyz/anchor": {
|
||||||
|
"version": "0.31.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.31.0.tgz",
|
||||||
|
"integrity": "sha512-Yb1NwP1s4cWhAw7wL7vOLHSWWw3cD5D9pRCVSeJpdqPaI+w7sfRLScnVJL6ViYMZynB7nAG/5HcUPKUnY0L9rw==",
|
||||||
|
"license": "(MIT OR Apache-2.0)",
|
||||||
|
"dependencies": {
|
||||||
|
"@coral-xyz/anchor-errors": "^0.31.0",
|
||||||
|
"@coral-xyz/borsh": "^0.31.0",
|
||||||
|
"@noble/hashes": "^1.3.1",
|
||||||
|
"@solana/web3.js": "^1.69.0",
|
||||||
|
"bn.js": "^5.1.2",
|
||||||
|
"bs58": "^4.0.1",
|
||||||
|
"buffer-layout": "^1.2.2",
|
||||||
|
"camelcase": "^6.3.0",
|
||||||
|
"cross-fetch": "^3.1.5",
|
||||||
|
"eventemitter3": "^4.0.7",
|
||||||
|
"pako": "^2.0.3",
|
||||||
|
"superstruct": "^0.15.4",
|
||||||
|
"toml": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@coral-xyz/anchor-errors": {
|
||||||
|
"version": "0.31.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.31.0.tgz",
|
||||||
|
"integrity": "sha512-SUERksFSQ+4F11hkROIwHq4mcoSMXJxwVWLoklefi4dU679zVWFVcTq6O7otvjY8wlUaRXeE+iYcQWZTw2ll6w==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@coral-xyz/anchor/node_modules/base-x": {
|
||||||
|
"version": "3.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz",
|
||||||
|
"integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@coral-xyz/anchor/node_modules/bs58": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base-x": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@coral-xyz/anchor/node_modules/camelcase": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@coral-xyz/anchor/node_modules/eventemitter3": {
|
||||||
|
"version": "4.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||||
|
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@coral-xyz/anchor/node_modules/superstruct": {
|
||||||
|
"version": "0.15.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz",
|
||||||
|
"integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@coral-xyz/borsh": {
|
||||||
|
"version": "0.31.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.31.0.tgz",
|
||||||
|
"integrity": "sha512-DwdQ5fuj+rGQCTKRnxnW1W2lvcpBaFc9m9M1TcGGlm+bwCcggmDgbLKLgF+LjIrKnc7Nd+bCACx5RA9YTK2I4Q==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"bn.js": "^5.1.2",
|
||||||
|
"buffer-layout": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@solana/web3.js": "^1.69.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@emnapi/core": {
|
"node_modules/@emnapi/core": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.3.1.tgz",
|
||||||
|
|
@ -4269,6 +4362,15 @@
|
||||||
"ieee754": "^1.2.1"
|
"ieee754": "^1.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer-layout": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/bufferutil": {
|
"node_modules/bufferutil": {
|
||||||
"version": "4.0.9",
|
"version": "4.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz",
|
||||||
|
|
@ -8023,6 +8125,12 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pako": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
|
||||||
|
"license": "(MIT AND Zlib)"
|
||||||
|
},
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
|
|
@ -9023,6 +9131,16 @@
|
||||||
"atomic-sleep": "^1.0.0"
|
"atomic-sleep": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sonner": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-njQ4Hht92m0sMqqHVDL32V2Oun9W1+PHO9NDv9FHfJjT3JT22IG4Jpo3FPQy+mouRKCXFWO+r67v6MrHX2zeIA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
|
|
@ -9508,6 +9626,12 @@
|
||||||
"node": ">=8.0"
|
"node": ">=8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/toml": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/tr46": {
|
"node_modules/tr46": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@coral-xyz/anchor": "^0.31.0",
|
||||||
"@fontsource/manrope": "^5.2.5",
|
"@fontsource/manrope": "^5.2.5",
|
||||||
"@privy-io/react-auth": "^2.7.2",
|
"@privy-io/react-auth": "^2.7.2",
|
||||||
"@solana/web3.js": "^1.98.0",
|
"@solana/web3.js": "^1.98.0",
|
||||||
|
|
@ -20,6 +21,7 @@
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-toastify": "^11.0.5",
|
"react-toastify": "^11.0.5",
|
||||||
|
"sonner": "^2.0.3",
|
||||||
"viem": "^2.24.2"
|
"viem": "^2.24.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
import Footer from "@/components/Footer";
|
import Footer from "@/components/Footer";
|
||||||
import Header from "@/components/Header";
|
import Header from "@/components/Header";
|
||||||
import HeroSection from "@/components/Home";
|
import HeroSection from "@/components/HeroSection";
|
||||||
import { PrivyProvider } from "@privy-io/react-auth";
|
import { PrivyProvider } from "@privy-io/react-auth";
|
||||||
import { toSolanaWalletConnectors } from "@privy-io/react-auth/solana";
|
import { toSolanaWalletConnectors } from "@privy-io/react-auth/solana";
|
||||||
|
import { Toaster } from "sonner";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -30,6 +31,7 @@ export default function Home() {
|
||||||
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Toaster position="top-right" richColors />
|
||||||
<Header/>
|
<Header/>
|
||||||
<HeroSection/>
|
<HeroSection/>
|
||||||
<Footer/>
|
<Footer/>
|
||||||
|
|
|
||||||
137
src/components/GameModal.tsx
Normal file
137
src/components/GameModal.tsx
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { ConnectedSolanaWallet, usePrivy, useSolanaWallets } from "@privy-io/react-auth";
|
||||||
|
import { Connection, PublicKey } from "@solana/web3.js";
|
||||||
|
import { AnchorProvider, Program, BN } from "@coral-xyz/anchor";
|
||||||
|
import idl from "../idl/bets_idl.json"; // Ensure this is the correct IDL path
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import { Bets } from "@/idl/bets";
|
||||||
|
import { Game, games } from "../data/games"; // Assuming you have a games data file
|
||||||
|
import { PriceSelection } from "./PriceSelection";
|
||||||
|
import { GameSelection } from "./GameSelection";
|
||||||
|
import { CLUSTER_URL } from "@/data/shared";
|
||||||
|
|
||||||
|
const PROGRAM_ID = new PublicKey("HxsDuhD7wcPxcMsrYdteMYxkffuwff8HoxhZ7NuFtM37");
|
||||||
|
// Change to Mainnet when deploying
|
||||||
|
|
||||||
|
interface GameModalProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function GameModal({ isOpen, onClose }: GameModalProps) {
|
||||||
|
const { wallets } = useSolanaWallets();
|
||||||
|
const { authenticated } = usePrivy();
|
||||||
|
|
||||||
|
const [program, setProgram] = useState<Program<Bets>>();
|
||||||
|
const [solanaWallet, setSolanaWallet] = useState<ConnectedSolanaWallet>();
|
||||||
|
|
||||||
|
const [selectedGame, setSelectedGame] = useState<Game | null>(null);
|
||||||
|
const [selectedPrice, setSelectedPrice] = useState<number | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (wallets.length > 0) {
|
||||||
|
const solWallet = wallets[0];
|
||||||
|
setSolanaWallet(solWallet);
|
||||||
|
|
||||||
|
const connection = new Connection(CLUSTER_URL, "confirmed");
|
||||||
|
const wallet = {
|
||||||
|
publicKey: new PublicKey(solWallet.address),
|
||||||
|
signTransaction: solWallet.signTransaction,
|
||||||
|
signAllTransactions: solWallet.signAllTransactions,
|
||||||
|
};
|
||||||
|
|
||||||
|
const provider = new AnchorProvider(connection, wallet, {
|
||||||
|
preflightCommitment: "processed",
|
||||||
|
});
|
||||||
|
|
||||||
|
const programInstance = new Program<Bets>(idl, provider);
|
||||||
|
setProgram(programInstance);
|
||||||
|
}
|
||||||
|
}, [wallets]);
|
||||||
|
|
||||||
|
const handleCreateGame = async () => {
|
||||||
|
|
||||||
|
if (!authenticated) {
|
||||||
|
toast.error("Please log in with Privy.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wallet = solanaWallet; // Get connected Privy wallet
|
||||||
|
if (!wallet) {
|
||||||
|
toast.error("Please connect your wallet.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selectedGame || selectedPrice === null) {
|
||||||
|
toast.error("Please select a game and a price.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!program) {
|
||||||
|
toast.error("Solana program not initialized.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const nonce = 1;
|
||||||
|
const [bet_list_pda] = await PublicKey.findProgramAddress(
|
||||||
|
[Buffer.from("bets_list")],
|
||||||
|
program.programId
|
||||||
|
);
|
||||||
|
const connection = new Connection(CLUSTER_URL, "confirmed");
|
||||||
|
|
||||||
|
console.log(`bets list : ${bet_list_pda}`);
|
||||||
|
|
||||||
|
// Create transaction
|
||||||
|
const tx = await program.methods
|
||||||
|
.createBet(new BN(selectedPrice * 1000000000), selectedGame.id, new BN(nonce))
|
||||||
|
.accounts({
|
||||||
|
betsList: bet_list_pda,
|
||||||
|
})
|
||||||
|
.transaction(); // Get transaction object instead of RPC call
|
||||||
|
|
||||||
|
tx.feePayer = new PublicKey(wallet.address);
|
||||||
|
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
|
||||||
|
|
||||||
|
// Sign transaction with Privy
|
||||||
|
const signedTx = await wallet.signTransaction(tx);
|
||||||
|
|
||||||
|
// Send transaction// Replace with correct RPC endpoint
|
||||||
|
const txId = await connection.sendRawTransaction(signedTx.serialize());
|
||||||
|
|
||||||
|
toast.success(`Bet created successfully! TX: ${txId}`);
|
||||||
|
console.log(`Transaction ID: ${txId}`);
|
||||||
|
onClose();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error creating bet:", error);
|
||||||
|
toast.error("Failed to create bet.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!isOpen) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 bg-black/70 flex justify-center items-start pt-10 z-50" onClick={onClose}>
|
||||||
|
<div
|
||||||
|
className="bg-[rgb(30,30,30)] text-white w-full max-w-lg p-6 rounded-2xl shadow-lg"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<h2 className="text-xl font-bold mb-4">Create Game</h2>
|
||||||
|
|
||||||
|
{/* Game Selection */}
|
||||||
|
<GameSelection games={games} selectedGame={selectedGame} onSelect={setSelectedGame} />
|
||||||
|
|
||||||
|
{/* Price Selection */}
|
||||||
|
<PriceSelection selectedPrice={selectedPrice} onSelect={setSelectedPrice} />
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="mt-6 w-full py-2 rounded-xl font-semibold bg-[rgb(248,144,22)] text-black hover:bg-white hover:scale-105"
|
||||||
|
onClick={handleCreateGame}
|
||||||
|
>
|
||||||
|
Confirm & Create Bet
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
33
src/components/GameSelection.tsx
Normal file
33
src/components/GameSelection.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import Image from "next/image";
|
||||||
|
import { Game } from "../data/games";
|
||||||
|
|
||||||
|
interface GameSelectionProps {
|
||||||
|
games: Game[];
|
||||||
|
selectedGame: Game | null;
|
||||||
|
onSelect: (game: Game) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GameSelection({ games, selectedGame, onSelect }: GameSelectionProps) {
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-3 gap-4 mb-6">
|
||||||
|
{games.map((game) => (
|
||||||
|
<div
|
||||||
|
key={game.id}
|
||||||
|
className={`p-4 cursor-pointer rounded-xl border-2 transition-transform duration-300
|
||||||
|
${selectedGame?.id === game.id ? "scale-110 border-gray-400 bg-gray-800" : "border-gray-600 bg-[rgb(10,10,10)]"}
|
||||||
|
hover:scale-105 hover:border-gray-400`}
|
||||||
|
onClick={() => onSelect(game)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={game.thumbnail}
|
||||||
|
alt={game.name}
|
||||||
|
width={100}
|
||||||
|
height={100}
|
||||||
|
className="mb-2 rounded-md"
|
||||||
|
/>
|
||||||
|
<h3 className="text-center text-sm">{game.name}</h3>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
67
src/components/HeroSection.tsx
Normal file
67
src/components/HeroSection.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import OpenGames from "./OpenGames";
|
||||||
|
import { Game, games } from "../data/games";
|
||||||
|
import GameModal from "./GameModal";
|
||||||
|
import { HowItWorksModal } from "./HowItWorksModal";
|
||||||
|
import YourGames from "./YourGames";
|
||||||
|
|
||||||
|
export default function HeroSection() {
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const [isGameModalOpen, setIsGameModalOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<section className="flex flex-col items-center text-center py-16">
|
||||||
|
<Image
|
||||||
|
src="/duelfiassets/Playing on Arcade Machine no BG.png"
|
||||||
|
alt="DuelFi Hero"
|
||||||
|
width={150}
|
||||||
|
height={50}
|
||||||
|
className="mb-6"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<h1 className="text-4xl font-bold text-white">
|
||||||
|
Instant <span className="text-[rgb(248,144,22)]">Duels</span>, Instant{" "}
|
||||||
|
<span className="text-[rgb(248,144,22)]">Wins</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="mt-12 px-12 py-4 bg-[rgb(248,144,22)] hover:bg-white text-black text-sm font-semibold rounded-xl flex items-center gap-2 transition duration-300 hover:scale-110"
|
||||||
|
onClick={() => setIsGameModalOpen(true)}
|
||||||
|
>
|
||||||
|
Create a Game
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className="w-5 h-5"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M7 7h10v10" />
|
||||||
|
<path d="M7 17 17 7" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<p
|
||||||
|
className="mt-4 text-gray-400 cursor-pointer hover:underline font-mono"
|
||||||
|
onClick={() => setIsModalOpen(true)}
|
||||||
|
>
|
||||||
|
How it works?..
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<YourGames />
|
||||||
|
<OpenGames />
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<GameModal isOpen={isGameModalOpen} onClose={() => setIsGameModalOpen(false)} />
|
||||||
|
<HowItWorksModal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ import { usePrivy } from "@privy-io/react-auth";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
export default function HeroSection() {
|
export default function HeroSection() {
|
||||||
const { ready, authenticated } = usePrivy();
|
const { authenticated } = usePrivy();
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const [isGameModalOpen, setIsGameModalOpen] = useState(false);
|
const [isGameModalOpen, setIsGameModalOpen] = useState(false);
|
||||||
const [selectedGame, setSelectedGame] = useState<Game | null>(null);
|
const [selectedGame, setSelectedGame] = useState<Game | null>(null);
|
||||||
|
|
|
||||||
41
src/components/HowItWorksModal.tsx
Normal file
41
src/components/HowItWorksModal.tsx
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
interface HowItWorksModalProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function HowItWorksModal({ isOpen, onClose }: HowItWorksModalProps) {
|
||||||
|
if (!isOpen) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 bg-black/70 flex justify-center items-start pt-10 z-50" onClick={onClose}>
|
||||||
|
<div
|
||||||
|
className="bg-[rgb(30,30,30)] text-white w-full max-w-lg p-6 rounded-2xl shadow-lg transform transition-transform duration-300 animate-slide-down"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<h2 className="text-xl font-bold mb-4">How It Works</h2>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
{[
|
||||||
|
{ step: "Connect Your Wallet", desc: "Start by linking your wallet securely." },
|
||||||
|
{ step: "Create or Join Game", desc: "Pick a game and set a wager, or join an existing match." },
|
||||||
|
{ step: "Place Your Bet", desc: "Confirm your wager and get ready to play." },
|
||||||
|
{ step: "Claim Your Winnings", desc: "Win the game and collect your rewards instantly!" },
|
||||||
|
].map(({ step, desc }, index) => (
|
||||||
|
<div key={index}>
|
||||||
|
<h3 className="text-[rgb(248,144,22)] font-bold text-lg">{index + 1}. {step}</h3>
|
||||||
|
<p className="text-xs text-gray-400 font-mono">{desc}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="mt-6 w-full bg-[rgb(248,144,22)] text-black font-semibold py-2 rounded-xl transition hover:bg-white hover:scale-105"
|
||||||
|
onClick={onClose}
|
||||||
|
>
|
||||||
|
Okay
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -30,7 +30,7 @@ export default function OpenGames() {
|
||||||
{/* Game Info - Left Aligned */}
|
{/* Game Info - Left Aligned */}
|
||||||
<div className="mt-4 px-3 text-left">
|
<div className="mt-4 px-3 text-left">
|
||||||
<h3 className="text-lg font-semibold text-white py-2">{game.name}</h3>
|
<h3 className="text-lg font-semibold text-white py-2">{game.name}</h3>
|
||||||
<p className="text-xs text-gray-400 font-mono py-1">Entry Fee</p>
|
<p className="text-xs text-gray-400 font-mono py-1">Wager</p>
|
||||||
<p className="text-xs text-white font-mono py-1">{game.entryFee}</p>
|
<p className="text-xs text-white font-mono py-1">{game.entryFee}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
32
src/components/PriceSelection.tsx
Normal file
32
src/components/PriceSelection.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
interface PriceSelectionProps {
|
||||||
|
selectedPrice: number | null;
|
||||||
|
onSelect: (price: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PriceSelection({ selectedPrice, onSelect }: PriceSelectionProps) {
|
||||||
|
const prices = [0.2, 0.5, 0.8];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-6 space-y-2">
|
||||||
|
{prices.map((price) => (
|
||||||
|
<p
|
||||||
|
key={price}
|
||||||
|
className={`flex items-center gap-2 text-gray-400 font-mono cursor-pointer transition-transform duration-500
|
||||||
|
${selectedPrice === price ? "text-white translate-x-2" : ""}`}
|
||||||
|
onClick={() => onSelect(price)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/duelfiassets/solana logo.png"
|
||||||
|
alt="SOL"
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
className="inline"
|
||||||
|
/>
|
||||||
|
{price} SOL
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ import { usePrivy, useSolanaWallets } from "@privy-io/react-auth";
|
||||||
import { Connection, PublicKey } from "@solana/web3.js"; // Solana Web3.js imports
|
import { Connection, PublicKey } from "@solana/web3.js"; // Solana Web3.js imports
|
||||||
import { toast, ToastContainer } from "react-toastify";
|
import { toast, ToastContainer } from "react-toastify";
|
||||||
import "react-toastify/dist/ReactToastify.css";
|
import "react-toastify/dist/ReactToastify.css";
|
||||||
|
import { CLUSTER_URL } from "@/data/shared";
|
||||||
|
|
||||||
export default function PrivyButton() {
|
export default function PrivyButton() {
|
||||||
const { login, logout, user } = usePrivy();
|
const { login, logout, user } = usePrivy();
|
||||||
|
|
@ -14,29 +15,30 @@ export default function PrivyButton() {
|
||||||
const [solBalance, setSolBalance] = useState("--");
|
const [solBalance, setSolBalance] = useState("--");
|
||||||
const modalRef = useRef<HTMLDivElement>(null);
|
const modalRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
const fetchSolBalance = async () => {
|
||||||
const fetchSolBalance = async () => {
|
|
||||||
|
|
||||||
wallets.forEach((wallet)=>{
|
wallets.forEach((wallet)=>{
|
||||||
console.log(wallet.address + " : " + wallet.type);
|
console.log(wallet.address + " : " + wallet.type);
|
||||||
if(wallet.type == "solana"){
|
if(wallet.type == "solana"){
|
||||||
setSolWallet(wallet.address);
|
setSolWallet(wallet.address);
|
||||||
}
|
|
||||||
})
|
|
||||||
if (solWallet!="") {
|
|
||||||
const walletAddress = solWallet; // Access the Solana wallet address
|
|
||||||
try {
|
|
||||||
const connection = new Connection("https://api.devnet.solana.com", "confirmed");
|
|
||||||
const publicKey = new PublicKey(walletAddress);
|
|
||||||
|
|
||||||
const balance = await connection.getBalance(publicKey);
|
|
||||||
setSolBalance((balance / 1e9).toFixed(2)); // Convert lamports to SOL (1 SOL = 1e9 lamports)
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to get balance:", error);
|
|
||||||
setSolBalance("Error");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
})
|
||||||
|
if (solWallet!="") {
|
||||||
|
const walletAddress = solWallet; // Access the Solana wallet address
|
||||||
|
try {
|
||||||
|
const connection = new Connection(CLUSTER_URL, "confirmed");
|
||||||
|
const publicKey = new PublicKey(walletAddress);
|
||||||
|
|
||||||
|
const balance = await connection.getBalance(publicKey);
|
||||||
|
setSolBalance((balance / 1e9).toFixed(2)); // Convert lamports to SOL (1 SOL = 1e9 lamports)
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to get balance:", error);
|
||||||
|
setSolBalance("Error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
|
||||||
if (wallets) {
|
if (wallets) {
|
||||||
fetchSolBalance();
|
fetchSolBalance();
|
||||||
|
|
@ -76,7 +78,7 @@ export default function PrivyButton() {
|
||||||
<>
|
<>
|
||||||
{user ? (
|
{user ? (
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsModalOpen(true)}
|
onClick={() =>{setIsModalOpen(true); fetchSolBalance();}}
|
||||||
className="bg-[rgb(248,144,22)] hover:bg-[rgb(248,200,100)] text-black px-6 py-3 rounded-md transition duration-300 hover:scale-105"
|
className="bg-[rgb(248,144,22)] hover:bg-[rgb(248,200,100)] text-black px-6 py-3 rounded-md transition duration-300 hover:scale-105"
|
||||||
>
|
>
|
||||||
<span className="font-bold">Connected</span>
|
<span className="font-bold">Connected</span>
|
||||||
|
|
|
||||||
126
src/components/YourGames.tsx
Normal file
126
src/components/YourGames.tsx
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
"use client";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { games } from "../data/games";
|
||||||
|
import { Connection, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
|
||||||
|
import { AnchorProvider, Program } from "@coral-xyz/anchor";
|
||||||
|
import { CLUSTER_URL } from "../data/shared";
|
||||||
|
import { Bets } from "../idl/bets";
|
||||||
|
import { FiTrash } from "react-icons/fi";
|
||||||
|
import idl from "../idl/bets_idl.json";
|
||||||
|
import { useSolanaWallets } from "@privy-io/react-auth";
|
||||||
|
|
||||||
|
export default function YourGames() {
|
||||||
|
const { wallets, ready } = useSolanaWallets();
|
||||||
|
const [openBets, setOpenBets] = useState<any[]>([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
// Function to fetch open bets
|
||||||
|
const fetchOpenBets = async () => {
|
||||||
|
try {
|
||||||
|
if (!wallets[0]) return;
|
||||||
|
|
||||||
|
const connection = new Connection(CLUSTER_URL);
|
||||||
|
const wallet = {
|
||||||
|
publicKey: new PublicKey(wallets[0].address),
|
||||||
|
signTransaction: wallets[0].signTransaction,
|
||||||
|
signAllTransactions: wallets[0].signAllTransactions,
|
||||||
|
};
|
||||||
|
const provider = new AnchorProvider(connection, wallet, {
|
||||||
|
preflightCommitment: "confirmed",
|
||||||
|
});
|
||||||
|
|
||||||
|
const program = new Program<Bets>(idl, provider);
|
||||||
|
const [bet_list_pda] = await PublicKey.findProgramAddress(
|
||||||
|
[Buffer.from("bets_list")],
|
||||||
|
program.programId
|
||||||
|
);
|
||||||
|
// Fetch all open bet accounts
|
||||||
|
const bet_list = await program.account.betsList.fetch(bet_list_pda);
|
||||||
|
|
||||||
|
// Extract required bet data
|
||||||
|
const formattedBets = await Promise.all(
|
||||||
|
bet_list.bets.map(async (bet) => {
|
||||||
|
const betAcc = await program.account.betVault.fetch(bet);
|
||||||
|
console.log(betAcc.gameId);
|
||||||
|
return {
|
||||||
|
id: betAcc.gameId,
|
||||||
|
owner: betAcc.owner.toBase58(),
|
||||||
|
joiner: betAcc.joiner ? betAcc.joiner.toBase58() : "Open",
|
||||||
|
wager: betAcc.wager.toNumber() / LAMPORTS_PER_SOL
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`Got ${formattedBets.length} bets`);
|
||||||
|
|
||||||
|
setOpenBets(formattedBets);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching open bets:", error);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Auto-refresh every 10 seconds
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ready) return;
|
||||||
|
|
||||||
|
fetchOpenBets(); // Initial fetch
|
||||||
|
|
||||||
|
const interval = setInterval(fetchOpenBets, 10000); // Refresh every 10s
|
||||||
|
|
||||||
|
return () => clearInterval(interval); // Cleanup on unmount
|
||||||
|
}, [ready]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="py-16 px-6">
|
||||||
|
<h2 className="text-3xl font-bold text-white mb-6">Your Games</h2>
|
||||||
|
|
||||||
|
{loading ? (
|
||||||
|
<p className="text-gray-400">Loading open games...</p>
|
||||||
|
) : (
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{openBets.map((bet) => {
|
||||||
|
const game = games.find((g) => g.id === bet.gameId); // Match game
|
||||||
|
|
||||||
|
if (!game) return null; // Skip unmatched bets
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={bet.id}
|
||||||
|
className="relative group bg-[rgb(30,30,30)] rounded-2xl p-2 w-50 overflow-hidden cursor-pointer transition-all duration-300"
|
||||||
|
>
|
||||||
|
{/* Game Thumbnail */}
|
||||||
|
<div className="relative w-full h-40 overflow-hidden rounded-xl">
|
||||||
|
<Image
|
||||||
|
src={game.thumbnail}
|
||||||
|
alt={game.name}
|
||||||
|
layout="fill"
|
||||||
|
objectFit="cover"
|
||||||
|
className="transition-transform duration-300 group-hover:scale-110"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Game Info */}
|
||||||
|
<div className="mt-4 px-3 text-left">
|
||||||
|
<h3 className="text-lg font-semibold text-white py-2">{game.name}</h3>
|
||||||
|
<p className="text-xs text-gray-400 font-mono py-1">Wager</p>
|
||||||
|
<p className="text-xs text-white font-mono py-1">{bet.wager} SOL</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Close Button (Trash Icon) */}
|
||||||
|
<button
|
||||||
|
className="absolute bottom-3 right-3 bg-red-600 text-white p-2 rounded-full transition duration-300 hover:bg-red-800"
|
||||||
|
onClick={() => console.log(`Removing bet ${bet.id}`)}
|
||||||
|
>
|
||||||
|
<FiTrash size={16} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
export const games = [
|
export const games = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: "tetris",
|
||||||
name: "Block Drop",
|
name: "Block Drop",
|
||||||
entryFee: "0.1 SOL",
|
entryFee: "0.1 SOL",
|
||||||
thumbnail: "/duelfiassets/Block Drop Illustration.jpeg",
|
thumbnail: "/duelfiassets/Block Drop Illustration.jpeg",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: "snakes",
|
||||||
name: "Venom Trails",
|
name: "Venom Trails",
|
||||||
entryFee: "0.02 ETH",
|
entryFee: "0.02 ETH",
|
||||||
thumbnail: "/duelfiassets/Venom Trail Game Cover Illustration.png",
|
thumbnail: "/duelfiassets/Venom Trail Game Cover Illustration.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: "bubbles",
|
||||||
name: "Wall Smash",
|
name: "Wall Smash",
|
||||||
entryFee: "0.05 ETH",
|
entryFee: "0.05 ETH",
|
||||||
thumbnail: "/duelfiassets/Wall Smash Game Cover Illustration.png",
|
thumbnail: "/duelfiassets/Wall Smash Game Cover Illustration.png",
|
||||||
|
|
@ -20,7 +20,7 @@ export const games = [
|
||||||
];
|
];
|
||||||
|
|
||||||
export interface Game {
|
export interface Game {
|
||||||
id: number;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
entryFee: string;
|
entryFee: string;
|
||||||
thumbnail: string;
|
thumbnail: string;
|
||||||
|
|
|
||||||
1
src/data/shared.ts
Normal file
1
src/data/shared.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export const CLUSTER_URL = "https://api.devnet.solana.com";
|
||||||
299
src/idl/bets.ts
Normal file
299
src/idl/bets.ts
Normal file
|
|
@ -0,0 +1,299 @@
|
||||||
|
/**
|
||||||
|
* Program IDL in camelCase format in order to be used in JS/TS.
|
||||||
|
*
|
||||||
|
* Note that this is only a type helper and is not the actual IDL. The original
|
||||||
|
* IDL can be found at `target/idl/bets.json`.
|
||||||
|
*/
|
||||||
|
export type Bets = {
|
||||||
|
"address": "HxsDuhD7wcPxcMsrYdteMYxkffuwff8HoxhZ7NuFtM37",
|
||||||
|
"metadata": {
|
||||||
|
"name": "bets",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"spec": "0.1.0",
|
||||||
|
"description": "Created with Anchor"
|
||||||
|
},
|
||||||
|
"instructions": [
|
||||||
|
{
|
||||||
|
"name": "closeBet",
|
||||||
|
"discriminator": [
|
||||||
|
185,
|
||||||
|
206,
|
||||||
|
13,
|
||||||
|
184,
|
||||||
|
176,
|
||||||
|
108,
|
||||||
|
140,
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "betsList",
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "betVault",
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "winner",
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "payer",
|
||||||
|
"writable": true,
|
||||||
|
"signer": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "systemProgram",
|
||||||
|
"address": "11111111111111111111111111111111"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "winner",
|
||||||
|
"type": "pubkey"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "createBet",
|
||||||
|
"discriminator": [
|
||||||
|
197,
|
||||||
|
42,
|
||||||
|
153,
|
||||||
|
2,
|
||||||
|
59,
|
||||||
|
63,
|
||||||
|
143,
|
||||||
|
246
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "payer",
|
||||||
|
"writable": true,
|
||||||
|
"signer": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "betsList",
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "betVault",
|
||||||
|
"writable": true,
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
98,
|
||||||
|
101,
|
||||||
|
116,
|
||||||
|
95,
|
||||||
|
118,
|
||||||
|
97,
|
||||||
|
117,
|
||||||
|
108,
|
||||||
|
116
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "account",
|
||||||
|
"path": "payer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "arg",
|
||||||
|
"path": "gameId"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "arg",
|
||||||
|
"path": "nonce"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "systemProgram",
|
||||||
|
"address": "11111111111111111111111111111111"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "wager",
|
||||||
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "gameId",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nonce",
|
||||||
|
"type": "u64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initialize",
|
||||||
|
"discriminator": [
|
||||||
|
175,
|
||||||
|
175,
|
||||||
|
109,
|
||||||
|
31,
|
||||||
|
13,
|
||||||
|
152,
|
||||||
|
155,
|
||||||
|
237
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "betsList",
|
||||||
|
"writable": true,
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
98,
|
||||||
|
101,
|
||||||
|
116,
|
||||||
|
115,
|
||||||
|
95,
|
||||||
|
108,
|
||||||
|
105,
|
||||||
|
115,
|
||||||
|
116
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "payer",
|
||||||
|
"writable": true,
|
||||||
|
"signer": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "systemProgram",
|
||||||
|
"address": "11111111111111111111111111111111"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "joinBet",
|
||||||
|
"discriminator": [
|
||||||
|
69,
|
||||||
|
116,
|
||||||
|
82,
|
||||||
|
26,
|
||||||
|
144,
|
||||||
|
192,
|
||||||
|
58,
|
||||||
|
238
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "betVault",
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "payer",
|
||||||
|
"writable": true,
|
||||||
|
"signer": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "systemProgram",
|
||||||
|
"address": "11111111111111111111111111111111"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "gameId",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "betVault",
|
||||||
|
"discriminator": [
|
||||||
|
103,
|
||||||
|
78,
|
||||||
|
21,
|
||||||
|
234,
|
||||||
|
18,
|
||||||
|
250,
|
||||||
|
230,
|
||||||
|
209
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "betsList",
|
||||||
|
"discriminator": [
|
||||||
|
231,
|
||||||
|
234,
|
||||||
|
50,
|
||||||
|
58,
|
||||||
|
81,
|
||||||
|
179,
|
||||||
|
239,
|
||||||
|
117
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": 6000,
|
||||||
|
"name": "customError",
|
||||||
|
"msg": "Custom error message"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"name": "betVault",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "gameId",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "owner",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "joiner",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wager",
|
||||||
|
"type": "u64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "betsList",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "bets",
|
||||||
|
"type": {
|
||||||
|
"vec": "pubkey"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"constants": [
|
||||||
|
{
|
||||||
|
"name": "seed",
|
||||||
|
"type": "string",
|
||||||
|
"value": "\"anchor\""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
292
src/idl/bets_idl.json
Normal file
292
src/idl/bets_idl.json
Normal file
|
|
@ -0,0 +1,292 @@
|
||||||
|
{
|
||||||
|
"address": "HxsDuhD7wcPxcMsrYdteMYxkffuwff8HoxhZ7NuFtM37",
|
||||||
|
"metadata": {
|
||||||
|
"name": "bets",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"spec": "0.1.0",
|
||||||
|
"description": "Created with Anchor"
|
||||||
|
},
|
||||||
|
"instructions": [
|
||||||
|
{
|
||||||
|
"name": "close_bet",
|
||||||
|
"discriminator": [
|
||||||
|
185,
|
||||||
|
206,
|
||||||
|
13,
|
||||||
|
184,
|
||||||
|
176,
|
||||||
|
108,
|
||||||
|
140,
|
||||||
|
107
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "bets_list",
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bet_vault",
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "winner",
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "payer",
|
||||||
|
"writable": true,
|
||||||
|
"signer": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "system_program",
|
||||||
|
"address": "11111111111111111111111111111111"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "winner",
|
||||||
|
"type": "pubkey"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "create_bet",
|
||||||
|
"discriminator": [
|
||||||
|
197,
|
||||||
|
42,
|
||||||
|
153,
|
||||||
|
2,
|
||||||
|
59,
|
||||||
|
63,
|
||||||
|
143,
|
||||||
|
246
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "payer",
|
||||||
|
"writable": true,
|
||||||
|
"signer": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bets_list",
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bet_vault",
|
||||||
|
"writable": true,
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
98,
|
||||||
|
101,
|
||||||
|
116,
|
||||||
|
95,
|
||||||
|
118,
|
||||||
|
97,
|
||||||
|
117,
|
||||||
|
108,
|
||||||
|
116
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "account",
|
||||||
|
"path": "payer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "arg",
|
||||||
|
"path": "game_id"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "arg",
|
||||||
|
"path": "_nonce"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "system_program",
|
||||||
|
"address": "11111111111111111111111111111111"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "wager",
|
||||||
|
"type": "u64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "game_id",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nonce",
|
||||||
|
"type": "u64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "initialize",
|
||||||
|
"discriminator": [
|
||||||
|
175,
|
||||||
|
175,
|
||||||
|
109,
|
||||||
|
31,
|
||||||
|
13,
|
||||||
|
152,
|
||||||
|
155,
|
||||||
|
237
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "bets_list",
|
||||||
|
"writable": true,
|
||||||
|
"pda": {
|
||||||
|
"seeds": [
|
||||||
|
{
|
||||||
|
"kind": "const",
|
||||||
|
"value": [
|
||||||
|
98,
|
||||||
|
101,
|
||||||
|
116,
|
||||||
|
115,
|
||||||
|
95,
|
||||||
|
108,
|
||||||
|
105,
|
||||||
|
115,
|
||||||
|
116
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "payer",
|
||||||
|
"writable": true,
|
||||||
|
"signer": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "system_program",
|
||||||
|
"address": "11111111111111111111111111111111"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "join_bet",
|
||||||
|
"discriminator": [
|
||||||
|
69,
|
||||||
|
116,
|
||||||
|
82,
|
||||||
|
26,
|
||||||
|
144,
|
||||||
|
192,
|
||||||
|
58,
|
||||||
|
238
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "bet_vault",
|
||||||
|
"writable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "payer",
|
||||||
|
"writable": true,
|
||||||
|
"signer": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "system_program",
|
||||||
|
"address": "11111111111111111111111111111111"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "game_id",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"name": "BetVault",
|
||||||
|
"discriminator": [
|
||||||
|
103,
|
||||||
|
78,
|
||||||
|
21,
|
||||||
|
234,
|
||||||
|
18,
|
||||||
|
250,
|
||||||
|
230,
|
||||||
|
209
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "BetsList",
|
||||||
|
"discriminator": [
|
||||||
|
231,
|
||||||
|
234,
|
||||||
|
50,
|
||||||
|
58,
|
||||||
|
81,
|
||||||
|
179,
|
||||||
|
239,
|
||||||
|
117
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": 6000,
|
||||||
|
"name": "CustomError",
|
||||||
|
"msg": "Custom error message"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"name": "BetVault",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "game_id",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "owner",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "joiner",
|
||||||
|
"type": "pubkey"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wager",
|
||||||
|
"type": "u64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "BetsList",
|
||||||
|
"type": {
|
||||||
|
"kind": "struct",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "bets",
|
||||||
|
"type": {
|
||||||
|
"vec": "pubkey"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"constants": [
|
||||||
|
{
|
||||||
|
"name": "SEED",
|
||||||
|
"type": "string",
|
||||||
|
"value": "\"anchor\""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user