text: const anchor = require("@project-serum/anchor");
  const { TOKEN_PROGRAM_ID, Token } = require("@solana/spl-token");
  const assert = require("assert");
  
  describe("escrow", () => {
    const provider = anchor.Provider.env();
    anchor.setProvider(provider);
  
    const program = anchor.workspace.Escrow;
  
    let mintA = null;
    let mintB = null;
    let initializerTokenAccountA = null;
    let initializerTokenAccountB = null;
    let takerTokenAccountA = null;
    let takerTokenAccountB = null;
    let pda = null;
  
    const takerAmount = 1000;
    const initializerAmount = 500;
  
    const escrowAccount = anchor.web3.Keypair.generate();
    const payer = anchor.web3.Keypair.generate();
    const mintAuthority = anchor.web3.Keypair.generate();
  
    it("Initialise escrow state", async () => {
      // Airdropping tokens to a payer.
      await provider.connection.confirmTransaction(
        await provider.connection.requestAirdrop(payer.publicKey, 10000000000),
        "confirmed"
      );
  
      mintA = await Token.createMint(
        provider.connection,
        payer,
        mintAuthority.publicKey,
        null,
        0,
        TOKEN_PROGRAM_ID
      );
  
      mintB = await Token.createMint(
        provider.connection,
        payer,
        mintAuthority.publicKey,
        null,
        0,
        TOKEN_PROGRAM_ID
      );
  
      initializerTokenAccountA = await mintA.createAccount(provider.wallet.publicKey);
      takerTokenAccountA = await mintA.createAccount(provider.wallet.publicKey);
  
      initializerTokenAccountB = await mintB.createAccount(provider.wallet.publicKey);
      takerTokenAccountB = await mintB.createAccount(provider.wallet.publicKey);
  
      await mintA.mintTo(
        initializerTokenAccountA,
        mintAuthority.publicKey,
        [mintAuthority],
        initializerAmount
      );
  
      await mintB.mintTo(
        takerTokenAccountB,
        mintAuthority.publicKey,
        [mintAuthority],
        takerAmount
      );
  
      let _initializerTokenAccountA = await mintA.getAccountInfo(initializerTokenAccountA);
      let _takerTokenAccountB = await mintB.getAccountInfo(takerTokenAccountB);
  
      assert.ok(_initializerTokenAccountA.amount.toNumber() == initializerAmount);
      assert.ok(_takerTokenAccountB.amount.toNumber() == takerAmount);
    });
  
    it("Initialize escrow", async () => {
      await program.rpc.initializeEscrow(
        new anchor.BN(initializerAmount),
        new anchor.BN(takerAmount),
        {
          accounts: {
            initializer: provider.wallet.publicKey,
            initializerDepositTokenAccount: initializerTokenAccountA,
            initializerReceiveTokenAccount: initializerTokenAccountB,
            escrowAccount: escrowAccount.publicKey,
            tokenProgram: TOKEN_PROGRAM_ID,
            rent: anchor.web3.SYSVAR_RENT_PUBKEY,
          },
          instructions: [
            await program.account.escrowAccount.createInstruction(escrowAccount),
          ],
          signers: [escrowAccount],
        }
      );
  
      // Get the PDA that is assigned authority to token account.
      const [_pda, _nonce] = await anchor.web3.PublicKey.findProgramAddress(
        [Buffer.from(anchor.utils.bytes.utf8.encode("escrow"))],
        program.programId
      );
  
      pda = _pda;
  
      let _initializerTokenAccountA = await mintA.getAccountInfo(initializerTokenAccountA);
  
      let _escrowAccount = await program.account.escrowAccount.fetch(
        escrowAccount.publicKey
      );
  
      // Check that the new owner is the PDA.
      assert.ok(_initializerTokenAccountA.owner.equals(pda));
  
      // Check that the values in the escrow account match what we expect.
      assert.ok(_escrowAccount.initializerKey.equals(provider.wallet.publicKey));
      assert.ok(_escrowAccount.initializerAmount.toNumber() == initializerAmount);
      assert.ok(_escrowAccount.takerAmount.toNumber() == takerAmount);
      assert.ok(
        _escrowAccount.initializerDepositTokenAccount.equals(initializerTokenAccountA)
      );
      assert.ok(
        _escrowAccount.initializerReceiveTokenAccount.equals(initializerTokenAccountB)
      );
    });
  
    it("Exchange escrow", async () => {
      await program.rpc.exchange({
        accounts: {
          taker: provider.wallet.publicKey,
          takerDepositTokenAccount: takerTokenAccountB,
          takerReceiveTokenAccount: takerTokenAccountA,
          pdaDepositTokenAccount: initializerTokenAccountA,
          initializerReceiveTokenAccount: initializerTokenAccountB,
          initializerMainAccount: provider.wallet.publicKey,
          escrowAccount: escrowAccount.publicKey,
          pdaAccount: pda,
          tokenProgram: TOKEN_PROGRAM_ID,
        },
      });
  
      let _takerTokenAccountA = await mintA.getAccountInfo(takerTokenAccountA);
      let _takerTokenAccountB = await mintB.getAccountInfo(takerTokenAccountB);
      let _initializerTokenAccountA = await mintA.getAccountInfo(initializerTokenAccountA);
      let _initializerTokenAccountB = await mintB.getAccountInfo(initializerTokenAccountB);
  
      // Check that the initializer gets back ownership of their token account.
      assert.ok(_takerTokenAccountA.owner.equals(provider.wallet.publicKey));
  
      assert.ok(_takerTokenAccountA.amount.toNumber() == initializerAmount);
      assert.ok(_initializerTokenAccountA.amount.toNumber() == 0);
      assert.ok(_initializerTokenAccountB.amount.toNumber() == takerAmount);
      assert.ok(_takerTokenAccountB.amount.toNumber() == 0);
    });
  
    let newEscrow = anchor.web3.Keypair.generate();
  
    it("Initialize escrow and cancel escrow", async () => {
      // Put back tokens into initializer token A account.
      await mintA.mintTo(
        initializerTokenAccountA,
        mintAuthority.publicKey,
        [mintAuthority],
        initializerAmount
      );
  
      await program.rpc.initializeEscrow(
        new anchor.BN(initializerAmount),
        new anchor.BN(takerAmount),
        {
          accounts: {
            initializer: provider.wallet.publicKey,
            initializerDepositTokenAccount: initializerTokenAccountA,
            initializerReceiveTokenAccount: initializerTokenAccountB,
            escrowAccount: newEscrow.publicKey,
            tokenProgram: TOKEN_PROGRAM_ID,
            rent: anchor.web3.SYSVAR_RENT_PUBKEY,
          },
          instructions: [await program.account.escrowAccount.createInstruction(newEscrow)],
          signers: [newEscrow],
        }
      );
  
      let _initializerTokenAccountA = await mintA.getAccountInfo(initializerTokenAccountA);
  
      // Check that the new owner is the PDA.
      assert.ok(_initializerTokenAccountA.owner.equals(pda));
  
      // Cancel the escrow.
      await program.rpc.cancelEscrow({
        accounts: {
          initializer: provider.wallet.publicKey,
          pdaDepositTokenAccount: initializerTokenAccountA,
          pdaAccount: pda,
          escrowAccount: newEscrow.publicKey,
          tokenProgram: TOKEN_PROGRAM_ID,
        },
      });
  
      // Check the final owner should be the provider public key.
      _initializerTokenAccountA = await mintA.getAccountInfo(initializerTokenAccountA);
      assert.ok(_initializerTokenAccountA.owner.equals(provider.wallet.publicKey));
  
      // Check all the funds are still there.
      assert.ok(_initializerTokenAccountA.amount.toNumber() == initializerAmount);
    });
  });
  