This commit is contained in:
Sewmina 2025-04-09 13:03:05 +05:30
parent de435d89aa
commit 147ef9e669
12 changed files with 80 additions and 61 deletions

View File

@ -8,7 +8,8 @@ import { PriceSelection } from "./PriceSelection";
import { GameSelection } from "./GameSelection";
import { createBet } from "@/shared/solana_helpers";
import { Game } from "@/types/Game";
import { EXPLORER_TX_TEMPLATE } from "@/data/shared";
import { connection, EXPLORER_TX_TEMPLATE } from "@/data/shared";
import { CONFIRMATION_THRESHOLD } from "@/shared/constants";
interface GameModalProps {
isOpen: boolean;
@ -61,23 +62,33 @@ export default function GameModal({ isOpen, onClose }: GameModalProps) {
}
setIsProcessing(true);
toast.loading("Creating bet");
try {
const tx = await createBet(wallet, user?.id ?? "", selectedPrice, selectedGame.id, false);
const url = EXPLORER_TX_TEMPLATE.replace("{address}", tx);
if (tx.length > 5) {
connection.confirmTransaction(tx, CONFIRMATION_THRESHOLD).finally(()=>{
toast.dismiss();
toast.success(`Bet created successfully!`, {
action: {
label: "View TX",
onClick: () => window.open(url, "_blank"),
},
});
})
}
onClose();
} catch (error) {
console.error("Error creating bet:", error);
toast.error("Failed to create bet. Please try again.");
toast.dismiss();
} finally {
setIsProcessing(false);
}
};

View File

