Skip to content

Commit 2a4ba64

Browse files
author
tilo-14
committed
add typescript tests for native and anchor programs
1 parent 49f89d7 commit 2a4ba64

26 files changed

Lines changed: 2119 additions & 0 deletions
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "light-token-anchor-examples",
3+
"version": "0.1.0",
4+
"description": "Anchor programs demonstrating Light Token CPI operations",
5+
"license": "Apache-2.0",
6+
"scripts": {
7+
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
8+
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check",
9+
"test": "ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
10+
},
11+
"dependencies": {
12+
"@coral-xyz/anchor": "0.31.1",
13+
"@lightprotocol/compressed-token": "0.22.1-alpha.7",
14+
"@lightprotocol/stateless.js": "0.22.1-alpha.6",
15+
"dotenv": "^16.5.0"
16+
},
17+
"devDependencies": {
18+
"@types/bn.js": "^5.1.0",
19+
"@types/chai": "^4.3.0",
20+
"@types/mocha": "^9.0.0",
21+
"chai": "^4.3.4",
22+
"mocha": "^9.0.3",
23+
"prettier": "^2.6.2",
24+
"ts-mocha": "^10.1.0",
25+
"typescript": "^5.0.0"
26+
}
27+
}
28+
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import * as assert from "assert";
2+
import BN from "bn.js";
3+
import {
4+
setupTestEnvironment,
5+
createTestMintWithTokens,
6+
getAta,
7+
waitForIndexer,
8+
Rpc,
9+
web3,
10+
anchor,
11+
} from "./shared";
12+
13+
describe("approve", () => {
14+
let rpc: Rpc;
15+
let payer: web3.Keypair;
16+
let provider: anchor.AnchorProvider;
17+
18+
before(async () => {
19+
const env = await setupTestEnvironment();
20+
rpc = env.rpc;
21+
payer = env.payer;
22+
provider = env.provider;
23+
});
24+
25+
it("approves a delegate via anchor program", async () => {
26+
const tokenAmount = 1_000_000;
27+
const approveAmount = new BN(500_000);
28+
29+
// 1. Setup: Create mint with tokens
30+
const { mint } = await createTestMintWithTokens(
31+
rpc,
32+
payer,
33+
payer.publicKey,
34+
tokenAmount
35+
);
36+
37+
// 2. Get the token account (ATA)
38+
const tokenAccount = getAta(payer.publicKey, mint);
39+
40+
// 3. Create a delegate keypair
41+
const delegate = web3.Keypair.generate();
42+
43+
// 4. Get the anchor program
44+
const program = anchor.workspace.LightTokenAnchorApprove;
45+
46+
// 5. Call the anchor program's approve instruction
47+
const tx = await program.methods
48+
.approve(approveAmount)
49+
.accounts({
50+
tokenAccount: tokenAccount,
51+
delegate: delegate.publicKey,
52+
owner: payer.publicKey,
53+
systemProgram: web3.SystemProgram.programId,
54+
})
55+
.signers([payer])
56+
.rpc({ commitment: "confirmed" });
57+
58+
console.log("Approve transaction:", tx);
59+
60+
// 6. Wait for indexer to process
61+
await waitForIndexer();
62+
63+
// 7. Verify delegation by checking delegate's access
64+
const delegatedAccounts = await rpc.getCompressedTokenAccountsByDelegate(
65+
delegate.publicKey,
66+
{ mint }
67+
);
68+
69+
assert.ok(
70+
delegatedAccounts.items.length > 0,
71+
"Delegate should have access to delegated accounts"
72+
);
73+
74+
console.log(`Successfully approved ${approveAmount.toString()} tokens to delegate ${delegate.publicKey.toBase58()}`);
75+
});
76+
77+
it("approves full balance to delegate", async () => {
78+
const tokenAmount = 750_000;
79+
const approveAmount = new BN(tokenAmount);
80+
81+
// Setup
82+
const { mint } = await createTestMintWithTokens(
83+
rpc,
84+
payer,
85+
payer.publicKey,
86+
tokenAmount
87+
);
88+
89+
const tokenAccount = getAta(payer.publicKey, mint);
90+
const delegate = web3.Keypair.generate();
91+
const program = anchor.workspace.LightTokenAnchorApprove;
92+
93+
// Approve full balance
94+
await program.methods
95+
.approve(approveAmount)
96+
.accounts({
97+
tokenAccount: tokenAccount,
98+
delegate: delegate.publicKey,
99+
owner: payer.publicKey,
100+
systemProgram: web3.SystemProgram.programId,
101+
})
102+
.signers([payer])
103+
.rpc({ commitment: "confirmed" });
104+
105+
await waitForIndexer();
106+
107+
// Verify
108+
const delegatedAccounts = await rpc.getCompressedTokenAccountsByDelegate(
109+
delegate.publicKey,
110+
{ mint }
111+
);
112+
113+
assert.ok(
114+
delegatedAccounts.items.length > 0,
115+
"Delegate should have access to full balance"
116+
);
117+
118+
console.log("Successfully approved full balance to delegate");
119+
});
120+
});
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import * as assert from "assert";
2+
import BN from "bn.js";
3+
import {
4+
setupTestEnvironment,
5+
createTestMintWithTokens,
6+
getAta,
7+
getCompressedTokenBalance,
8+
waitForIndexer,
9+
Rpc,
10+
web3,
11+
anchor,
12+
} from "./shared";
13+
14+
describe("burn", () => {
15+
let rpc: Rpc;
16+
let payer: web3.Keypair;
17+
let provider: anchor.AnchorProvider;
18+
19+
before(async () => {
20+
const env = await setupTestEnvironment();
21+
rpc = env.rpc;
22+
payer = env.payer;
23+
provider = env.provider;
24+
});
25+
26+
it("burns tokens via anchor program", async () => {
27+
const initialAmount = 1_000_000;
28+
const burnAmount = new BN(250_000);
29+
30+
// 1. Setup: Create mint and mint initial tokens using SDK
31+
const { mint } = await createTestMintWithTokens(
32+
rpc,
33+
payer,
34+
payer.publicKey,
35+
initialAmount
36+
);
37+
38+
// 2. Get the source ATA
39+
const source = getAta(payer.publicKey, mint);
40+
41+
// 3. Get the anchor program
42+
const program = anchor.workspace.LightTokenAnchorBurn;
43+
44+
// 4. Call the anchor program's burn instruction
45+
const tx = await program.methods
46+
.burn(burnAmount)
47+
.accounts({
48+
source: source,
49+
mint: mint,
50+
authority: payer.publicKey,
51+
})
52+
.signers([payer])
53+
.rpc({ commitment: "confirmed" });
54+
55+
console.log("Burn transaction:", tx);
56+
57+
// 5. Wait for indexer to process
58+
await waitForIndexer();
59+
60+
// 6. Verify the balance decreased
61+
const expectedBalance = BigInt(initialAmount) - BigInt(burnAmount.toString());
62+
const balance = await getCompressedTokenBalance(rpc, payer.publicKey, mint);
63+
assert.strictEqual(
64+
balance.toString(),
65+
expectedBalance.toString(),
66+
`Expected balance ${expectedBalance.toString()}, got ${balance.toString()}`
67+
);
68+
69+
console.log(`Successfully burned ${burnAmount.toString()} tokens, remaining: ${balance.toString()}`);
70+
});
71+
72+
it("burns all tokens", async () => {
73+
const initialAmount = 500_000;
74+
const burnAmount = new BN(initialAmount);
75+
76+
// Setup
77+
const { mint } = await createTestMintWithTokens(
78+
rpc,
79+
payer,
80+
payer.publicKey,
81+
initialAmount
82+
);
83+
84+
const source = getAta(payer.publicKey, mint);
85+
const program = anchor.workspace.LightTokenAnchorBurn;
86+
87+
// Burn all tokens
88+
await program.methods
89+
.burn(burnAmount)
90+
.accounts({
91+
source: source,
92+
mint: mint,
93+
authority: payer.publicKey,
94+
})
95+
.signers([payer])
96+
.rpc({ commitment: "confirmed" });
97+
98+
await waitForIndexer();
99+
100+
// Verify balance is zero
101+
const balance = await getCompressedTokenBalance(rpc, payer.publicKey, mint);
102+
assert.strictEqual(
103+
balance.toString(),
104+
"0",
105+
`Expected balance 0, got ${balance.toString()}`
106+
);
107+
108+
console.log("Successfully burned all tokens");
109+
});
110+
});
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import * as assert from "assert";
2+
import {
3+
setupTestEnvironment,
4+
createTestMint,
5+
getAta,
6+
waitForIndexer,
7+
RENT_SPONSOR,
8+
CTOKEN_PROGRAM_ID,
9+
Rpc,
10+
web3,
11+
anchor,
12+
} from "./shared";
13+
14+
describe("close", () => {
15+
let rpc: Rpc;
16+
let payer: web3.Keypair;
17+
let provider: anchor.AnchorProvider;
18+
19+
before(async () => {
20+
const env = await setupTestEnvironment();
21+
rpc = env.rpc;
22+
payer = env.payer;
23+
provider = env.provider;
24+
});
25+
26+
it("closes an empty token account via anchor program", async () => {
27+
// 1. Setup: Create mint (no tokens minted, account has zero balance)
28+
const { mint } = await createTestMint(rpc, payer);
29+
30+
// 2. Get the token account (ATA) - this will be an empty account
31+
const tokenAccount = getAta(payer.publicKey, mint);
32+
33+
// 3. Record balance before close
34+
const balanceBefore = await rpc.getBalance(payer.publicKey);
35+
36+
// 4. Get the anchor program
37+
const program = anchor.workspace.LightTokenAnchorClose;
38+
39+
// 5. Call the anchor program's close_account instruction
40+
const tx = await program.methods
41+
.closeAccount()
42+
.accounts({
43+
tokenProgram: CTOKEN_PROGRAM_ID,
44+
account: tokenAccount,
45+
destination: payer.publicKey,
46+
owner: payer.publicKey,
47+
rentSponsor: RENT_SPONSOR,
48+
})
49+
.signers([payer])
50+
.rpc({ commitment: "confirmed" });
51+
52+
console.log("Close transaction:", tx);
53+
54+
// 6. Wait for indexer to process
55+
await waitForIndexer();
56+
57+
// 7. Verify account is closed (should not exist or be empty)
58+
const accounts = await rpc.getCompressedTokenAccountsByOwner(payer.publicKey, { mint });
59+
60+
// After closing, the account should either not exist or have no balance
61+
const hasAccount = accounts.items.length > 0;
62+
if (hasAccount) {
63+
// If account still exists, verify it's closed/zeroed
64+
console.log("Account still exists in index, checking state...");
65+
} else {
66+
console.log("Account successfully closed - no longer in index");
67+
}
68+
69+
// Verify lamports returned to destination
70+
const balanceAfter = await rpc.getBalance(payer.publicKey);
71+
console.log(`Balance before: ${balanceBefore}, after: ${balanceAfter}`);
72+
73+
console.log(`Successfully closed token account ${tokenAccount.toBase58()}`);
74+
});
75+
});
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as assert from "assert";
2+
import { setupTestEnvironment, createTestMint, Rpc, web3 } from "./shared";
3+
import { createTokenPool } from "@lightprotocol/compressed-token";
4+
5+
describe("create-ata", () => {
6+
let rpc: Rpc;
7+
let payer: web3.Keypair;
8+
9+
before(async () => {
10+
const env = await setupTestEnvironment();
11+
rpc = env.rpc;
12+
payer = env.payer;
13+
});
14+
15+
it("creates token pool", async () => {
16+
const { mint } = await createTestMint(rpc, payer);
17+
18+
const poolInfo = await rpc.getAccountInfo(mint);
19+
assert.ok(poolInfo !== null);
20+
});
21+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import * as assert from "assert";
2+
import { setupTestEnvironment, createTestMint, Rpc, web3 } from "./shared";
3+
4+
describe("create-mint", () => {
5+
let rpc: Rpc;
6+
let payer: web3.Keypair;
7+
8+
before(async () => {
9+
const env = await setupTestEnvironment();
10+
rpc = env.rpc;
11+
payer = env.payer;
12+
});
13+
14+
it("creates a compressed mint", async () => {
15+
const { mint, mintAuthority } = await createTestMint(rpc, payer);
16+
17+
const mintInfo = await rpc.getAccountInfo(mint);
18+
assert.ok(mintInfo !== null);
19+
});
20+
21+
it("creates a mint with freeze authority", async () => {
22+
const freezeAuthority = payer.publicKey;
23+
const { mint } = await createTestMint(rpc, payer, 9, freezeAuthority);
24+
25+
const mintInfo = await rpc.getAccountInfo(mint);
26+
assert.ok(mintInfo !== null);
27+
});
28+
});

0 commit comments

Comments
 (0)