|
@@ -1,32 +1,28 @@
|
|
|
-import { randomBytes } from "node:crypto";
|
|
|
-import * as anchor from "@coral-xyz/anchor";
|
|
|
-import { BN, type Program } from "@coral-xyz/anchor";
|
|
|
-import {
|
|
|
- TOKEN_2022_PROGRAM_ID,
|
|
|
- type TOKEN_PROGRAM_ID,
|
|
|
- getAssociatedTokenAddressSync,
|
|
|
-} from "@solana/spl-token";
|
|
|
-import { LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js";
|
|
|
-import { assert } from "chai";
|
|
|
-import type { Escrow } from "../target/types/escrow";
|
|
|
-
|
|
|
-import {
|
|
|
- confirmTransaction,
|
|
|
- createAccountsMintsAndTokenAccounts,
|
|
|
- makeKeypairs,
|
|
|
-} from "@solana-developers/helpers";
|
|
|
+import { randomBytes } from 'node:crypto';
|
|
|
+import * as anchor from '@coral-xyz/anchor';
|
|
|
+import { BN, type Program } from '@coral-xyz/anchor';
|
|
|
+import { TOKEN_2022_PROGRAM_ID, type TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync } from '@solana/spl-token';
|
|
|
+import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
|
|
|
+import { assert } from 'chai';
|
|
|
+import type { Escrow } from '../target/types/escrow';
|
|
|
+
|
|
|
+import { confirmTransaction, createAccountsMintsAndTokenAccounts, makeKeypairs } from '@solana-developers/helpers';
|
|
|
|
|
|
// Work on both Token Program and new Token Extensions Program
|
|
|
-const TOKEN_PROGRAM: typeof TOKEN_2022_PROGRAM_ID | typeof TOKEN_PROGRAM_ID =
|
|
|
- TOKEN_2022_PROGRAM_ID;
|
|
|
+const TOKEN_PROGRAM: typeof TOKEN_2022_PROGRAM_ID | typeof TOKEN_PROGRAM_ID = TOKEN_2022_PROGRAM_ID;
|
|
|
|
|
|
const SECONDS = 1000;
|
|
|
|
|
|
+// Tests must complete within half this time otherwise
|
|
|
+// they are marked as slow. Since Anchor involves a little
|
|
|
+// network IO, these tests usually take about 15 seconds.
|
|
|
+const ANCHOR_SLOW_TEST_THRESHOLD = 40 * SECONDS;
|
|
|
+
|
|
|
const getRandomBigNumber = (size = 8) => {
|
|
|
return new BN(randomBytes(size));
|
|
|
};
|
|
|
|
|
|
-describe("escrow", async () => {
|
|
|
+describe('escrow', async () => {
|
|
|
// Use the cluster and the keypair from Anchor.toml
|
|
|
const provider = anchor.AnchorProvider.env();
|
|
|
anchor.setProvider(provider);
|
|
@@ -54,80 +50,67 @@ describe("escrow", async () => {
|
|
|
const tokenAOfferedAmount = new BN(1_000_000);
|
|
|
const tokenBWantedAmount = new BN(1_000_000);
|
|
|
|
|
|
- before(
|
|
|
- "Creates Alice and Bob accounts, 2 token mints, and associated token accounts for both tokens for both users",
|
|
|
- async () => {
|
|
|
- const usersMintsAndTokenAccounts =
|
|
|
- await createAccountsMintsAndTokenAccounts(
|
|
|
- [
|
|
|
- // Alice's token balances
|
|
|
- [
|
|
|
- // 1_000_000_000 of token A
|
|
|
- 1_000_000_000,
|
|
|
- // 0 of token B
|
|
|
- 0,
|
|
|
- ],
|
|
|
- // Bob's token balances
|
|
|
- [
|
|
|
- // 0 of token A
|
|
|
- 0,
|
|
|
- // 1_000_000_000 of token B
|
|
|
- 1_000_000_000,
|
|
|
- ],
|
|
|
- ],
|
|
|
- 1 * LAMPORTS_PER_SOL,
|
|
|
- connection,
|
|
|
- payer
|
|
|
- );
|
|
|
-
|
|
|
- const users = usersMintsAndTokenAccounts.users;
|
|
|
- alice = users[0];
|
|
|
- bob = users[1];
|
|
|
-
|
|
|
- const mints = usersMintsAndTokenAccounts.mints;
|
|
|
- tokenMintA = mints[0];
|
|
|
- tokenMintB = mints[1];
|
|
|
-
|
|
|
- const tokenAccounts = usersMintsAndTokenAccounts.tokenAccounts;
|
|
|
-
|
|
|
- const aliceTokenAccountA = tokenAccounts[0][0];
|
|
|
- const aliceTokenAccountB = tokenAccounts[0][1];
|
|
|
-
|
|
|
- const bobTokenAccountA = tokenAccounts[1][0];
|
|
|
- const bobTokenAccountB = tokenAccounts[1][1];
|
|
|
-
|
|
|
- // Save the accounts for later use
|
|
|
- accounts.maker = alice.publicKey;
|
|
|
- accounts.taker = bob.publicKey;
|
|
|
- accounts.tokenMintA = tokenMintA.publicKey;
|
|
|
- accounts.makerTokenAccountA = aliceTokenAccountA;
|
|
|
- accounts.takerTokenAccountA = bobTokenAccountA;
|
|
|
- accounts.tokenMintB = tokenMintB.publicKey;
|
|
|
- accounts.makerTokenAccountB = aliceTokenAccountB;
|
|
|
- accounts.takerTokenAccountB = bobTokenAccountB;
|
|
|
- }
|
|
|
- );
|
|
|
-
|
|
|
- it("Puts the tokens Alice offers into the vault when Alice makes an offer", async () => {
|
|
|
+ before('Creates Alice and Bob accounts, 2 token mints, and associated token accounts for both tokens for both users', async () => {
|
|
|
+ const usersMintsAndTokenAccounts = await createAccountsMintsAndTokenAccounts(
|
|
|
+ [
|
|
|
+ // Alice's token balances
|
|
|
+ [
|
|
|
+ // 1_000_000_000 of token A
|
|
|
+ 1_000_000_000,
|
|
|
+ // 0 of token B
|
|
|
+ 0,
|
|
|
+ ],
|
|
|
+ // Bob's token balances
|
|
|
+ [
|
|
|
+ // 0 of token A
|
|
|
+ 0,
|
|
|
+ // 1_000_000_000 of token B
|
|
|
+ 1_000_000_000,
|
|
|
+ ],
|
|
|
+ ],
|
|
|
+ 1 * LAMPORTS_PER_SOL,
|
|
|
+ connection,
|
|
|
+ payer,
|
|
|
+ );
|
|
|
+
|
|
|
+ const users = usersMintsAndTokenAccounts.users;
|
|
|
+ alice = users[0];
|
|
|
+ bob = users[1];
|
|
|
+
|
|
|
+ const mints = usersMintsAndTokenAccounts.mints;
|
|
|
+ tokenMintA = mints[0];
|
|
|
+ tokenMintB = mints[1];
|
|
|
+
|
|
|
+ const tokenAccounts = usersMintsAndTokenAccounts.tokenAccounts;
|
|
|
+
|
|
|
+ const aliceTokenAccountA = tokenAccounts[0][0];
|
|
|
+ const aliceTokenAccountB = tokenAccounts[0][1];
|
|
|
+
|
|
|
+ const bobTokenAccountA = tokenAccounts[1][0];
|
|
|
+ const bobTokenAccountB = tokenAccounts[1][1];
|
|
|
+
|
|
|
+ // Save the accounts for later use
|
|
|
+ accounts.maker = alice.publicKey;
|
|
|
+ accounts.taker = bob.publicKey;
|
|
|
+ accounts.tokenMintA = tokenMintA.publicKey;
|
|
|
+ accounts.makerTokenAccountA = aliceTokenAccountA;
|
|
|
+ accounts.takerTokenAccountA = bobTokenAccountA;
|
|
|
+ accounts.tokenMintB = tokenMintB.publicKey;
|
|
|
+ accounts.makerTokenAccountB = aliceTokenAccountB;
|
|
|
+ accounts.takerTokenAccountB = bobTokenAccountB;
|
|
|
+ });
|
|
|
+
|
|
|
+ it('Puts the tokens Alice offers into the vault when Alice makes an offer', async () => {
|
|
|
// Pick a random ID for the offer we'll make
|
|
|
const offerId = getRandomBigNumber();
|
|
|
|
|
|
// Then determine the account addresses we'll use for the offer and the vault
|
|
|
const offer = PublicKey.findProgramAddressSync(
|
|
|
- [
|
|
|
- Buffer.from("offer"),
|
|
|
- accounts.maker.toBuffer(),
|
|
|
- offerId.toArrayLike(Buffer, "le", 8),
|
|
|
- ],
|
|
|
- program.programId
|
|
|
+ [Buffer.from('offer'), accounts.maker.toBuffer(), offerId.toArrayLike(Buffer, 'le', 8)],
|
|
|
+ program.programId,
|
|
|
)[0];
|
|
|
|
|
|
- const vault = getAssociatedTokenAddressSync(
|
|
|
- accounts.tokenMintA,
|
|
|
- offer,
|
|
|
- true,
|
|
|
- TOKEN_PROGRAM
|
|
|
- );
|
|
|
+ const vault = getAssociatedTokenAddressSync(accounts.tokenMintA, offer, true, TOKEN_PROGRAM);
|
|
|
|
|
|
accounts.offer = offer;
|
|
|
accounts.vault = vault;
|
|
@@ -152,7 +135,7 @@ describe("escrow", async () => {
|
|
|
assert(offerAccount.tokenMintA.equals(accounts.tokenMintA));
|
|
|
assert(offerAccount.tokenMintB.equals(accounts.tokenMintB));
|
|
|
assert(offerAccount.tokenBWantedAmount.eq(tokenBWantedAmount));
|
|
|
- }).slow(60 * SECONDS);
|
|
|
+ }).slow(ANCHOR_SLOW_TEST_THRESHOLD);
|
|
|
|
|
|
it("Puts the tokens from the vault into Bob's account, and gives Alice Bob's tokens, when Bob takes an offer", async () => {
|
|
|
const transactionSignature = await program.methods
|
|
@@ -165,20 +148,14 @@ describe("escrow", async () => {
|
|
|
|
|
|
// Check the offered tokens are now in Bob's account
|
|
|
// (note: there is no before balance as Bob didn't have any offered tokens before the transaction)
|
|
|
- const bobTokenAccountBalanceAfterResponse =
|
|
|
- await connection.getTokenAccountBalance(accounts.takerTokenAccountA);
|
|
|
- const bobTokenAccountBalanceAfter = new BN(
|
|
|
- bobTokenAccountBalanceAfterResponse.value.amount
|
|
|
- );
|
|
|
+ const bobTokenAccountBalanceAfterResponse = await connection.getTokenAccountBalance(accounts.takerTokenAccountA);
|
|
|
+ const bobTokenAccountBalanceAfter = new BN(bobTokenAccountBalanceAfterResponse.value.amount);
|
|
|
assert(bobTokenAccountBalanceAfter.eq(tokenAOfferedAmount));
|
|
|
|
|
|
// Check the wanted tokens are now in Alice's account
|
|
|
// (note: there is no before balance as Alice didn't have any wanted tokens before the transaction)
|
|
|
- const aliceTokenAccountBalanceAfterResponse =
|
|
|
- await connection.getTokenAccountBalance(accounts.makerTokenAccountB);
|
|
|
- const aliceTokenAccountBalanceAfter = new BN(
|
|
|
- aliceTokenAccountBalanceAfterResponse.value.amount
|
|
|
- );
|
|
|
+ const aliceTokenAccountBalanceAfterResponse = await connection.getTokenAccountBalance(accounts.makerTokenAccountB);
|
|
|
+ const aliceTokenAccountBalanceAfter = new BN(aliceTokenAccountBalanceAfterResponse.value.amount);
|
|
|
assert(aliceTokenAccountBalanceAfter.eq(tokenBWantedAmount));
|
|
|
- }).slow(60 * SECONDS);
|
|
|
+ }).slow(ANCHOR_SLOW_TEST_THRESHOLD);
|
|
|
});
|