@ -7,7 +7,7 @@ import GameModal from "./GameModal";
import { HowItWorksModal } from "./HowItWorksModal";
import YourGames from "./YourGames";
import { Bet } from "@/types/Bet";
import { fetchOpenBets, createBet, joinBet, getVaultByAddress } from "@/shared/solana_helpers";
import { fetchOpenBets, createBet, getVaultByAddress } from "@/shared/solana_helpers";
import { ConnectedSolanaWallet, usePrivy, useSolanaWallets } from "@privy-io/react-auth";
import { RematchModal } from "./RematchModal";
@ -21,7 +21,6 @@ export default function HeroSection() {
const [lastActiveBet, setLastActiveBet] = useState<Bet>();
const [rematchInProgress, setRematchInProgress] = useState(false);
const [rematchTxError, setRematchTxError] = useState(false);
const [rematchBetAddress, setRematchBetAddress] = useState<string | null>(null);
const { wallets, ready } = useSolanaWallets();
const { user } = usePrivy();
@ -102,8 +101,8 @@ export default function HeroSection() {
const pollUntilFound = async (
maxRetries = 10,
delayMs = 3000
): Promise<any> => {
for (let i = 0; i < maxRetries; i++) {
): Promise<Bet | undefined> => {
for (let i:number = 0; i < maxRetries; i++) {
const vault = await getVaultByAddress(solWallet, tx);
if (vault) return vault;
console.log(`Waiting for vault account... (${i + 1}/${maxRetries})`);
@ -166,8 +165,8 @@ export default function HeroSection() {
address: string,
maxRetries = 10,
delayMs = 3000
): Promise<any> => {
for (let i = 0; i < maxRetries; i++) {
): Promise<Bet | undefined> => {
for (let i:number = 0; i < maxRetries; i++) {
console.log(`Polling vault for address ${address}... (${i + 1}/${maxRetries})`);
const vault = await getVaultByAddress(solWallet, address);
if (vault) return vault;
@ -175,13 +174,14 @@ export default function HeroSection() {
}
console.warn("Vault not found after max retries.");
return null;
return;
};
const rematchVault:Bet = await pollForVault(rematchAddress);
const rematchVault:Bet | undefined = await pollForVault(rematchAddress);
if (rematchVault) {
const tx = await joinBet(solWallet, user?.id!, rematchVault.id, rematchVault.address);
// const tx = await joinBet(solWallet, user?.id!, rematchVault.id, rematchVault.address);
setMyActiveBet(rematchVault);
setLastActiveBet(rematchVault);
setRematch(false);
@ -286,6 +286,7 @@ export default function HeroSection() {
return (
<>
{myActiveBet && !rematch ? (
(myActiveBet.owner_id && myActiveBet.joiner_id) ? (
<div className="w-full h-screen flex justify-center items-center bg-black">
<iframe
ref={iframeRef}
@ -294,6 +295,10 @@ export default function HeroSection() {
allowFullScreen
/>
</div>
) : <>
<div className="w-full h-screen flex justify-center items-center bg-black">
<label>Loading...</label>
</div></>
) : (
<section className="flex flex-col items-center text-center py-16">
<Image

View File

@ -6,8 +6,8 @@ import { joinBet } from "@/shared/solana_helpers";
import { Bet } from "../types/Bet";
import { fetchUserById } from "@/shared/data_fetcher";
import { toast } from "sonner";
import { EXPLORER_TX_TEMPLATE } from "@/data/shared";
import { WAGER_PRIZE_MULT } from "@/shared/constants";
import { connection, EXPLORER_TX_TEMPLATE } from "@/data/shared";
import { CONFIRMATION_THRESHOLD, WAGER_PRIZE_MULT } from "@/shared/constants";
interface GameModalProps {
bets: Bet[];
@ -29,17 +29,22 @@ export default function YourGames({ bets }: GameModalProps) {
wallet = _wallet;
}
});
toast.loading("Joining Bet");
const tx = await joinBet(wallet, user?.id ?? "", selectedBet.id, selectedBet.address);
const url = EXPLORER_TX_TEMPLATE.replace("{address}", tx);
if (tx.length > 5) {
connection.confirmTransaction(tx, CONFIRMATION_THRESHOLD).finally(()=>{
toast.dismiss();
toast.success("Joined game successfully!", {
action: {
label: "View TX",
onClick: () => window.open(url, "_blank"),
},
});
})
} else {
toast.error("Failed to join this game");
}

View File

@ -1,7 +1,5 @@
"use client";
import { Bet } from "@/types/Bet";
import React, { useEffect } from "react";
import { fetchOpenBets } from "../shared/solana_helpers"; // adjust path as needed
import React from "react";
import { ConnectedSolanaWallet } from "@privy-io/react-auth"; // import your wallet type
interface RematchModalProps {
@ -13,9 +11,7 @@ interface RematchModalProps {
export const RematchModal: React.FC<RematchModalProps> = ({
isOwner,
inProgress,
hasError,
wallets
} : RematchModalProps) => {

View File

@ -7,7 +7,8 @@ import { useSolanaWallets } from "@privy-io/react-auth";
import { closeBet } from "@/shared/solana_helpers";
import { Bet } from "../types/Bet";
import { toast } from "sonner";
import { EXPLORER_TX_TEMPLATE } from "@/data/shared";
import { connection, EXPLORER_TX_TEMPLATE } from "@/data/shared";
import { CONFIRMATION_THRESHOLD } from "@/shared/constants";
interface GameModalProps {
bets: Bet[];
}
@ -41,6 +42,7 @@ export default function YourGames({bets}:GameModalProps) {
const handleCloseBet = async () => {
if (!selectedBet) return;
setIsProcessing(true);
toast.loading("Closing bet");
let wallet = wallets[0];
wallets.forEach((_wallet) => {
if (wallet.type === "solana") {
@ -49,8 +51,10 @@ export default function YourGames({bets}:GameModalProps) {
});
try {
const tx = await closeBet(wallet, selectedBet.id);
const url = EXPLORER_TX_TEMPLATE.replace("{address}", tx);
const url = EXPLORER_TX_TEMPLATE.replace("{address}", tx);
connection.confirmTransaction(tx, CONFIRMATION_THRESHOLD).finally(()=>{
toast.dismiss();
toast.success(`Closed the bet successfully!`, {
action: {
label: "View TX",
@ -58,6 +62,8 @@ export default function YourGames({bets}:GameModalProps) {
},
});
updateBets();
})
} catch (error) {
console.error("Error closing bet:", error);
toast.message("Failed to close the bet. Please try again.");

View File

@ -1,3 +1,6 @@
import { Connection } from "@solana/web3.js";
export const CLUSTER_URL = "https://api.devnet.solana.com";
export const EXPLORER_ADDRESS_TEMPLATE = "https://explorer.solana.com/address/{address}?cluster=devnet";
export const EXPLORER_TX_TEMPLATE = "https://explorer.solana.com/tx/{address}?cluster=devnet";
export const connection = new Connection(CLUSTER_URL);

View File

@ -3,4 +3,4 @@ import { Commitment, PublicKey } from "@solana/web3.js";
export const FEE_COLLECTOR_PUBKEY = new PublicKey("cocD4r4yNpHxPq7CzUebxEMyLki3X4d2Y3HcTX5ptUc");
export const WAGER_PRIZE_MULT = 0.95;
export const CONFIRMATION_THRESHOLD:Commitment = 'processed';
export const CONFIRMATION_THRESHOLD:Commitment = 'finalized';

View File

@ -1,4 +1,4 @@
import { CLUSTER_URL } from "@/data/shared";
import { CLUSTER_URL, connection } from "@/data/shared";
import { Bets } from "@/idl/bets";
import { AnchorProvider, BN, Program } from "@coral-xyz/anchor";
import { ConnectedSolanaWallet } from "@privy-io/react-auth";
@ -6,14 +6,12 @@ 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 { Game } from "@/types/Game";
import { CONFIRMATION_THRESHOLD, FEE_COLLECTOR_PUBKEY } from "./constants";
export const fetchOpenBets = async (wallets: ConnectedSolanaWallet): Promise<Bet[]> => {
try {
if (!wallets) return [];
const connection = new Connection(CLUSTER_URL);
const wallet = {
publicKey: new PublicKey(wallets.address),
signTransaction: wallets.signTransaction,
@ -61,7 +59,6 @@ export async function getVaultByAddress(wallets: ConnectedSolanaWallet, address:
try {
if (!wallets) return undefined;
const connection = new Connection(CLUSTER_URL);
const wallet = {
publicKey: new PublicKey(wallets.address),
signTransaction: wallets.signTransaction,
@ -93,7 +90,6 @@ export async function getVaultByAddress(wallets: ConnectedSolanaWallet, address:
export async function closeBet(wallets: ConnectedSolanaWallet, betId: string): Promise<string> {
try {
const connection = new Connection(CLUSTER_URL);
const wallet = {
publicKey: new PublicKey(wallets.address),
signTransaction: wallets.signTransaction,
@ -147,6 +143,7 @@ export async function closeBet(wallets: ConnectedSolanaWallet, betId: string): P
// Send transaction// Replace with correct RPC endpoint
const txId = await connection.sendRawTransaction(signedTx.serialize());
console.log(`Transaction: ${tx}`);
return txId;
} catch (error) {
@ -156,7 +153,7 @@ export async function closeBet(wallets: ConnectedSolanaWallet, betId: string): P
}
export async function createBet(wallets: ConnectedSolanaWallet, uid: string, selectedPrice: number, selectedGame: string, get_account_address: boolean): Promise<string> {
const connection = new Connection(CLUSTER_URL);
const wallet = {
publicKey: new PublicKey(wallets.address),
signTransaction: wallets.signTransaction,
@ -169,7 +166,6 @@ export async function createBet(wallets: ConnectedSolanaWallet, uid: string, sel
const program = new Program<Bets>(idl, provider);
try {
toast.loading("Creating bet...");
const nonce = getRandomInt(100000000);
const [bet_list_pda] = await PublicKey.findProgramAddress(
[Buffer.from("bets_list")],
@ -195,8 +191,6 @@ export async function createBet(wallets: ConnectedSolanaWallet, uid: string, sel
// Send transaction
const txId = await connection.sendRawTransaction(signedTx.serialize());
console.log(`Transaction sent: ${txId}`);
toast.success("Bet created successfully");
console.log(`Transaction confirmed: ${txId}`);
if (get_account_address) {
const gameIdBytes = Buffer.from(selectedGame); // selectedGame is a string (game_id)
@ -231,7 +225,6 @@ export async function createBet(wallets: ConnectedSolanaWallet, uid: string, sel
}
export async function joinBet(wallets: ConnectedSolanaWallet, uid: string, gameId: string, address: string): Promise<string> {
const connection = new Connection(CLUSTER_URL);
const wallet = {
publicKey: new PublicKey(wallets.address),
signTransaction: wallets.signTransaction,

View File

@ -1,10 +1,10 @@
interface GameHistory {
address: string;
master_score: string;
client_score: string;
winner: string;
wager: string;
master_id: string;
client_id: string;
game:string;
}
// interface GameHistory {
// address: string;
// master_score: string;
// client_score: string;
// winner: string;
// wager: string;
// master_id: string;
// client_id: string;
// game:string;
// }

View File

@ -2,7 +2,7 @@ export interface Submission{
username: string;
master_score: number;
client_score: number;
leaderboard: any;
leaderboard: string;
master_id:string;
client_id:string;
winner:string;