Browse Source

WIP on using kinobi client instead of anchor in tests

Mike MacCana 1 year ago
parent
commit
ba6b823492

+ 1 - 1
tokens/escrow/anchor/Anchor.toml

@@ -15,4 +15,4 @@ cluster = "Localnet"
 wallet = "~/.config/solana/id.json"
 
 [scripts]
-test = "pnpm ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
+test = "esrun tests/*.ts"

+ 7 - 14
tokens/escrow/anchor/package.json

@@ -4,19 +4,12 @@
     "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "^0.30.0",
-    "@solana-developers/helpers": "^2.4.0",
-    "@solana/spl-token": "^0.4.6"
+    "@kinobi-so/nodes-from-anchor": "^0.21.1",
+    "@kinobi-so/renderers": "^0.21.1",
+    "@kinobi-so/renderers-js": "^0.21.6",
+    "@solana/web3.js": "^2.0.0-rc.1",
+    "@types/node": "^22.4.1",
+    "kinobi": "^0.21.3"
   },
-  "license": "MIT",
-  "devDependencies": {
-    "@types/bn.js": "^5.1.0",
-    "@types/chai": "^4.3.0",
-    "@types/mocha": "^9.0.0",
-    "chai": "^4.3.4",
-    "mocha": "^9.0.3",
-    "prettier": "^2.6.2",
-    "ts-mocha": "^10.0.0",
-    "typescript": "^4.3.5"
-  }
+  "license": "MIT"
 }

+ 198 - 159
tokens/escrow/anchor/tests/escrow.ts

@@ -1,169 +1,208 @@
-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 { assert } from 'node:console';
+import { describe, test } from 'node:test';
+import { IdlV01, rootNodeFromAnchor } from '@kinobi-so/nodes-from-anchor';
+import { renderJavaScriptVisitor } from '@kinobi-so/renderers';
+import { createSolanaRpc } from '@solana/web3.js';
+// From https://github.com/kinobi-so/kinobi?tab=readme-ov-file#from-program-to-kinobi
+import { createFromRoot } from 'kinobi';
+import anchorIdl from '../target/idl/escrow.json';
 
-import { confirmTransaction, createAccountsMintsAndTokenAccounts, makeKeypairs } from '@solana-developers/helpers';
+const rootNode = rootNodeFromAnchor(anchorIdl as IdlV01);
 
-// 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 kinobi = createFromRoot(rootNode);
 
-const SECONDS = 1000;
+const log = console.log;
 
-// 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;
+log(kinobi);
 
