From 6779da9882a398090e6c63f2c71e14d335a94dc5 Mon Sep 17 00:00:00 2001 From: Sewmina Dilshan Date: Sun, 18 May 2025 08:46:11 +0530 Subject: [PATCH] usdt --- src/bets.json | 178 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/bets.ts | 178 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/close.ts | 77 +++++++++++++++------- src/create.ts | 90 ++++++++++++++++++++++--- src/get.ts | 5 +- 5 files changed, 485 insertions(+), 43 deletions(-) diff --git a/src/bets.json b/src/bets.json index 4547ebc..5cf0a76 100644 --- a/src/bets.json +++ b/src/bets.json @@ -1,5 +1,5 @@ { - "address": "JAf3ZkQ469okXAzA6BKJeKBb9ZkCtZanULaUsapskoyn", + "address": "Haj94DF925qNRgcoRwQfNsVLKgSmFhG4bjgtvusMkkpD", "metadata": { "name": "bets", "version": "0.1.0", @@ -41,15 +41,53 @@ "writable": true, "signer": true }, + { + "name": "owner_referrer", + "writable": true, + "optional": true + }, + { + "name": "joiner_referrer", + "writable": true, + "optional": true + }, { "name": "system_program", "address": "11111111111111111111111111111111" + }, + { + "name": "bet_vault_token_account", + "writable": true, + "optional": true + }, + { + "name": "fee_wallet_token_account", + "writable": true, + "optional": true + }, + { + "name": "owner_referrer_token_account", + "writable": true, + "optional": true + }, + { + "name": "joiner_referrer_token_account", + "writable": true, + "optional": true + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } ], "args": [ { "name": "winner", "type": "pubkey" + }, + { + "name": "userid", + "type": "string" } ] }, @@ -112,6 +150,20 @@ { "name": "system_program", "address": "11111111111111111111111111111111" + }, + { + "name": "payer_token_account", + "writable": true, + "optional": true + }, + { + "name": "bet_vault_token_account", + "writable": true, + "optional": true + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } ], "args": [ @@ -130,6 +182,20 @@ { "name": "nonce", "type": "u64" + }, + { + "name": "is_native_sol", + "type": "bool" + }, + { + "name": "token_mint", + "type": { + "option": "pubkey" + } + }, + { + "name": "token_decimals", + "type": "u8" } ] }, @@ -205,6 +271,20 @@ { "name": "system_program", "address": "11111111111111111111111111111111" + }, + { + "name": "payer_token_account", + "writable": true, + "optional": true + }, + { + "name": "bet_vault_token_account", + "writable": true, + "optional": true + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } ], "args": [ @@ -217,6 +297,62 @@ "type": "string" } ] + }, + { + "name": "refund_bet", + "discriminator": [ + 209, + 182, + 226, + 96, + 55, + 121, + 83, + 183 + ], + "accounts": [ + { + "name": "bets_list", + "writable": true + }, + { + "name": "bet_vault", + "writable": true + }, + { + "name": "owner", + "writable": true + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + }, + { + "name": "bet_vault_token_account", + "writable": true, + "optional": true + }, + { + "name": "joiner_token_account", + "writable": true, + "optional": true + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + ], + "args": [ + { + "name": "owner", + "type": "pubkey" + } + ] } ], "accounts": [ @@ -250,8 +386,28 @@ "errors": [ { "code": 6000, - "name": "CustomError", - "msg": "Custom error message" + "name": "BetNotFilled", + "msg": "Bet is not filled yet!" + }, + { + "code": 6001, + "name": "BetAlreadyFilled", + "msg": "Bet is already filled" + }, + { + "code": 6002, + "name": "InvalidWinner", + "msg": "The winner must be either the owner or the joiner of the bet." + }, + { + "code": 6003, + "name": "InvalidFeeCollector", + "msg": "Please use the correct fee collector address" + }, + { + "code": 6004, + "name": "JoinerAccountNotProvided", + "msg": "" } ], "types": [ @@ -283,6 +439,20 @@ { "name": "wager", "type": "u64" + }, + { + "name": "is_native_sol", + "type": "bool" + }, + { + "name": "token_mint", + "type": { + "option": "pubkey" + } + }, + { + "name": "token_decimals", + "type": "u8" } ] } @@ -306,7 +476,7 @@ { "name": "FEE_COLLECTOR", "type": "string", - "value": "\"cocD4r4yNpHxPq7CzUebxEMyLki3X4d2Y3HcTX5ptUc\"" + "value": "\"9esrj2X33pr5og6fdkDMjaW6fdnnb9hT1cWshamxTdL4\"" }, { "name": "SEED", diff --git a/src/bets.ts b/src/bets.ts index 76e79cc..3e55451 100644 --- a/src/bets.ts +++ b/src/bets.ts @@ -5,7 +5,7 @@ * IDL can be found at `target/idl/bets.json`. */ export type Bets = { - "address": "JAf3ZkQ469okXAzA6BKJeKBb9ZkCtZanULaUsapskoyn", + "address": "Haj94DF925qNRgcoRwQfNsVLKgSmFhG4bjgtvusMkkpD", "metadata": { "name": "bets", "version": "0.1.0", @@ -47,15 +47,53 @@ export type Bets = { "writable": true, "signer": true }, + { + "name": "ownerReferrer", + "writable": true, + "optional": true + }, + { + "name": "joinerReferrer", + "writable": true, + "optional": true + }, { "name": "systemProgram", "address": "11111111111111111111111111111111" + }, + { + "name": "betVaultTokenAccount", + "writable": true, + "optional": true + }, + { + "name": "feeWalletTokenAccount", + "writable": true, + "optional": true + }, + { + "name": "ownerReferrerTokenAccount", + "writable": true, + "optional": true + }, + { + "name": "joinerReferrerTokenAccount", + "writable": true, + "optional": true + }, + { + "name": "tokenProgram", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } ], "args": [ { "name": "winner", "type": "pubkey" + }, + { + "name": "userid", + "type": "string" } ] }, @@ -118,6 +156,20 @@ export type Bets = { { "name": "systemProgram", "address": "11111111111111111111111111111111" + }, + { + "name": "payerTokenAccount", + "writable": true, + "optional": true + }, + { + "name": "betVaultTokenAccount", + "writable": true, + "optional": true + }, + { + "name": "tokenProgram", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } ], "args": [ @@ -136,6 +188,20 @@ export type Bets = { { "name": "nonce", "type": "u64" + }, + { + "name": "isNativeSol", + "type": "bool" + }, + { + "name": "tokenMint", + "type": { + "option": "pubkey" + } + }, + { + "name": "tokenDecimals", + "type": "u8" } ] }, @@ -211,6 +277,20 @@ export type Bets = { { "name": "systemProgram", "address": "11111111111111111111111111111111" + }, + { + "name": "payerTokenAccount", + "writable": true, + "optional": true + }, + { + "name": "betVaultTokenAccount", + "writable": true, + "optional": true + }, + { + "name": "tokenProgram", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } ], "args": [ @@ -223,6 +303,62 @@ export type Bets = { "type": "string" } ] + }, + { + "name": "refundBet", + "discriminator": [ + 209, + 182, + 226, + 96, + 55, + 121, + 83, + 183 + ], + "accounts": [ + { + "name": "betsList", + "writable": true + }, + { + "name": "betVault", + "writable": true + }, + { + "name": "owner", + "writable": true + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + }, + { + "name": "betVaultTokenAccount", + "writable": true, + "optional": true + }, + { + "name": "joinerTokenAccount", + "writable": true, + "optional": true + }, + { + "name": "tokenProgram", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + ], + "args": [ + { + "name": "owner", + "type": "pubkey" + } + ] } ], "accounts": [ @@ -256,8 +392,28 @@ export type Bets = { "errors": [ { "code": 6000, - "name": "customError", - "msg": "Custom error message" + "name": "betNotFilled", + "msg": "Bet is not filled yet!" + }, + { + "code": 6001, + "name": "betAlreadyFilled", + "msg": "Bet is already filled" + }, + { + "code": 6002, + "name": "invalidWinner", + "msg": "The winner must be either the owner or the joiner of the bet." + }, + { + "code": 6003, + "name": "invalidFeeCollector", + "msg": "Please use the correct fee collector address" + }, + { + "code": 6004, + "name": "joinerAccountNotProvided", + "msg": "" } ], "types": [ @@ -289,6 +445,20 @@ export type Bets = { { "name": "wager", "type": "u64" + }, + { + "name": "isNativeSol", + "type": "bool" + }, + { + "name": "tokenMint", + "type": { + "option": "pubkey" + } + }, + { + "name": "tokenDecimals", + "type": "u8" } ] } @@ -312,7 +482,7 @@ export type Bets = { { "name": "feeCollector", "type": "string", - "value": "\"cocD4r4yNpHxPq7CzUebxEMyLki3X4d2Y3HcTX5ptUc\"" + "value": "\"9esrj2X33pr5og6fdkDMjaW6fdnnb9hT1cWshamxTdL4\"" }, { "name": "seed", diff --git a/src/close.ts b/src/close.ts index 76fcaf3..60e039b 100644 --- a/src/close.ts +++ b/src/close.ts @@ -5,39 +5,68 @@ import { clusterUrl, cocSk, getRandomInt, testerSk } from "./shared"; const IDL = require('./bets.json'); async function close(){ - const keypair = Keypair.fromSecretKey(Uint8Array.from(testerSk)); + const keypair = Keypair.fromSecretKey(Uint8Array.from(cocSk)); const cocKeypair = Keypair.fromSecretKey(Uint8Array.from(cocSk)); - const connection = new Connection(clusterUrl); - const provider = new AnchorProvider(connection, new Wallet(keypair)); - const program:Program = new Program(IDL,provider); + const connection = new Connection(clusterUrl, { + commitment: 'confirmed', + confirmTransactionInitialTimeout: 60000 + }); + const provider = new AnchorProvider(connection, new Wallet(keypair), { + commitment: 'confirmed', + preflightCommitment: 'confirmed', + }); + const program:Program = new Program(IDL, provider); let solBalance = (await connection.getBalance(keypair.publicKey))/ LAMPORTS_PER_SOL; console.log(`Tester ${keypair.publicKey} has ${solBalance} SOL`); const [bet_list_pda] = await PublicKey.findProgramAddress([Buffer.from("bets_list")], program.programId); console.log(`Bets list PDA : ${bet_list_pda}`); - const bet_list = await program.account.betsList.fetch(bet_list_pda); - for (const bet of bet_list.bets) { - const betAcc = await program.account.betVault.fetch(bet); - const winner = betAcc.owner; - console.log(`Closing ${bet}`); - const tx = await program.methods.closeBet(winner).accounts({ - betVault: bet, - betsList: bet_list_pda, - winner: winner, - feeWallet: cocKeypair.publicKey - }).rpc(); - console.log(`tx: ${tx}`); - const hash = await connection.confirmTransaction(tx); - console.log(`tx complete: ${hash}`); - solBalance = (await connection.getBalance(keypair.publicKey))/ LAMPORTS_PER_SOL; - - console.log(`Tester ${keypair.publicKey} has ${solBalance} SOL`); - + try { + const bet_list = await program.account.betsList.fetch(bet_list_pda); + for (const bet of bet_list.bets) { + try { + const betAcc = await program.account.betVault.fetch(bet); + const winner = betAcc.owner; + console.log(`Closing ${bet}`); + + const tx = await program.methods.closeBet(winner, betAcc.ownerId).accounts({ + betVault: bet, + betsList: bet_list_pda, + winner: winner, + feeWallet: new PublicKey("9esrj2X33pr5og6fdkDMjaW6fdnnb9hT1cWshamxTdL4"), + ownerReferrer: new PublicKey("BaTgUMPsk8fZoEMwig81Pw1KHmPpoYt31oiR5Qr2c8XR"), + joinerReferrer: new PublicKey("9esrj2X33pr5og6fdkDMjaW6fdnnb9hT1cWshamxTdL4"), + }).rpc({ + skipPreflight: false, + maxRetries: 3 + }); + console.log(`tx: ${tx}`); + + const confirmation = await connection.confirmTransaction(tx); + + if (confirmation.value.err) { + console.error(`Transaction failed: ${confirmation.value.err}`); + continue; + } + + console.log(`tx complete: ${tx}`); + solBalance = (await connection.getBalance(keypair.publicKey))/ LAMPORTS_PER_SOL; + console.log(`Tester ${keypair.publicKey} has ${solBalance} SOL`); + } catch (err) { + console.error(`Error processing bet ${bet}:`, err); + continue; + } + } + } catch (err) { + console.error('Error fetching bet list:', err); + throw err; } - } -close(); \ No newline at end of file +close().catch(err => { + console.error('Fatal error:', err); + process.exit(1); +}); \ No newline at end of file diff --git a/src/create.ts b/src/create.ts index 9720159..ac5226e 100644 --- a/src/create.ts +++ b/src/create.ts @@ -1,37 +1,107 @@ -import { Connection, PublicKey, Keypair, clusterApiUrl, LAMPORTS_PER_SOL } from "@solana/web3.js"; +import { Connection, PublicKey, Keypair, clusterApiUrl, LAMPORTS_PER_SOL, SystemProgram, Transaction } from "@solana/web3.js"; import { Bets } from "./bets"; import { AnchorProvider, BN, Program, Wallet } from "@coral-xyz/anchor"; import { clusterUrl, cocSk, getRandomInt, testerSk } from "./shared"; +import { createAssociatedTokenAccountInstruction, getAccount, getAssociatedTokenAddress, getAssociatedTokenAddressSync, TOKEN_PROGRAM_ID } from "@solana/spl-token"; const IDL = require('./bets.json'); -async function create(){ +async function create() { const keypair = Keypair.fromSecretKey(Uint8Array.from(testerSk)); const connection = new Connection(clusterUrl); const provider = new AnchorProvider(connection, new Wallet(keypair)); - const program:Program = new Program(IDL,provider); + const program: Program = new Program(IDL, provider); - let solBalance = (await connection.getBalance(keypair.publicKey))/ LAMPORTS_PER_SOL; + // Check and request SOL balance if needed + let solBalance = (await connection.getBalance(keypair.publicKey)) / LAMPORTS_PER_SOL; console.log(`Tester ${keypair.publicKey} has ${solBalance} SOL`); - if(solBalance <= 1){ + if (solBalance <= 1) { console.log("Requesting airdrop due to insufficient funds"); - try{ + try { await connection.requestAirdrop(keypair.publicKey, 5); - }catch{ + } catch { console.log("Airdrop failed"); } solBalance = await connection.getBalance(keypair.publicKey); console.log(`Tester now has ${solBalance} SOL`); } - const [bet_list_pda] = await PublicKey.findProgramAddress([Buffer.from("bets_list")], program.programId); + // Get bets list PDA + const [bet_list_pda] = await PublicKey.findProgramAddress( + [Buffer.from("bets_list")], + program.programId + ); console.log(`Bets list PDA : ${bet_list_pda}`); + const nonce = getRandomInt(100000000000); - const tx = await program.methods.createBet(new BN(100000000),"tester", "tetris", new BN(nonce)).accounts({ + + // Find bet vault PDA + const [bet_vault_pda] = await PublicKey.findProgramAddress( + [ + Buffer.from("bet_vault"), + keypair.publicKey.toBuffer(), + Buffer.from("tetris"), + new BN(nonce).toArrayLike(Buffer, "le", 8) + ], + program.programId + ); + + // For native SOL bet + const isNativeSol = false; + const tokenMint = new PublicKey("8iFREvVdmLKxVeibpC5VLRr1S6X5dm7gYR3VCU1wpump"); + + // Create the bet vault token account if it doesn't exist + let betVaultTokenAccount; + if (!isNativeSol) { + // For SPL tokens, create the token account + betVaultTokenAccount = await getAssociatedTokenAddress( + tokenMint, + bet_vault_pda, + true // allowOwnerOffCurve = true because it's a PDA + ); + + // Create the token account if it doesn't exist + try { + await getAccount(connection, betVaultTokenAccount); + } catch { + const createAtaIx = createAssociatedTokenAccountInstruction( + keypair.publicKey, // payer + betVaultTokenAccount, // ata + bet_vault_pda, // owner + tokenMint // mint + ); + + const tx = await connection.sendTransaction( + new Transaction().add(createAtaIx), + [keypair] + ); + await connection.confirmTransaction(tx); + } + } + + // Get payer's token account + const payerTokenAccount = await getAssociatedTokenAddress( + tokenMint, + keypair.publicKey + ); + + // Create the bet + const tx = await program.methods.createBet( + new BN(100000000), + "tester", + "tetris", + new BN(nonce), + isNativeSol, + tokenMint, + 9 // decimals for SOL + ).accounts({ betsList: bet_list_pda, + payer: keypair.publicKey, + payerTokenAccount: isNativeSol ? null : payerTokenAccount, + betVaultTokenAccount: isNativeSol ? null : betVaultTokenAccount, }).rpc(); + console.log(`create tx : ${tx}`); await connection.confirmTransaction(tx); - console.log(`tx complete`); } diff --git a/src/get.ts b/src/get.ts index 7ecea3d..c15658f 100644 --- a/src/get.ts +++ b/src/get.ts @@ -25,7 +25,10 @@ async function get(){ owner: betAcc.owner + " : " + betAcc.ownerId, joiner: betAcc.joiner + " : " + betAcc.joinerId, wager: betAcc.wager.toNumber() + `: ${betAcc.wager.toNumber() / LAMPORTS_PER_SOL}SOL`, - balance: solBalance + " SOL" + balance: solBalance, + is_native_sol: betAcc.isNativeSol, + token_mint: betAcc.tokenMint, + token_decimals: betAcc.tokenDecimals, }); }) }