import { CLUSTER_URL, connection, VALIDATOR_URL, VALIDATOR_URL_DEV } from "@/data/shared"; import { Bets } from "@/idl/bets"; import { AnchorProvider, BN, Program } from "@coral-xyz/anchor"; import { ConnectedSolanaWallet } from "@privy-io/react-auth"; import { Connection, LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js"; import idl from "../idl/bets_idl.json"; import { Bet } from "@/types/Bet"; import { toast } from "sonner"; import { CONFIRMATION_THRESHOLD } from "./constants"; import { add_new_activity } from "./data_fetcher"; export async function fetchOpenBets(): Promise { const response = await fetch(`${VALIDATOR_URL}fetchBets`); const data = await response.json(); console.log(`Fetched ${data.length} open bets from validator`); return data; } export async function fetchOpenBetsDev(): Promise { const response = await fetch(`${VALIDATOR_URL_DEV}fetchBets`); const data = await response.json(); console.log(`Fetched ${data.length} open bets from validator`); return data; } export async function getVaultByAddress(wallets: ConnectedSolanaWallet, address: string): Promise { try { if (!wallets) return undefined; const wallet = { publicKey: new PublicKey(wallets.address), signTransaction: wallets.signTransaction, signAllTransactions: wallets.signAllTransactions, }; const provider = new AnchorProvider(connection, wallet, { preflightCommitment: CONFIRMATION_THRESHOLD, }); const program = new Program(idl, provider); // Extract required bet data const betAcc = await program.account.betVault.fetch(address); // console.log(betAcc.gameId); return { address: address.toString(), id: betAcc.gameId, owner: betAcc.owner.toBase58(), owner_id: betAcc.ownerId, joiner: betAcc.joiner ? betAcc.joiner.toBase58() : "Open", joiner_id: betAcc.joinerId, wager: betAcc.wager.toNumber() / LAMPORTS_PER_SOL }; } catch (error) { console.error("Error fetching open bets:", error); } return undefined; } export async function closeBet(wallets: ConnectedSolanaWallet, uid:string, betId: string): Promise { try { const wallet = { publicKey: new PublicKey(wallets.address), signTransaction: wallets.signTransaction, signAllTransactions: wallets.signAllTransactions, }; const provider = new AnchorProvider(connection, wallet, { preflightCommitment: CONFIRMATION_THRESHOLD, }); const program = new Program(idl, provider); const [bet_list_pda] = await PublicKey.findProgramAddress( [Buffer.from("bets_list")], program.programId ); // Fetch the bet list const betList = await program.account.betsList.fetch(bet_list_pda); let chosenBet: PublicKey | null = null; let game_id:string = ""; for (const bet of betList.bets) { const betAcc = await program.account.betVault.fetch(bet); if (betAcc.owner.toBase58() === wallets.address && betAcc.gameId.toString() === betId) { chosenBet = bet; game_id = betAcc.gameId.toString(); break; } } if (!chosenBet) { console.error(`Bet not found or not owned by the user\n${wallets.address}\n${betId}`); return ""; } const winner = new PublicKey(wallets.address); const chosenBetVaultAcc = await program.account.betVault.fetch(chosenBet); // Execute the closeBet transaction const tx = await program.methods .closeBet(winner, uid) .accounts({ betVault: chosenBet, betsList: bet_list_pda, winner: winner }) .transaction(); tx.feePayer = new PublicKey(wallets.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()); add_new_activity("close", uid, chosenBetVaultAcc.joinerId, game_id, chosenBetVaultAcc.wager.toNumber() / LAMPORTS_PER_SOL); console.log(`Transaction: ${txId}`); return txId; } catch (error) { console.error("Error closing bet:", error); } return ""; } export async function createBet(wallets: ConnectedSolanaWallet, uid: string, selectedPrice: number, selectedGame: string, get_account_address: boolean): Promise { const wallet = { publicKey: new PublicKey(wallets.address), signTransaction: wallets.signTransaction, signAllTransactions: wallets.signAllTransactions, }; const provider = new AnchorProvider(connection, wallet, { preflightCommitment: CONFIRMATION_THRESHOLD, }); const program = new Program(idl, provider); try { const nonce = getRandomInt(100000000); const [bet_list_pda] = await PublicKey.findProgramAddress( [Buffer.from("bets_list")], program.programId ); console.log(`bets list : ${bet_list_pda}`); // Create transaction const tx = await program.methods .createBet(new BN(selectedPrice * 1000000000), uid, selectedGame, new BN(nonce)) .accounts({ betsList: bet_list_pda, }) .transaction(); // Get transaction object instead of RPC call tx.feePayer = new PublicKey(wallets.address); tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash; // Sign transaction with Privy const signedTx = await wallet.signTransaction(tx); // Send transaction const txId = await connection.sendRawTransaction(signedTx.serialize()); console.log(`Transaction sent: ${txId}`); console.log(`Transaction confirmed: ${txId}`); add_new_activity("create", uid, "", selectedGame, selectedPrice); if (get_account_address) { const gameIdBytes = Buffer.from(selectedGame); // selectedGame is a string (game_id) const nonceBytes = new BN(nonce).toArrayLike(Buffer, "le", 8); // _nonce.to_le_bytes() const [betVaultPda] = await PublicKey.findProgramAddress( [ Buffer.from("bet_vault"), new PublicKey(wallets.address).toBuffer(), // payer gameIdBytes, nonceBytes, ], program.programId ); return betVaultPda.toString(); } else { return txId; } } catch (error: unknown) { toast.dismiss(); const errorMessage = String(error); // Converts error to string safely if (errorMessage.includes("already in use")) { toast.error("You can't make 2 bets for the same game."); } else { toast.error("Failed to create bet."); console.error(error); } } return ""; } export async function joinBet(wallets: ConnectedSolanaWallet, uid: string, gameId: string, address: string): Promise { const wallet = { publicKey: new PublicKey(wallets.address), signTransaction: wallets.signTransaction, signAllTransactions: wallets.signAllTransactions, }; const provider = new AnchorProvider(connection, wallet, { preflightCommitment: CONFIRMATION_THRESHOLD, }); const program = new Program(idl, provider); try { const [bet_list_pda] = await PublicKey.findProgramAddress( [Buffer.from("bets_list")], program.programId ); const connection = new Connection(CLUSTER_URL, CONFIRMATION_THRESHOLD); const betVaultPubkey = new PublicKey(address); console.log(`bets list : ${bet_list_pda}`); // Create transaction const tx = await program.methods .joinBet(uid, gameId) .accounts({ betVault: betVaultPubkey, }) .transaction(); // Get transaction object instead of RPC call tx.feePayer = new PublicKey(wallets.address); tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash; // Sign transaction with Privy const signedTx = await wallet.signTransaction(tx); const chosenBetVaultAcc = await program.account.betVault.fetch(betVaultPubkey); // Send transaction// Replace with correct RPC endpoint const txId = await connection.sendRawTransaction(signedTx.serialize()); add_new_activity("join", "",uid, gameId, chosenBetVaultAcc.wager.toNumber() / LAMPORTS_PER_SOL); console.log(`Transaction ID: ${txId}`); return txId; } catch (error: unknown) { // const errorMessage = String(error); // Converts error to string safely toast.error("Failed to create bet."); console.error(error); } return ""; } function getRandomInt(max: number): number { return Math.floor(Math.random() * max); }