|
@@ -1,32 +1,30 @@
|
|
|
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,
|
|
|
- type TOKEN_PROGRAM_ID,
|
|
|
- createAssociatedTokenAccountIdempotentInstruction,
|
|
|
- createInitializeMint2Instruction,
|
|
|
- createMintToInstruction,
|
|
|
- getAssociatedTokenAddressSync,
|
|
|
- getMinimumBalanceForRentExemptMint,
|
|
|
-} from '@solana/spl-token';
|
|
|
-import { LAMPORTS_PER_SOL, PublicKey, SystemProgram, Transaction, type TransactionInstruction } from '@solana/web3.js';
|
|
|
+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, makeKeypairs } from '@solana-developers/helpers';
|
|
|
+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 SECONDS = 1000;
|
|
|
+
|
|
|
const getRandomBigNumber = (size = 8) => {
|
|
|
return new BN(randomBytes(size));
|
|
|
};
|
|
|
|
|
|
describe('escrow', async () => {
|
|
|
- anchor.setProvider(anchor.AnchorProvider.env());
|
|
|
+ // Use the cluster and the keypair from Anchor.toml
|
|
|
+ const provider = anchor.AnchorProvider.env();
|
|
|
+ anchor.setProvider(provider);
|
|
|
|
|
|
- const provider = anchor.getProvider();
|
|
|
+ // See https://github.com/coral-xyz/anchor/issues/3122
|
|
|
+ const user = (provider.wallet as anchor.Wallet).payer;
|
|
|
+ const payer = user;
|
|
|
|
|
|
const connection = provider.connection;
|
|
|
|
|
@@ -37,68 +35,12 @@ describe('escrow', async () => {
|
|
|
tokenProgram: TOKEN_PROGRAM,
|
|
|
};
|
|
|
|
|
|
- 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);
|
|
|
+ let alice: anchor.web3.Keypair;
|
|
|
+ let bob: anchor.web3.Keypair;
|
|
|
+ let tokenMintA: anchor.web3.Keypair;
|
|
|
+ let tokenMintB: anchor.web3.Keypair;
|
|
|
|
|
|
- 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;
|
|
|
- });
|
|
|
+ [alice, bob, tokenMintA, tokenMintB] = makeKeypairs(4);
|
|
|
|
|
|
const tokenAOfferedAmount = new BN(1_000_000);
|
|
|
const tokenBWantedAmount = new BN(1_000_000);
|
|
@@ -164,11 +106,61 @@ describe('escrow', async () => {
|
|
|
assert(aliceTokenAccountBalanceAfter.eq(tokenBWantedAmount));
|
|
|
};
|
|
|
|
|
|
+ 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 () => {
|
|
|
await make();
|
|
|
- });
|
|
|
+ }).slow(60 * SECONDS);
|
|
|
|
|
|
it("Puts the tokens from the vault into Bob's account, and gives Alice Bob's tokens, when Bob takes an offer", async () => {
|
|
|
await take();
|
|
|
- });
|
|
|
+ }).slow(60 * SECONDS);
|
|
|
});
|