v1 almost
BIN
public/UnityBuild/tetris/Build/prod.data
Normal file
22
public/UnityBuild/tetris/Build/prod.framework.js
Normal file
1
public/UnityBuild/tetris/Build/prod.loader.js
Normal file
BIN
public/UnityBuild/tetris/Build/prod.wasm
Normal file
BIN
public/UnityBuild/tetris/TemplateData/MemoryProfiler.png
Normal file
|
After Width: | Height: | Size: 665 B |
BIN
public/UnityBuild/tetris/TemplateData/favicon.ico
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
public/UnityBuild/tetris/TemplateData/fullscreen-button.png
Normal file
|
After Width: | Height: | Size: 175 B |
|
After Width: | Height: | Size: 96 B |
|
After Width: | Height: | Size: 109 B |
BIN
public/UnityBuild/tetris/TemplateData/progress-bar-full-dark.png
Normal file
|
After Width: | Height: | Size: 74 B |
|
After Width: | Height: | Size: 84 B |
16
public/UnityBuild/tetris/TemplateData/style.css
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
body { padding: 0; margin: 0 }
|
||||
#unity-container { position: absolute }
|
||||
#unity-container.unity-desktop { left: 50%; top: 50%; transform: translate(-50%, -50%) }
|
||||
#unity-container.unity-mobile { position: fixed; width: 100%; height: 100% }
|
||||
#unity-canvas { background: #231F20 }
|
||||
.unity-mobile #unity-canvas { width: 100%; height: 100% }
|
||||
#unity-loading-bar { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: none }
|
||||
#unity-logo { width: 154px; height: 130px; background: url('unity-logo-dark.png') no-repeat center }
|
||||
#unity-progress-bar-empty { width: 141px; height: 18px; margin-top: 10px; margin-left: 6.5px; background: url('progress-bar-empty-dark.png') no-repeat center }
|
||||
#unity-progress-bar-full { width: 0%; height: 18px; margin-top: 10px; background: url('progress-bar-full-dark.png') no-repeat center }
|
||||
#unity-footer { position: relative }
|
||||
.unity-mobile #unity-footer { display: none }
|
||||
#unity-webgl-logo { float:left; width: 204px; height: 38px; background: url('webgl-logo.png') no-repeat center }
|
||||
#unity-build-title { float: right; margin-right: 10px; line-height: 38px; font-family: arial; font-size: 18px }
|
||||
#unity-fullscreen-button { cursor:pointer; float: right; width: 38px; height: 38px; background: url('fullscreen-button.png') no-repeat center }
|
||||
#unity-warning { position: absolute; left: 50%; top: 5%; transform: translate(-50%); background: white; padding: 10px; display: none }
|
||||
BIN
public/UnityBuild/tetris/TemplateData/unity-logo-dark.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
public/UnityBuild/tetris/TemplateData/unity-logo-light.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
public/UnityBuild/tetris/TemplateData/webgl-logo.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
public/UnityBuild/tetris/TemplateData/webmemd-icon.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
122
public/UnityBuild/tetris/index.html
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Unity WebGL Player | TetrisMP</title>
|
||||
<link rel="shortcut icon" href="TemplateData/favicon.ico">
|
||||
<link rel="stylesheet" href="TemplateData/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="unity-container" class="unity-desktop">
|
||||
<canvas id="unity-canvas" width=1280 height=720 tabindex="-1"></canvas>
|
||||
<div id="unity-loading-bar">
|
||||
<div id="unity-logo"></div>
|
||||
<div id="unity-progress-bar-empty">
|
||||
<div id="unity-progress-bar-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="unity-warning"> </div>
|
||||
<div id="unity-footer">
|
||||
<div id="unity-webgl-logo"></div>
|
||||
<div id="unity-fullscreen-button"></div>
|
||||
<div id="unity-build-title">TetrisMP</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
|
||||
var container = document.querySelector("#unity-container");
|
||||
var canvas = document.querySelector("#unity-canvas");
|
||||
var loadingBar = document.querySelector("#unity-loading-bar");
|
||||
var progressBarFull = document.querySelector("#unity-progress-bar-full");
|
||||
var fullscreenButton = document.querySelector("#unity-fullscreen-button");
|
||||
var warningBanner = document.querySelector("#unity-warning");
|
||||
|
||||
// Shows a temporary message banner/ribbon for a few seconds, or
|
||||
// a permanent error message on top of the canvas if type=='error'.
|
||||
// If type=='warning', a yellow highlight color is used.
|
||||
// Modify or remove this function to customize the visually presented
|
||||
// way that non-critical warnings and error messages are presented to the
|
||||
// user.
|
||||
function unityShowBanner(msg, type) {
|
||||
function updateBannerVisibility() {
|
||||
warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
|
||||
}
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = msg;
|
||||
warningBanner.appendChild(div);
|
||||
if (type == 'error') div.style = 'background: red; padding: 10px;';
|
||||
else {
|
||||
if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
|
||||
setTimeout(function() {
|
||||
warningBanner.removeChild(div);
|
||||
updateBannerVisibility();
|
||||
}, 5000);
|
||||
}
|
||||
updateBannerVisibility();
|
||||
}
|
||||
|
||||
var buildUrl = "Build";
|
||||
var loaderUrl = buildUrl + "/prod.loader.js";
|
||||
var config = {
|
||||
dataUrl: buildUrl + "/prod.data",
|
||||
frameworkUrl: buildUrl + "/prod.framework.js",
|
||||
codeUrl: buildUrl + "/prod.wasm",
|
||||
streamingAssetsUrl: "StreamingAssets",
|
||||
companyName: "DefaultCompany",
|
||||
productName: "TetrisMP",
|
||||
productVersion: "1.0",
|
||||
showBanner: unityShowBanner,
|
||||
};
|
||||
|
||||
// By default, Unity keeps WebGL canvas render target size matched with
|
||||
// the DOM size of the canvas element (scaled by window.devicePixelRatio)
|
||||
// Set this to false if you want to decouple this synchronization from
|
||||
// happening inside the engine, and you would instead like to size up
|
||||
// the canvas DOM size and WebGL render target sizes yourself.
|
||||
// config.matchWebGLToCanvasSize = false;
|
||||
|
||||
if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
|
||||
// Mobile device style: fill the whole browser client area with the game canvas:
|
||||
|
||||
var meta = document.createElement('meta');
|
||||
meta.name = 'viewport';
|
||||
meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';
|
||||
document.getElementsByTagName('head')[0].appendChild(meta);
|
||||
container.className = "unity-mobile";
|
||||
canvas.className = "unity-mobile";
|
||||
|
||||
// To lower canvas resolution on mobile devices to gain some
|
||||
// performance, uncomment the following line:
|
||||
// config.devicePixelRatio = 1;
|
||||
|
||||
|
||||
} else {
|
||||
// Desktop style: Render the game canvas in a window that can be maximized to fullscreen:
|
||||
|
||||
canvas.style.width = "1280px";
|
||||
canvas.style.height = "720px";
|
||||
}
|
||||
|
||||
loadingBar.style.display = "block";
|
||||
|
||||
var script = document.createElement("script");
|
||||
script.src = loaderUrl;
|
||||
script.onload = () => {
|
||||
createUnityInstance(canvas, config, (progress) => {
|
||||
progressBarFull.style.width = 100 * progress + "%";
|
||||
}).then((unityInstance) => {
|
||||
loadingBar.style.display = "none";
|
||||
fullscreenButton.onclick = () => {
|
||||
unityInstance.SetFullscreen(1);
|
||||
};
|
||||
}).catch((message) => {
|
||||
alert(message);
|
||||
});
|
||||
};
|
||||
|
||||
document.body.appendChild(script);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,18 +1,74 @@
|
|||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import OpenGames from "./OpenGames";
|
||||
import GameModal from "./GameModal";
|
||||
import { HowItWorksModal } from "./HowItWorksModal";
|
||||
import YourGames from "./YourGames";
|
||||
import { Bet } from "@/types/Bet";
|
||||
import { fetchOpenBets } from "@/shared/solana_helpers";
|
||||
import { usePrivy, useSolanaWallets } from "@privy-io/react-auth";
|
||||
|
||||
export default function HeroSection() {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [isGameModalOpen, setIsGameModalOpen] = useState(false);
|
||||
const [bets, setBets] = useState<Bet[]>([]);
|
||||
const [myActiveBet, setMyActiveBet] = useState<Bet>();
|
||||
const { wallets, ready } = useSolanaWallets();
|
||||
const {user} = usePrivy();
|
||||
|
||||
async function updateBets() {
|
||||
if (!ready || wallets.length === 0) return;
|
||||
|
||||
// Find the wallet to use (either Solana wallet or the first available wallet)
|
||||
let wallet = wallets.find((_wallet) => _wallet.type === "solana") || wallets[0];
|
||||
|
||||
// Fetch the open bets
|
||||
const fetchedBets = await fetchOpenBets(wallet);
|
||||
|
||||
|
||||
|
||||
// Filter out the bets that are not filled (do not have both owner_id and joiner_id)
|
||||
const filteredBets = fetchedBets.filter((bet) => !(bet.owner_id && bet.joiner_id));
|
||||
|
||||
// Create a new list for filled bets (bets that have both owner_id and joiner_id set)
|
||||
const filledBets = fetchedBets.filter((bet) => bet.owner_id && bet.joiner_id);
|
||||
const activeBet = filledBets.find((bet)=> bet.owner_id == user?.id || bet.joiner_id==user?.id);
|
||||
console.log("My active bet:", activeBet);
|
||||
console.log("Filtered bets:", filteredBets);
|
||||
console.log("Filled bets:", filledBets); // This is the new list for filled bets
|
||||
|
||||
// Set the state for filtered bets and active bet
|
||||
setBets(filteredBets);
|
||||
setMyActiveBet(activeBet);
|
||||
|
||||
// If needed, you can also use the filledBets list for something else
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!ready) return;
|
||||
|
||||
updateBets();
|
||||
const interval = setInterval(updateBets, 10000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [ready]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{myActiveBet ? (
|
||||
// Render Unity WebGL game when myActiveBet is found
|
||||
<div className="w-full h-screen flex justify-center items-center bg-black">
|
||||
<iframe
|
||||
src={`/UnityBuild/${myActiveBet.id}/index.html?betId=${myActiveBet.id}&owner=${myActiveBet.owner_id}&joiner=${myActiveBet.joiner_id}&address=${myActiveBet.address}`} // Change this to the actual path of your Unity WebGL build
|
||||
className="w-full h-full"
|
||||
allowFullScreen
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
// Render the original UI when no active bet
|
||||
<section className="flex flex-col items-center text-center py-16">
|
||||
<Image
|
||||
src="/duelfiassets/Playing on Arcade Machine no BG.png"
|
||||
|
|
@ -54,10 +110,10 @@ export default function HeroSection() {
|
|||
How it works?..
|
||||
</p>
|
||||
|
||||
<YourGames />
|
||||
<OpenGames />
|
||||
|
||||
<YourGames bets={bets} />
|
||||
<OpenGames bets={bets} />
|
||||
</section>
|
||||
)}
|
||||
|
||||
<GameModal isOpen={isGameModalOpen} onClose={() => setIsGameModalOpen(false)} />
|
||||
<HowItWorksModal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} />
|
||||
|
|
|
|||
|
|
@ -1,17 +1,51 @@
|
|||
"use client";
|
||||
import { useEffect, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import { games } from "../data/games";
|
||||
import { useSolanaWallets } from "@privy-io/react-auth";
|
||||
import { fetchOpenBets } from "@/shared/solana_helpers";
|
||||
import { usePrivy, useSolanaWallets } from "@privy-io/react-auth";
|
||||
import { joinBet } from "@/shared/solana_helpers";
|
||||
import { Bet } from "../types/Bet";
|
||||
import { fetchUserById } from "@/shared/data_fetcher";
|
||||
export default function YourGames() {
|
||||
import { toast } from "sonner";
|
||||
import { EXPLORER_TX_TEMPLATE } from "@/data/shared";
|
||||
|
||||
interface GameModalProps {
|
||||
bets: Bet[];
|
||||
}
|
||||
|
||||
export default function YourGames({ bets }: GameModalProps) {
|
||||
const { wallets, ready } = useSolanaWallets();
|
||||
const [myBets, setMyBets] = useState<Bet[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { user } = usePrivy();
|
||||
const [selectedBet, setSelectedBet] = useState<Bet | null>(null); // Track selected bet
|
||||
|
||||
const handleJoinGame = async () => {
|
||||
if (!selectedBet) return;
|
||||
|
||||
let wallet = wallets[0];
|
||||
wallets.forEach((_wallet) => {
|
||||
if (wallet.type === "solana") {
|
||||
wallet = _wallet;
|
||||
}
|
||||
});
|
||||
|
||||
const tx = await joinBet(wallet, user?.id ?? "", selectedBet.id, selectedBet.address);
|
||||
const url = EXPLORER_TX_TEMPLATE.replace("{address}", tx);
|
||||
|
||||
if (tx.length > 5) {
|
||||
toast.success("Joined game successfully!", {
|
||||
action: {
|
||||
label: "View TX",
|
||||
onClick: () => window.open(url, "_blank"),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
toast.error("Failed to join this game");
|
||||
}
|
||||
|
||||
setSelectedBet(null); // Close modal
|
||||
};
|
||||
|
||||
// Function to fetch open bets
|
||||
const updateBets = async () => {
|
||||
let wallet = wallets[0];
|
||||
wallets.forEach((_wallet) => {
|
||||
|
|
@ -19,29 +53,29 @@ export default function YourGames() {
|
|||
wallet = _wallet;
|
||||
}
|
||||
});
|
||||
const bets: Bet[] = await fetchOpenBets(wallet);
|
||||
const filteredBets = (bets.filter((bet) => bet.owner !== wallet.address));
|
||||
|
||||
const filteredBets = bets.filter((bet) => bet.owner !== wallet.address);
|
||||
const enrichedBets = await Promise.all(
|
||||
filteredBets.map(async (bet) => {
|
||||
const ownerProfile = await fetchUserById(bet.owner_id);
|
||||
return {
|
||||
...bet,
|
||||
ownerProfile, // contains {username, x_profile_url, etc.}
|
||||
ownerProfile,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
setMyBets(enrichedBets);
|
||||
setLoading(false);
|
||||
console.log(`Got ${bets.length} bets`);
|
||||
}
|
||||
// Auto-refresh every 10 seconds
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!ready) return;
|
||||
updateBets();
|
||||
const interval = setInterval(updateBets, 10000); // Refresh every 10s
|
||||
|
||||
return () => clearInterval(interval); // Cleanup on unmount
|
||||
}, [ready]);
|
||||
const interval = setInterval(updateBets, 10000);
|
||||
return () => clearInterval(interval);
|
||||
}, [bets]);
|
||||
|
||||
return (
|
||||
<section className="py-16 px-6">
|
||||
|
|
@ -49,20 +83,20 @@ export default function YourGames() {
|
|||
|
||||
{loading ? (
|
||||
<p className="text-gray-400">Loading Open games...</p>
|
||||
) :
|
||||
myBets.length === 0 ? <></> : (
|
||||
) : myBets.length === 0 ? (
|
||||
<p className="text-gray-400">No open games available</p>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{myBets.map((bet) => {
|
||||
console.log(`Finding game for the id ${bet.id}`)
|
||||
const game = games.find((g) => g.id === bet.id); // Match game
|
||||
const game = games.find((g) => g.id === bet.id);
|
||||
if (!game) return null;
|
||||
|
||||
if (!game) return null; // Skip unmatched bets
|
||||
return (
|
||||
<div
|
||||
key={bet.id + bet.owner}
|
||||
key={bet.address}
|
||||
className="relative group bg-[rgb(30,30,30)] rounded-2xl p-2 w-50 overflow-hidden cursor-pointer transition-all duration-300"
|
||||
onClick={() => setSelectedBet(bet)} // Open modal
|
||||
>
|
||||
{/* Game Thumbnail */}
|
||||
<div className="relative w-full h-40 overflow-hidden rounded-xl">
|
||||
<Image
|
||||
src={game.thumbnail}
|
||||
|
|
@ -71,14 +105,11 @@ export default function YourGames() {
|
|||
objectFit="cover"
|
||||
className="transition-all duration-300 group-hover:brightness-50"
|
||||
/>
|
||||
|
||||
{/* Join Overlay */}
|
||||
<div className="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||
<span className="text-white text-xl font-bold">Join</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Game Info */}
|
||||
<div className="mt-4 px-3 text-left">
|
||||
<h3 className="text-lg font-semibold text-white py-2">{game.name}</h3>
|
||||
|
||||
|
|
@ -92,7 +123,6 @@ export default function YourGames() {
|
|||
<p className="text-white">{(bet.wager * 2).toFixed(2)} SOL</p>
|
||||
</div>
|
||||
|
||||
{/* User Info */}
|
||||
{bet.ownerProfile && (
|
||||
<div className="flex items-center gap-2 mt-4">
|
||||
<Image
|
||||
|
|
@ -105,13 +135,41 @@ export default function YourGames() {
|
|||
<p className="text-white text-sm font-mono">{bet.ownerProfile.username}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Modal */}
|
||||
{selectedBet && (
|
||||
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
|
||||
<div className="bg-gray-900 text-white p-6 rounded-lg shadow-lg max-w-sm w-full">
|
||||
<h2 className="text-xl font-bold mb-4">Are you sure to join this bet?</h2>
|
||||
<p><strong>Wager:</strong> {selectedBet.wager} SOL | <strong>Prize:</strong> {(selectedBet.wager * 2).toFixed(2)} SOL</p>
|
||||
<p><strong>Game:</strong> {games.find(g => g.id === selectedBet.id)?.name}</p>
|
||||
<div className="flex items-center mt-3">
|
||||
{selectedBet.ownerProfile && (
|
||||
<>
|
||||
<Image
|
||||
src={selectedBet.ownerProfile.x_profile_url || `https://vps.playpoolstudios.com/duelfi/profile_pics/${selectedBet.ownerProfile.id}.jpg`}
|
||||
alt={selectedBet.ownerProfile.username}
|
||||
width={32}
|
||||
height={32}
|
||||
className="w-8 h-8 rounded-full mr-2"
|
||||
/>
|
||||
<p><strong>Offered by:</strong> {selectedBet.ownerProfile.username}</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-end gap-3 mt-4">
|
||||
<button onClick={() => setSelectedBet(null)} className="bg-gray-700 px-4 py-2 rounded">Cancel</button>
|
||||
<button onClick={handleJoinGame} className="bg-blue-500 px-4 py-2 rounded">Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,14 @@ import Image from "next/image";
|
|||
import { games } from "../data/games";
|
||||
import { FiTrash } from "react-icons/fi";
|
||||
import { useSolanaWallets } from "@privy-io/react-auth";
|
||||
import { fetchOpenBets, closeBet } from "@/shared/solana_helpers";
|
||||
import { closeBet } from "@/shared/solana_helpers";
|
||||
import { Bet } from "../types/Bet";
|
||||
import { toast } from "sonner";
|
||||
import { EXPLORER_TX_TEMPLATE } from "@/data/shared";
|
||||
|
||||
export default function YourGames() {
|
||||
interface GameModalProps {
|
||||
bets: Bet[];
|
||||
}
|
||||
export default function YourGames({bets}:GameModalProps) {
|
||||
const { wallets, ready } = useSolanaWallets();
|
||||
const [myBets, setMyBets] = useState<Bet[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
|
@ -24,7 +26,6 @@ export default function YourGames() {
|
|||
wallet = _wallet;
|
||||
}
|
||||
});
|
||||
const bets: Bet[] = await fetchOpenBets(wallet);
|
||||
setMyBets(bets.filter((bet) => bet.owner === wallet.address));
|
||||
setLoading(false);
|
||||
};
|
||||
|
|
@ -34,7 +35,7 @@ export default function YourGames() {
|
|||
updateBets();
|
||||
const interval = setInterval(updateBets, 10000);
|
||||
return () => clearInterval(interval);
|
||||
}, [ready]);
|
||||
}, [bets]);
|
||||
|
||||
// Handle bet closing
|
||||
const handleCloseBet = async () => {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ export const fetchOpenBets = async (wallets: ConnectedSolanaWallet): Promise<Bet
|
|||
const betAcc = await program.account.betVault.fetch(bet);
|
||||
console.log(betAcc.gameId);
|
||||
return {
|
||||
address: bet.toString(),
|
||||
id: betAcc.gameId,
|
||||
owner: betAcc.owner.toBase58(),
|
||||
owner_id:betAcc.ownerId,
|
||||
|
|
@ -55,8 +56,6 @@ export const fetchOpenBets = async (wallets: ConnectedSolanaWallet): Promise<Bet
|
|||
return [];
|
||||
};
|
||||
|
||||
|
||||
|
||||
export async function closeBet(wallets: ConnectedSolanaWallet, betId: string): Promise<string> {
|
||||
try {
|
||||
const connection = new Connection(CLUSTER_URL);
|
||||
|
|
@ -120,7 +119,6 @@ export const fetchOpenBets = async (wallets: ConnectedSolanaWallet): Promise<Bet
|
|||
return "";
|
||||
}
|
||||
|
||||
|
||||
export async function createBet(wallets:ConnectedSolanaWallet, uid:string,selectedPrice:number,selectedGame:Game):Promise<string>{
|
||||
const connection = new Connection(CLUSTER_URL);
|
||||
const wallet = {
|
||||
|
|
@ -179,6 +177,60 @@ export async function createBet(wallets:ConnectedSolanaWallet, uid:string,select
|
|||
return "";
|
||||
}
|
||||
|
||||
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,
|
||||
signAllTransactions: wallets.signAllTransactions,
|
||||
};
|
||||
const provider = new AnchorProvider(connection, wallet, {
|
||||
preflightCommitment: "confirmed",
|
||||
});
|
||||
|
||||
const program = new Program<Bets>(idl, provider);
|
||||
|
||||
try {
|
||||
const [bet_list_pda] = await PublicKey.findProgramAddress(
|
||||
[Buffer.from("bets_list")],
|
||||
program.programId
|
||||
);
|
||||
const connection = new Connection(CLUSTER_URL, "confirmed");
|
||||
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);
|
||||
|
||||
// Send transaction// Replace with correct RPC endpoint
|
||||
const txId = await connection.sendRawTransaction(signedTx.serialize());
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
export interface Bet {
|
||||
address:string;
|
||||
id: string;
|
||||
owner: string;
|
||||
owner_id:string;
|
||||
|
|
|
|||