|
@@ -1,6 +1,6 @@
|
|
|
-import { randomBytes } from "node:crypto";
|
|
|
-import * as anchor from "@coral-xyz/anchor";
|
|
|
-import { BN, type Program } from "@coral-xyz/anchor";
|
|
|
+import { randomBytes } from 'node:crypto';
|
|
|
+import * as anchor from '@coral-xyz/anchor';
|
|
|
+import { BN, type Program } from '@coral-xyz/anchor';
|
|
|
import {
|
|
|
MINT_SIZE,
|
|
|
TOKEN_2022_PROGRAM_ID,
|
|
@@ -10,27 +10,20 @@ import {
|
|
|
createMintToInstruction,
|
|
|
getAssociatedTokenAddressSync,
|
|
|
getMinimumBalanceForRentExemptMint,
|
|
|
-} from "@solana/spl-token";
|
|
|
-import {
|
|
|
- LAMPORTS_PER_SOL,
|
|
|
- PublicKey,
|
|
|
- SystemProgram,
|
|
|
- Transaction,
|
|
|
- type TransactionInstruction,
|
|
|
-} from "@solana/web3.js";
|
|
|
-import { assert } from "chai";
|
|
|
-import type { Escrow } from "../target/types/escrow";
|
|
|
+} from '@solana/spl-token';
|
|
|
+import { LAMPORTS_PER_SOL, PublicKey, SystemProgram, Transaction, type TransactionInstruction } from '@solana/web3.js';
|
|
|
+import { assert } from 'chai';
|
|
|
+import type { Escrow } from '../target/types/escrow';
|
|
|
|
|
|
-import { confirmTransaction, makeKeypairs } from "@solana-developers/helpers";
|
|
|
+import { confirmTransaction, makeKeypairs } from '@solana-developers/helpers';
|
|
|
|
|
|
-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 getRandomBigNumber = (size = 8) => {
|
|
|
return new BN(randomBytes(size));
|
|
|
};
|
|
|
|
|
|
-describe("escrow", async () => {
|
|
|
+describe('escrow', async () => {
|
|
|
anchor.setProvider(anchor.AnchorProvider.env());
|
|
|
|
|
|
const provider = anchor.getProvider();
|
|
@@ -46,112 +39,66 @@ describe("escrow", async () => {
|
|
|
|
|
|
const [alice, bob, tokenMintA, tokenMintB] = makeKeypairs(4);
|
|
|
|
|
|
- before(
|
|
|
- "Creates Alice and Bob accounts, 2 token mints, and associated token accounts for both tokens for both users",
|
|
|
- async () => {
|
|
|
- const [
|
|
|
- aliceTokenAccountA,
|
|
|
- aliceTokenAccountB,
|
|
|
- bobTokenAccountA,
|
|
|
- bobTokenAccountB,
|
|
|
- ] = [alice, bob].flatMap((keypair) =>
|
|
|
- [tokenMintA, tokenMintB].map((mint) =>
|
|
|
- getAssociatedTokenAddressSync(
|
|
|
- mint.publicKey,
|
|
|
- keypair.publicKey,
|
|
|
- false,
|
|
|
- TOKEN_PROGRAM
|
|
|
- )
|
|
|
- )
|
|
|
- );
|
|
|
-
|
|
|
- // Airdrops to users, and creates two tokens mints 'A' and 'B'"
|
|
|
- const minimumLamports = await getMinimumBalanceForRentExemptMint(
|
|
|
- connection
|
|
|
- );
|
|
|
-
|
|
|
- const sendSolInstructions: Array<TransactionInstruction> = [
|
|
|
- alice,
|
|
|
- bob,
|
|
|
- ].map((account) =>
|
|
|
- SystemProgram.transfer({
|
|
|
- fromPubkey: provider.publicKey,
|
|
|
- toPubkey: account.publicKey,
|
|
|
- lamports: 10 * LAMPORTS_PER_SOL,
|
|
|
- })
|
|
|
- );
|
|
|
-
|
|
|
- const createMintInstructions: Array<TransactionInstruction> = [
|
|
|
- tokenMintA,
|
|
|
- tokenMintB,
|
|
|
- ].map((mint) =>
|
|
|
- SystemProgram.createAccount({
|
|
|
- fromPubkey: provider.publicKey,
|
|
|
- newAccountPubkey: mint.publicKey,
|
|
|
- lamports: minimumLamports,
|
|
|
- space: MINT_SIZE,
|
|
|
- programId: TOKEN_PROGRAM,
|
|
|
- })
|
|
|
- );
|
|
|
-
|
|
|
- // Make tokenA and tokenB mints, mint tokens and create ATAs
|
|
|
- const mintTokensInstructions: Array<TransactionInstruction> = [
|
|
|
- {
|
|
|
- mint: tokenMintA.publicKey,
|
|
|
- authority: alice.publicKey,
|
|
|
- ata: aliceTokenAccountA,
|
|
|
- },
|
|
|
- {
|
|
|
- mint: tokenMintB.publicKey,
|
|
|
- authority: bob.publicKey,
|
|
|
- ata: bobTokenAccountB,
|
|
|
- },
|
|
|
- ].flatMap((mintDetails) => [
|
|
|
- createInitializeMint2Instruction(
|
|
|
- mintDetails.mint,
|
|
|
- 6,
|
|
|
- mintDetails.authority,
|
|
|
- null,
|
|
|
- TOKEN_PROGRAM
|
|
|
- ),
|
|
|
- createAssociatedTokenAccountIdempotentInstruction(
|
|
|
- provider.publicKey,
|
|
|
- mintDetails.ata,
|
|
|
- mintDetails.authority,
|
|
|
- mintDetails.mint,
|
|
|
- TOKEN_PROGRAM
|
|
|
- ),
|
|
|
- createMintToInstruction(
|
|
|
- mintDetails.mint,
|
|
|
- mintDetails.ata,
|
|
|
- mintDetails.authority,
|
|
|
- 1_000_000_000,
|
|
|
- [],
|
|
|
- TOKEN_PROGRAM
|
|
|
- ),
|
|
|
- ]);
|
|
|
-
|
|
|
- // Add all these instructions to our transaction
|
|
|
- const tx = new Transaction();
|
|
|
- tx.instructions = [
|
|
|
- ...sendSolInstructions,
|
|
|
- ...createMintInstructions,
|
|
|
- ...mintTokensInstructions,
|
|
|
- ];
|
|
|
-
|
|
|
- await provider.sendAndConfirm(tx, [tokenMintA, tokenMintB, alice, bob]);
|
|
|
-
|
|
|
- // 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;
|
|
|
- }
|
|
|
- );
|
|
|
+ before('Creates Alice and Bob accounts, 2 token mints, and associated token accounts for both tokens for both users', async () => {
|
|
|
+ const [aliceTokenAccountA, aliceTokenAccountB, bobTokenAccountA, bobTokenAccountB] = [alice, bob].flatMap((keypair) =>
|
|
|
+ [tokenMintA, tokenMintB].map((mint) => getAssociatedTokenAddressSync(mint.publicKey, keypair.publicKey, false, TOKEN_PROGRAM)),
|
|
|
+ );
|
|
|
+
|
|
|
+ // Airdrops to users, and creates two tokens mints 'A' and 'B'"
|
|
|
+ const minimumLamports = await getMinimumBalanceForRentExemptMint(connection);
|
|
|
+
|
|
|
+ const sendSolInstructions: Array<TransactionInstruction> = [alice, bob].map((account) =>
|
|
|
+ SystemProgram.transfer({
|
|
|
+ fromPubkey: provider.publicKey,
|
|
|
+ toPubkey: account.publicKey,
|
|
|
+ lamports: 10 * LAMPORTS_PER_SOL,
|
|
|
+ }),
|
|
|
+ );
|
|
|
+
|
|
|
+ const createMintInstructions: Array<TransactionInstruction> = [tokenMintA, tokenMintB].map((mint) =>
|
|
|
+ SystemProgram.createAccount({
|
|
|
+ fromPubkey: provider.publicKey,
|
|
|
+ newAccountPubkey: mint.publicKey,
|
|
|
+ lamports: minimumLamports,
|
|
|
+ space: MINT_SIZE,
|
|
|
+ programId: TOKEN_PROGRAM,
|
|
|
+ }),
|
|
|
+ );
|
|
|
+
|
|
|
+ // Make tokenA and tokenB mints, mint tokens and create ATAs
|
|
|
+ const mintTokensInstructions: Array<TransactionInstruction> = [
|
|
|
+ {
|
|
|
+ mint: tokenMintA.publicKey,
|
|
|
+ authority: alice.publicKey,
|
|
|
+ ata: aliceTokenAccountA,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ mint: tokenMintB.publicKey,
|
|
|
+ authority: bob.publicKey,
|
|
|
+ ata: bobTokenAccountB,
|
|
|
+ },
|
|
|
+ ].flatMap((mintDetails) => [
|
|
|
+ createInitializeMint2Instruction(mintDetails.mint, 6, mintDetails.authority, null, TOKEN_PROGRAM),
|
|
|
+ createAssociatedTokenAccountIdempotentInstruction(provider.publicKey, mintDetails.ata, mintDetails.authority, mintDetails.mint, TOKEN_PROGRAM),
|
|
|
+ createMintToInstruction(mintDetails.mint, mintDetails.ata, mintDetails.authority, 1_000_000_000, [], TOKEN_PROGRAM),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // Add all these instructions to our transaction
|
|
|
+ const tx = new Transaction();
|
|
|
+ tx.instructions = [...sendSolInstructions, ...createMintInstructions, ...mintTokensInstructions];
|
|
|
+
|
|
|
+ await provider.sendAndConfirm(tx, [tokenMintA, tokenMintB, alice, bob]);
|
|
|
+
|
|
|
+ // 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;
|
|
|
+ });
|
|
|
|
|
|
const tokenAOfferedAmount = new BN(1_000_000);
|
|
|
const tokenBWantedAmount = new BN(1_000_000);
|
|
@@ -163,20 +110,11 @@ describe("escrow", async () => {
|
|
|
|
|
|
// 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;
|
|
@@ -215,24 +153,18 @@ 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));
|
|
|
};
|
|
|
|
|
|
- it("Puts the tokens Alice offers into the vault when Alice makes an offer", async () => {
|
|
|
+ it('Puts the tokens Alice offers into the vault when Alice makes an offer', async () => {
|
|
|
await make();
|
|
|
});
|
|
|
|