duelfi_bets_anchor/tests/bets.ts
2025-05-16 14:32:46 +05:30

417 lines
12 KiB
TypeScript

import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { Bets } from "../target/types/bets";
import { PublicKey, SystemProgram, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID, createMint, createAccount, mintTo, getAccount } from "@solana/spl-token";
import { assert } from "chai";
describe("bets", () => {
// Configure the client to use the local cluster
const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.Bets as Program<Bets>;
// Test accounts
const owner = Keypair.generate();
const joiner = Keypair.generate();
const feeWallet = Keypair.generate();
const ownerReferrer = Keypair.generate();
const joinerReferrer = Keypair.generate();
// SPL Token accounts
let tokenMint: PublicKey;
let ownerTokenAccount: PublicKey;
let joinerTokenAccount: PublicKey;
let betVaultTokenAccount: PublicKey;
let feeWalletTokenAccount: PublicKey;
let ownerReferrerTokenAccount: PublicKey;
let joinerReferrerTokenAccount: PublicKey;
// Program state accounts
let betsList: PublicKey;
let betVault: PublicKey;
const gameId = "test-game-1";
const ownerId = "owner123";
const joinerId = "joiner456";
const wager = new anchor.BN(LAMPORTS_PER_SOL); // 1 SOL or 1 token
const tokenDecimals = 9;
before(async () => {
// Airdrop SOL to test accounts
await provider.connection.requestAirdrop(owner.publicKey, 10 * LAMPORTS_PER_SOL);
await provider.connection.requestAirdrop(joiner.publicKey, 10 * LAMPORTS_PER_SOL);
await provider.connection.requestAirdrop(feeWallet.publicKey, 10 * LAMPORTS_PER_SOL);
await provider.connection.requestAirdrop(ownerReferrer.publicKey, 10 * LAMPORTS_PER_SOL);
await provider.connection.requestAirdrop(joinerReferrer.publicKey, 10 * LAMPORTS_PER_SOL);
// Create SPL token mint
tokenMint = await createMint(
provider.connection,
owner,
owner.publicKey,
null,
tokenDecimals
);
// Create token accounts
ownerTokenAccount = await createAccount(
provider.connection,
owner,
tokenMint,
owner.publicKey
);
joinerTokenAccount = await createAccount(
provider.connection,
joiner,
tokenMint,
joiner.publicKey
);
betVaultTokenAccount = await createAccount(
provider.connection,
owner,
tokenMint,
owner.publicKey
);
feeWalletTokenAccount = await createAccount(
provider.connection,
feeWallet,
tokenMint,
feeWallet.publicKey
);
ownerReferrerTokenAccount = await createAccount(
provider.connection,
ownerReferrer,
tokenMint,
ownerReferrer.publicKey
);
joinerReferrerTokenAccount = await createAccount(
provider.connection,
joinerReferrer,
tokenMint,
joinerReferrer.publicKey
);
// Mint tokens to owner and joiner
await mintTo(
provider.connection,
owner,
tokenMint,
ownerTokenAccount,
owner,
100 * LAMPORTS_PER_SOL
);
await mintTo(
provider.connection,
owner,
tokenMint,
joinerTokenAccount,
owner,
100 * LAMPORTS_PER_SOL
);
});
it("Initializes the bets list", async () => {
[betsList] = PublicKey.findProgramAddressSync(
[Buffer.from("bets_list")],
program.programId
);
await program.methods
.initialize()
.accounts({
betsList,
payer: provider.wallet.publicKey,
systemProgram: SystemProgram.programId,
})
.rpc();
const betsListAccount = await program.account.betsList.fetch(betsList);
assert.ok(betsListAccount.bets.length === 0);
});
describe("Native SOL bets", () => {
it("Creates a bet with native SOL", async () => {
const nonce = new anchor.BN(Date.now());
[betVault] = PublicKey.findProgramAddressSync(
[
Buffer.from("bet_vault"),
owner.publicKey.toBuffer(),
Buffer.from(gameId),
nonce.toArrayLike(Buffer, "le", 8),
],
program.programId
);
await program.methods
.createBet(
wager,
ownerId,
gameId,
nonce,
true, // isNativeSol
null, // tokenMint
0 // tokenDecimals
)
.accounts({
payer: owner.publicKey,
betsList,
betVault,
systemProgram: SystemProgram.programId,
})
.signers([owner])
.rpc();
const betVaultAccount = await program.account.betVault.fetch(betVault);
assert.ok(betVaultAccount.owner.equals(owner.publicKey));
assert.ok(betVaultAccount.ownerId === ownerId);
assert.ok(betVaultAccount.gameId === gameId);
assert.ok(betVaultAccount.wager.eq(wager));
assert.ok(betVaultAccount.isNativeSol === true);
});
it("Joins a bet with native SOL", async () => {
await program.methods
.joinBet(joinerId, gameId)
.accounts({
betVault,
payer: joiner.publicKey,
systemProgram: SystemProgram.programId,
})
.signers([joiner])
.rpc();
const betVaultAccount = await program.account.betVault.fetch(betVault);
assert.ok(betVaultAccount.joiner.equals(joiner.publicKey));
assert.ok(betVaultAccount.joinerId === joinerId);
});
it("Closes a bet with native SOL", async () => {
await program.methods
.closeBet(owner.publicKey, ownerId)
.accounts({
betsList,
betVault,
feeWallet: feeWallet.publicKey,
winner: owner.publicKey,
payer: owner.publicKey,
ownerReferrer: ownerReferrer.publicKey,
joinerReferrer: joinerReferrer.publicKey,
systemProgram: SystemProgram.programId,
})
.signers([owner])
.rpc();
// Verify the bet was removed from the list
const betsListAccount = await program.account.betsList.fetch(betsList);
assert.ok(!betsListAccount.bets.some(bet => bet.equals(betVault)));
});
});
describe("SPL Token bets", () => {
it("Creates a bet with SPL tokens", async () => {
const nonce = new anchor.BN(Date.now());
[betVault] = PublicKey.findProgramAddressSync(
[
Buffer.from("bet_vault"),
owner.publicKey.toBuffer(),
Buffer.from(gameId),
nonce.toArrayLike(Buffer, "le", 8),
],
program.programId
);
await program.methods
.createBet(
wager,
ownerId,
gameId,
nonce,
false, // isNativeSol
tokenMint,
tokenDecimals
)
.accounts({
payer: owner.publicKey,
betsList,
betVault,
systemProgram: SystemProgram.programId,
payerTokenAccount: ownerTokenAccount,
betVaultTokenAccount,
tokenProgram: TOKEN_PROGRAM_ID,
})
.signers([owner])
.rpc();
const betVaultAccount = await program.account.betVault.fetch(betVault);
assert.ok(betVaultAccount.owner.equals(owner.publicKey));
assert.ok(betVaultAccount.ownerId === ownerId);
assert.ok(betVaultAccount.gameId === gameId);
assert.ok(betVaultAccount.wager.eq(wager));
assert.ok(betVaultAccount.isNativeSol === false);
assert.ok(betVaultAccount.tokenMint.equals(tokenMint));
assert.ok(betVaultAccount.tokenDecimals === tokenDecimals);
});
it("Joins a bet with SPL tokens", async () => {
await program.methods
.joinBet(joinerId, gameId)
.accounts({
betVault,
payer: joiner.publicKey,
systemProgram: SystemProgram.programId,
payerTokenAccount: joinerTokenAccount,
betVaultTokenAccount,
tokenProgram: TOKEN_PROGRAM_ID,
})
.signers([joiner])
.rpc();
const betVaultAccount = await program.account.betVault.fetch(betVault);
assert.ok(betVaultAccount.joiner.equals(joiner.publicKey));
assert.ok(betVaultAccount.joinerId === joinerId);
});
it("Closes a bet with SPL tokens", async () => {
await program.methods
.closeBet(owner.publicKey, ownerId)
.accounts({
betsList,
betVault,
feeWallet: feeWallet.publicKey,
winner: owner.publicKey,
payer: owner.publicKey,
ownerReferrer: ownerReferrer.publicKey,
joinerReferrer: joinerReferrer.publicKey,
systemProgram: SystemProgram.programId,
betVaultTokenAccount,
feeWalletTokenAccount,
ownerReferrerTokenAccount,
joinerReferrerTokenAccount,
tokenProgram: TOKEN_PROGRAM_ID,
})
.signers([owner])
.rpc();
// Verify the bet was removed from the list
const betsListAccount = await program.account.betsList.fetch(betsList);
assert.ok(!betsListAccount.bets.some(bet => bet.equals(betVault)));
});
});
describe("Refund functionality", () => {
it("Refunds a native SOL bet", async () => {
// Create a new bet
const nonce = new anchor.BN(Date.now());
[betVault] = PublicKey.findProgramAddressSync(
[
Buffer.from("bet_vault"),
owner.publicKey.toBuffer(),
Buffer.from(gameId),
nonce.toArrayLike(Buffer, "le", 8),
],
program.programId
);
await program.methods
.createBet(
wager,
ownerId,
gameId,
nonce,
true, // isNativeSol
null, // tokenMint
0 // tokenDecimals
)
.accounts({
payer: owner.publicKey,
betsList,
betVault,
systemProgram: SystemProgram.programId,
})
.signers([owner])
.rpc();
// Refund the bet
await program.methods
.refundBet(owner.publicKey)
.accounts({
betsList,
betVault,
owner: owner.publicKey,
payer: owner.publicKey,
systemProgram: SystemProgram.programId,
})
.signers([owner])
.rpc();
// Verify the bet was removed from the list
const betsListAccount = await program.account.betsList.fetch(betsList);
assert.ok(!betsListAccount.bets.some(bet => bet.equals(betVault)));
});
it("Refunds an SPL token bet", async () => {
// Create a new bet
const nonce = new anchor.BN(Date.now());
[betVault] = PublicKey.findProgramAddressSync(
[
Buffer.from("bet_vault"),
owner.publicKey.toBuffer(),
Buffer.from(gameId),
nonce.toArrayLike(Buffer, "le", 8),
],
program.programId
);
await program.methods
.createBet(
wager,
ownerId,
gameId,
nonce,
false, // isNativeSol
tokenMint,
tokenDecimals
)
.accounts({
payer: owner.publicKey,
betsList,
betVault,
systemProgram: SystemProgram.programId,
payerTokenAccount: ownerTokenAccount,
betVaultTokenAccount,
tokenProgram: TOKEN_PROGRAM_ID,
})
.signers([owner])
.rpc();
// Refund the bet
await program.methods
.refundBet(owner.publicKey)
.accounts({
betsList,
betVault,
owner: owner.publicKey,
payer: owner.publicKey,
systemProgram: SystemProgram.programId,
betVaultTokenAccount,
joinerTokenAccount,
tokenProgram: TOKEN_PROGRAM_ID,
})
.signers([owner])
.rpc();
// Verify the bet was removed from the list
const betsListAccount = await program.account.betsList.fetch(betsList);
assert.ok(!betsListAccount.bets.some(bet => bet.equals(betVault)));
});
});
});