-const getRandomBigNumber = (size = 8) => {
-  return new BN(randomBytes(size));
+// that the first argument of the renderJavaScriptVisitor function should be a folder not a file.
+const visitor = renderJavaScriptVisitor('generated-client', {
+  formatCode: true,
+});
+
+kinobi.accept(visitor);
+
+// import { TOKEN_2022_PROGRAM_ID, type TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync } from '@solana/spl-token';
+// import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
+
+// import type { Escrow } from '../target/types/escrow';
+
+const CLUSTERS = {
+  devnet: 'https://api.devnet.solana.com',
+  testnet: 'https://api.testnet.solana.com',
+  mainnet: 'https://api.mainnet-beta.solana.com',
+  localnet: 'http://127.0.0.1:8899',
+};
+
+const CLUSTER_NAMES = Object.keys(CLUSTERS);
+
+const connect = (clusterNameOrURL: string) => {
+  if (CLUSTER_NAMES.includes(clusterNameOrURL)) {
+    return createSolanaRpc(clusterNameOrURL);
+  }
+  return createSolanaRpc(clusterNameOrURL);
 };
 
+const rpc = connect('localnet');
+
+// import * as Escrow from 'escrow-generated.ts'
+
+// // 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;
+
+// // 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;
+
+// function getRandomBigInt(max = 256) {
+//   return BigInt(Math.floor(Math.random() * max));
+// }
+
 describe('escrow', async () => {
-  // Use the cluster and the keypair from Anchor.toml
-  const provider = anchor.AnchorProvider.env();
-  anchor.setProvider(provider);
-
-  // See https://github.com/coral-xyz/anchor/issues/3122
-  const user = (provider.wallet as anchor.Wallet).payer;
-  const payer = user;
-
-  const connection = provider.connection;
-
-  const program = anchor.workspace.Escrow as Program<Escrow>;
-
-  // We're going to reuse these accounts across multiple tests
-  const accounts: Record<string, PublicKey> = {
-    tokenProgram: TOKEN_PROGRAM,
-  };
-
-  let alice: anchor.web3.Keypair;
-  let bob: anchor.web3.Keypair;
-  let tokenMintA: anchor.web3.Keypair;
-  let tokenMintB: anchor.web3.Keypair;
-
-  [alice, bob, tokenMintA, tokenMintB] = makeKeypairs(4);
-
-  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,
-    );
-
-    // Alice will be the maker (creator) of the offer
-    // Bob will be the taker (acceptor) of the offer
-    const users = usersMintsAndTokenAccounts.users;
-    alice = users[0];
-    bob = users[1];
-
-    // tokenMintA represents the token Alice is offering
-    // tokenMintB represents the token Alice wants in return
-    const mints = usersMintsAndTokenAccounts.mints;
-    tokenMintA = mints[0];
-    tokenMintB = mints[1];
-
-    const tokenAccounts = usersMintsAndTokenAccounts.tokenAccounts;
-
-    // aliceTokenAccountA is Alice's account for tokenA (the token she's offering)
-    // aliceTokenAccountB is Alice's account for tokenB (the token she wants)
-    const aliceTokenAccountA = tokenAccounts[0][0];
-    const aliceTokenAccountB = tokenAccounts[0][1];
-
-    // bobTokenAccountA is Bob's account for tokenA (the token Alice is offering)
-    // bobTokenAccountB is Bob's account for tokenB (the token Alice wants)
-    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;
+  test('escrow', async () => {
+    assert(true);
   });
-
-  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,
-    )[0];
-
-    const vault = getAssociatedTokenAddressSync(accounts.tokenMintA, offer, true, TOKEN_PROGRAM);
-
-    accounts.offer = offer;
-    accounts.vault = vault;
-
-    const transactionSignature = await program.methods
-      .makeOffer(offerId, tokenAOfferedAmount, tokenBWantedAmount)
-      .accounts({ ...accounts })
-      .signers([alice])
-      .rpc();
-
-    await confirmTransaction(connection, transactionSignature);
-
-    // Check our vault contains the tokens offered
-    const vaultBalanceResponse = await connection.getTokenAccountBalance(vault);
-    const vaultBalance = new BN(vaultBalanceResponse.value.amount);
-    assert(vaultBalance.eq(tokenAOfferedAmount));
-
-    // Check our Offer account contains the correct data
-    const offerAccount = await program.account.offer.fetch(offer);
-
-    assert(offerAccount.maker.equals(alice.publicKey));
-    assert(offerAccount.tokenMintA.equals(accounts.tokenMintA));
-    assert(offerAccount.tokenMintB.equals(accounts.tokenMintB));
-    assert(offerAccount.tokenBWantedAmount.eq(tokenBWantedAmount));
-  }).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
-      .takeOffer()
-      .accounts({ ...accounts })
-      .signers([bob])
-      .rpc();
-
-    await confirmTransaction(connection, transactionSignature);
-
-    // 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);
-    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);
-    assert(aliceTokenAccountBalanceAfter.eq(tokenBWantedAmount));
-  }).slow(ANCHOR_SLOW_TEST_THRESHOLD);
+  //   // See https://github.com/coral-xyz/anchor/issues/3122
+  //   const payer = user;
+
+  //   const connection = provider.connection;
+
+  //   const program = anchor.workspace.Escrow as Program<Escrow>;
+
+  //   // We're going to reuse these accounts across multiple tests
+  //   const accounts: Record<string, PublicKey> = {
+  //     tokenProgram: TOKEN_PROGRAM,
+  //   };
+
+  //   let alice: anchor.web3.Keypair;
+  //   let bob: anchor.web3.Keypair;
+  //   let tokenMintA: anchor.web3.Keypair;
+  //   let tokenMintB: anchor.web3.Keypair;
+
+  //   [alice, bob, tokenMintA, tokenMintB] = makeKeypairs(4);
+
+  //   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,
+  //     );
+
+  //     // Alice will be the maker (creator) of the offer
+  //     // Bob will be the taker (acceptor) of the offer
+  //     const users = usersMintsAndTokenAccounts.users;
+  //     alice = users[0];
+  //     bob = users[1];
+
+  //     // tokenMintA represents the token Alice is offering
+  //     // tokenMintB represents the token Alice wants in return
+  //     const mints = usersMintsAndTokenAccounts.mints;
+  //     tokenMintA = mints[0];
+  //     tokenMintB = mints[1];
+
+  //     const tokenAccounts = usersMintsAndTokenAccounts.tokenAccounts;
+
+  //     // aliceTokenAccountA is Alice's account for tokenA (the token she's offering)
+  //     // aliceTokenAccountB is Alice's account for tokenB (the token she wants)
+  //     const aliceTokenAccountA = tokenAccounts[0][0];
+  //     const aliceTokenAccountB = tokenAccounts[0][1];
+
+  //     // bobTokenAccountA is Bob's account for tokenA (the token Alice is offering)
+  //     // bobTokenAccountB is Bob's account for tokenB (the token Alice wants)
+  //     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,
+  //     )[0];
+
+  //     const vault = getAssociatedTokenAddressSync(accounts.tokenMintA, offer, true, TOKEN_PROGRAM);
+
+  //     accounts.offer = offer;
+  //     accounts.vault = vault;
+
+  //     const transactionSignature = await program.methods
+  //       .makeOffer(offerId, tokenAOfferedAmount, tokenBWantedAmount)
+  //       .accounts({ ...accounts })
+  //       .signers([alice])
+  //       .rpc();
+
+  //     await confirmTransaction(connection, transactionSignature);
+
+  //     // Check our vault contains the tokens offered
+  //     const vaultBalanceResponse = await connection.getTokenAccountBalance(vault);
+  //     const vaultBalance = new BN(vaultBalanceResponse.value.amount);
+  //     assert(vaultBalance.eq(tokenAOfferedAmount));
+
+  //     // Check our Offer account contains the correct data
+  //     const offerAccount = await program.account.offer.fetch(offer);
+
+  //     assert(offerAccount.maker.equals(alice.publicKey));
+  //     assert(offerAccount.tokenMintA.equals(accounts.tokenMintA));
+  //     assert(offerAccount.tokenMintB.equals(accounts.tokenMintB));
+  //     assert(offerAccount.tokenBWantedAmount.eq(tokenBWantedAmount));
+  //   }).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
+  //       .takeOffer()
+  //       .accounts({ ...accounts })
+  //       .signers([bob])
+  //       .rpc();
+
+  //     await confirmTransaction(connection, transactionSignature);
+
+  //     // 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);
+  //     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);
+  //     assert(aliceTokenAccountBalanceAfter.eq(tokenBWantedAmount));
+  //   }).slow(ANCHOR_SLOW_TEST_THRESHOLD);
 });

+ 10 - 6
tokens/escrow/anchor/tsconfig.json

@@ -1,10 +1,14 @@
+// See https://aka.ms/tsconfig
 {
   "compilerOptions": {
-    "types": ["mocha", "chai"],
-    "typeRoots": ["./node_modules/@types"],
-    "lib": ["es2015"],
-    "module": "commonjs",
-    "target": "es6",
-    "esModuleInterop": true
+    "target": "es2022",
+    "moduleResolution": "nodeNext",
+    "module": "nodeNext",
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "strict": true,
+    "skipLibCheck": true,
+    // had to turn this on for Kinobi
+    "resolveJsonModule": true
   }
 }