417 lines
12 KiB
TypeScript
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)));
|
|
});
|
|
});
|
|
});
|