@unclaimedsol/spl-burn-close-sdk 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ ## 1.3.0
4
+
5
+ - Preserve the fetched blockhash's `lastValidBlockHeight` on built transactions and add
6
+ an optional matching height for caller-supplied blockhashes.
7
+ - Reject non-finite, non-positive, and fractional `chunkSize` values at build time,
8
+ including on empty input. The default remains 12.
9
+ - Validate unsigned serialization during building. Oversized transactions raise a clear
10
+ size error at build time instead of failing later when sent; other serialization failures
11
+ (for example an invalid blockhash or account key) report the original error as `cause`.
12
+ Choose a smaller chunk size; additional caller instructions still count against 1,232 bytes.
13
+ - Fix CommonJS TypeScript resolution with separate import/require declaration exports.
14
+ - Correct the documented hybrid fee and confirmation examples; describe compute-budget
15
+ considerations without adding a default compute-budget instruction.
16
+ - Add instruction, batching, expiry, documentation and packed-package tests with CI.
17
+
18
+ Existing instruction encoding, asynchronous helpers and return types remain unchanged.
package/README.md CHANGED
@@ -1,13 +1,14 @@
1
1
  # Burn and Close Solana SPL Tokens SDK
2
2
 
3
- A lightweight Solana SDK to **burn SPL tokens and close token accounts** with a **fixed 5%** protocol fee.
3
+ A lightweight Solana SDK to **burn SPL tokens and close token accounts** with the June 2026 Unclaimed SOL token cleanup fee policy.
4
4
  This library only **builds unsigned transactions** – you handle signing and sending them, whether in the browser (Wallet Adapter) or server (Keypair).
5
5
 
6
6
  ## ✨ Features
7
7
 
8
8
  - 🔥 Burn all tokens in provided ATAs.
9
9
  - 🧹 Close token accounts, reclaiming rent to the user.
10
- - 💸 Automatic 5% protocol fee (hardcoded in program).
10
+ - 💸 On-chain fee recipient is enforced by the program.
11
+ - 🧾 Hybrid cleanup fee: `max(floor(gross * 200 / 10000), gross - 2,000,000)` lamports per closed account. For 2,039,280 lamports recovered, the fee is 40,785 lamports.
11
12
  - ⚡ Automatic batching (default 12 ATAs per transaction).
12
13
  - 🪙 Supports SPL Token and Token-2022.
13
14
  - 🔐 Supports **frontend partial signing** and **backend full signing** workflows.
@@ -19,7 +20,7 @@ This library only **builds unsigned transactions** – you handle signing and se
19
20
 
20
21
  1. The SDK prepares TransactionInstructions for your on-chain burn+close program.
21
22
  2. Program burns tokens in each ATA, then closes it, sending rent back to the owner.
22
- 3. A 5% fee is enforced on-chain and sent to the hardcoded recipient.
23
+ 3. The program sends the greater of 2% of recovered rent (rounded down) or the amount above 2,000,000 lamports to the hardcoded fee recipient, per successfully closed account.
23
24
  4. The SDK never asks for private keys — you sign & send transactions yourself.
24
25
 
25
26
  ---
@@ -32,7 +33,9 @@ npm i @unclaimedsol/spl-burn-close-sdk
32
33
 
33
34
  We use @solana/web3.js in peerDependencies to avoid version conflicts, so make sure you already have it installed.
34
35
 
35
- Requires Node 18+.
36
+ Requires Node 18+. On Node 18, use a compatible locked dependency graph for web3.js;
37
+ fresh dependency resolution can select an ESM-only `uuid` through `rpc-websockets`
38
+ that breaks CommonJS loading. CI tests the repository’s locked dependency graph.
36
39
 
37
40
  ---
38
41
 
@@ -64,15 +67,15 @@ const txs = await buildBurnAndCloseTransactions(
64
67
  for (const tx of txs) {
65
68
  tx.partialSign(keypair);
66
69
  const sig = await connection.sendRawTransaction(tx.serialize());
67
- let latestBlockhash = await connection.getLatestBlockhash(
68
- connection.commitment
69
- );
70
- await connection.confirmTransaction({
70
+ const confirmation = await connection.confirmTransaction({
71
71
  signature: sig,
72
- blockhash: latestBlockhash.blockhash,
73
- lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
72
+ blockhash: tx.recentBlockhash!,
73
+ lastValidBlockHeight: tx.lastValidBlockHeight!,
74
74
  });
75
- console.log("✅ Sent:", sig);
75
+ if (confirmation.value.err) {
76
+ throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`);
77
+ }
78
+ console.log("✅ Confirmed:", sig);
76
79
  }
77
80
  ```
78
81
 
@@ -108,7 +111,7 @@ const txs = await buildBurnAndCloseTransactions(
108
111
  // PROGRAM_ID,
109
112
  // user,
110
113
  // pairs,
111
- // { chunkSize: 2 },
114
+ // { chunkSize: 3 },
112
115
  // TOKEN_2022_PROGRAM_ID
113
116
  // );
114
117
 
@@ -118,22 +121,47 @@ const signed = wallet.signAllTransactions
118
121
  : await Promise.all(txs.map((t) => wallet.signTransaction!(t)));
119
122
 
120
123
  // Send
121
- for (const stx of signed) {
124
+ for (const [index, stx] of signed.entries()) {
125
+ // Wallets may reconstruct transactions and omit expiry metadata.
126
+ const tx = txs[index];
122
127
  const sig = await connection.sendRawTransaction(stx.serialize());
123
- let latestBlockhash = await connection.getLatestBlockhash(
124
- connection.commitment
125
- );
126
- await connection.confirmTransaction({
128
+ const confirmation = await connection.confirmTransaction({
127
129
  signature: sig,
128
- blockhash: latestBlockhash.blockhash,
129
- lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
130
+ blockhash: tx.recentBlockhash!,
131
+ lastValidBlockHeight: tx.lastValidBlockHeight!,
130
132
  });
131
- console.log("✅ Sent:", sig);
133
+ if (confirmation.value.err) {
134
+ throw new Error(`Transaction failed: ${JSON.stringify(confirmation.value.err)}`);
135
+ }
136
+ console.log("✅ Confirmed:", sig);
132
137
  }
133
138
  ```
134
139
 
135
140
  ---
136
141
 
142
+ ## Batching and blockhash expiry
143
+
144
+ `chunkSize` defaults to 12 and must be a finite positive integer. Invalid values and
145
+ transactions that cannot serialize within the legacy 1,232-byte limit now throw during
146
+ building. Size depends on unique accounts and signers, including a separate fee payer;
147
+ there is no fixed pair cap. Instructions added afterwards (including compute budget or
148
+ memo instructions) count against the same limit, so recheck size after adding them.
149
+
150
+ The app uses batches of 10 classic token accounts or 3 Token-2022 accounts and also adds
151
+ a compute-unit limit. These are production configuration values, not a guarantee for
152
+ every workload; this release did not simulate their compute usage. The SDK adds no
153
+ compute-budget instruction. Choose a batch size and compute budget for your workload.
154
+
155
+ Fetched transactions carry `recentBlockhash` and its matching `lastValidBlockHeight`.
156
+ If you supply `recentBlockhash`, supply its matching `lastValidBlockHeight` too when using
157
+ the confirmation examples above. Without an explicit height it remains undefined; the
158
+ SDK never fetches a height for a caller-supplied blockhash. A height supplied without a
159
+ blockhash is ignored in favor of the fetched pair. Confirm using the original transaction
160
+ metadata, even if the wallet returns a reconstructed signed transaction.
161
+
162
+ Instruction data is a browser-safe `Uint8Array` typed as `Buffer` for web3.js compatibility;
163
+ do not call Buffer-only methods on it.
164
+
137
165
  ## 🌐 Cluster support
138
166
 
139
167
  This SDK targets the Unclaimed SOL mainnet program (`PROGRAM_ID`) and fee recipient (`FEE_RECIPIENT`).
package/dist/index.cjs CHANGED
@@ -10,6 +10,17 @@ exports.PROGRAM_ID = new web3_js_1.PublicKey("UNCaXzXkR3vp8mbCJyxWUvwuRk5uHgzrwe
10
10
  exports.FEE_RECIPIENT = new web3_js_1.PublicKey("uncNCRycMtNPj2kXHfwiCgNrzCTnC9xU5FS8ZeWyn3M");
11
11
  exports.TOKEN_PROGRAM_ID = new web3_js_1.PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
12
12
  exports.TOKEN_2022_PROGRAM_ID = new web3_js_1.PublicKey("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb");
13
+ /** Legacy transaction wire limit, including the signature-count prefix and signature slots. */
14
+ const PACKET_DATA_SIZE = 1232;
15
+ function packetSizeError() {
16
+ return new Error("Burn and close: transaction could not be serialized within the 1,232-byte limit. " +
17
+ "Reduce chunkSize.");
18
+ }
19
+ /** web3.js reports oversized messages as "Transaction too large" or a buffer overrun. */
20
+ function isPacketSizeError(error) {
21
+ const message = error instanceof Error ? error.message : String(error);
22
+ return /Transaction too large|encoding overruns (?:Uint8Array|Buffer)/i.test(message);
23
+ }
13
24
  /**
14
25
  * Build *unsigned* transactions that call the on-chain burn+close program.
15
26
  * You sign and send them yourself (frontend wallet or backend keypair).
@@ -23,12 +34,15 @@ exports.TOKEN_2022_PROGRAM_ID = new web3_js_1.PublicKey("TokenzQdBNbLqP5VEhdkAS6
23
34
  * @returns Array of *unsigned* Transaction objects
24
35
  */
25
36
  async function buildBurnAndCloseTransactions(connection, programId, user, pairs, options = {}, tokenProgramId = exports.TOKEN_PROGRAM_ID) {
37
+ const chunkSize = options.chunkSize ?? 12;
38
+ if (!Number.isFinite(chunkSize) || !Number.isInteger(chunkSize) || chunkSize <= 0) {
39
+ throw new Error("Burn and close: chunkSize must be a finite positive integer.");
40
+ }
26
41
  if (!pairs.length)
27
42
  return [];
28
- const chunkSize = Math.max(1, options.chunkSize ?? 12);
29
43
  const commitment = options.commitment ?? "confirmed";
30
44
  const feePayer = options.feePayer ?? user;
31
- // Split into chunks so we stay under CU / account limits
45
+ // Split into batches; callers must choose a suitable compute budget.
32
46
  const chunks = [];
33
47
  for (let i = 0; i < pairs.length; i += chunkSize) {
34
48
  chunks.push(pairs.slice(i, i + chunkSize));
@@ -36,8 +50,9 @@ async function buildBurnAndCloseTransactions(connection, programId, user, pairs,
36
50
  // Instruction data: [selector=0]
37
51
  // Use Uint8Array (browser-safe) and cast for web3.js' Buffer typing.
38
52
  const data = new Uint8Array([0]);
39
- const recentBlockhash = options.recentBlockhash ??
40
- (await connection.getLatestBlockhash({ commitment })).blockhash;
53
+ const { blockhash, lastValidBlockHeight } = options.recentBlockhash !== undefined
54
+ ? { blockhash: options.recentBlockhash, lastValidBlockHeight: options.lastValidBlockHeight }
55
+ : await connection.getLatestBlockhash({ commitment });
41
56
  const txs = [];
42
57
  for (const chunk of chunks) {
43
58
  const keys = [
@@ -58,7 +73,22 @@ async function buildBurnAndCloseTransactions(connection, programId, user, pairs,
58
73
  });
59
74
  const tx = new web3_js_1.Transaction().add(ix);
60
75
  tx.feePayer = feePayer;
61
- tx.recentBlockhash = recentBlockhash;
76
+ tx.recentBlockhash = blockhash;
77
+ tx.lastValidBlockHeight = lastValidBlockHeight;
78
+ let wireSize;
79
+ try {
80
+ wireSize = tx.serialize({ requireAllSignatures: false }).length;
81
+ }
82
+ catch (error) {
83
+ if (isPacketSizeError(error)) {
84
+ throw packetSizeError();
85
+ }
86
+ throw new Error("Burn and close: transaction could not be serialized. " +
87
+ "Check the supplied transaction inputs, including recentBlockhash and account keys.", { cause: error });
88
+ }
89
+ if (wireSize > PACKET_DATA_SIZE) {
90
+ throw packetSizeError();
91
+ }
62
92
  txs.push(tx);
63
93
  }
64
94
  return txs;
@@ -70,6 +100,8 @@ async function buildBurnAndCloseTransactions(connection, programId, user, pairs,
70
100
  * Unlike `buildBurnAndCloseTransactions`, this helper does **not**
71
101
  * create or sign full transactions — it only constructs one
72
102
  * instruction for a batch of (mint, ATA) pairs.
103
+ * Instruction data is a browser-safe Uint8Array, typed as Buffer for web3.js;
104
+ * do not rely on Buffer-only methods on the returned data.
73
105
  */
74
106
  async function buildBurnAndCloseInstruction(programId, user, pairs, tokenProgramId) {
75
107
  if (!pairs.length) {
@@ -0,0 +1,53 @@
1
+ import { Connection, PublicKey, Transaction, TransactionInstruction, Commitment } from "@solana/web3.js";
2
+ /** Exporting on-chain program ID for convenience */
3
+ export declare const PROGRAM_ID: PublicKey;
4
+ /** Hardcoded fee recipient on-chain expectation */
5
+ export declare const FEE_RECIPIENT: PublicKey;
6
+ export declare const TOKEN_PROGRAM_ID: PublicKey;
7
+ export declare const TOKEN_2022_PROGRAM_ID: PublicKey;
8
+ export type Pair = {
9
+ mint: PublicKey;
10
+ ata: PublicKey;
11
+ };
12
+ export type BuildOptions = {
13
+ /** Max pairs per transaction: a finite positive integer (default: 12). */
14
+ chunkSize?: number;
15
+ /** Use this commitment when fetching blockhash (default: "confirmed") */
16
+ commitment?: Commitment;
17
+ /**
18
+ * Optional explicit fee payer (defaults to `user`)
19
+ * Note: whoever signs must cover fees on-chain.
20
+ */
21
+ feePayer?: PublicKey;
22
+ /**
23
+ * Provide your own recent blockhash (advanced). If omitted,
24
+ * we fetch a fresh one and reuse it for all built transactions.
25
+ */
26
+ recentBlockhash?: string;
27
+ /** Expiry height matching recentBlockhash; ignored when the blockhash is fetched. */
28
+ lastValidBlockHeight?: number;
29
+ };
30
+ /**
31
+ * Build *unsigned* transactions that call the on-chain burn+close program.
32
+ * You sign and send them yourself (frontend wallet or backend keypair).
33
+ *
34
+ * @param connection Solana RPC connection
35
+ * @param programId Your deployed program ID
36
+ * @param user The user whose ATAs will be burned/closed
37
+ * @param pairs Array of { mint, ata } to process
38
+ * @param options Chunking / blockhash / payer tweaks
39
+ * @param tokenProgramId Support for multiple Token programs
40
+ * @returns Array of *unsigned* Transaction objects
41
+ */
42
+ export declare function buildBurnAndCloseTransactions(connection: Connection, programId: PublicKey, user: PublicKey, pairs: Pair[], options?: BuildOptions, tokenProgramId?: PublicKey): Promise<Transaction[]>;
43
+ /**
44
+ * Build a single **TransactionInstruction** that calls the on-chain
45
+ * burn+close program for a specific Token Program (either SPL Token or Token-2022).
46
+ *
47
+ * Unlike `buildBurnAndCloseTransactions`, this helper does **not**
48
+ * create or sign full transactions — it only constructs one
49
+ * instruction for a batch of (mint, ATA) pairs.
50
+ * Instruction data is a browser-safe Uint8Array, typed as Buffer for web3.js;
51
+ * do not rely on Buffer-only methods on the returned data.
52
+ */
53
+ export declare function buildBurnAndCloseInstruction(programId: PublicKey, user: PublicKey, pairs: Pair[], tokenProgramId: PublicKey): Promise<TransactionInstruction | null>;
package/dist/index.d.ts CHANGED
@@ -10,7 +10,7 @@ export type Pair = {
10
10
  ata: PublicKey;
11
11
  };
12
12
  export type BuildOptions = {
13
- /** Max pairs per transaction (default: 12) */
13
+ /** Max pairs per transaction: a finite positive integer (default: 12). */
14
14
  chunkSize?: number;
15
15
  /** Use this commitment when fetching blockhash (default: "confirmed") */
16
16
  commitment?: Commitment;
@@ -24,6 +24,8 @@ export type BuildOptions = {
24
24
  * we fetch a fresh one and reuse it for all built transactions.
25
25
  */
26
26
  recentBlockhash?: string;
27
+ /** Expiry height matching recentBlockhash; ignored when the blockhash is fetched. */
28
+ lastValidBlockHeight?: number;
27
29
  };
28
30
  /**
29
31
  * Build *unsigned* transactions that call the on-chain burn+close program.
@@ -45,5 +47,7 @@ export declare function buildBurnAndCloseTransactions(connection: Connection, pr
45
47
  * Unlike `buildBurnAndCloseTransactions`, this helper does **not**
46
48
  * create or sign full transactions — it only constructs one
47
49
  * instruction for a batch of (mint, ATA) pairs.
50
+ * Instruction data is a browser-safe Uint8Array, typed as Buffer for web3.js;
51
+ * do not rely on Buffer-only methods on the returned data.
48
52
  */
49
53
  export declare function buildBurnAndCloseInstruction(programId: PublicKey, user: PublicKey, pairs: Pair[], tokenProgramId: PublicKey): Promise<TransactionInstruction | null>;
package/dist/index.js CHANGED
@@ -5,6 +5,17 @@ export const PROGRAM_ID = new PublicKey("UNCaXzXkR3vp8mbCJyxWUvwuRk5uHgzrwe6jcWP
5
5
  export const FEE_RECIPIENT = new PublicKey("uncNCRycMtNPj2kXHfwiCgNrzCTnC9xU5FS8ZeWyn3M");
6
6
  export const TOKEN_PROGRAM_ID = new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
7
7
  export const TOKEN_2022_PROGRAM_ID = new PublicKey("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb");
8
+ /** Legacy transaction wire limit, including the signature-count prefix and signature slots. */
9
+ const PACKET_DATA_SIZE = 1232;
10
+ function packetSizeError() {
11
+ return new Error("Burn and close: transaction could not be serialized within the 1,232-byte limit. " +
12
+ "Reduce chunkSize.");
13
+ }
14
+ /** web3.js reports oversized messages as "Transaction too large" or a buffer overrun. */
15
+ function isPacketSizeError(error) {
16
+ const message = error instanceof Error ? error.message : String(error);
17
+ return /Transaction too large|encoding overruns (?:Uint8Array|Buffer)/i.test(message);
18
+ }
8
19
  /**
9
20
  * Build *unsigned* transactions that call the on-chain burn+close program.
10
21
  * You sign and send them yourself (frontend wallet or backend keypair).
@@ -18,12 +29,15 @@ export const TOKEN_2022_PROGRAM_ID = new PublicKey("TokenzQdBNbLqP5VEhdkAS6EPFLC
18
29
  * @returns Array of *unsigned* Transaction objects
19
30
  */
20
31
  export async function buildBurnAndCloseTransactions(connection, programId, user, pairs, options = {}, tokenProgramId = TOKEN_PROGRAM_ID) {
32
+ const chunkSize = options.chunkSize ?? 12;
33
+ if (!Number.isFinite(chunkSize) || !Number.isInteger(chunkSize) || chunkSize <= 0) {
34
+ throw new Error("Burn and close: chunkSize must be a finite positive integer.");
35
+ }
21
36
  if (!pairs.length)
22
37
  return [];
23
- const chunkSize = Math.max(1, options.chunkSize ?? 12);
24
38
  const commitment = options.commitment ?? "confirmed";
25
39
  const feePayer = options.feePayer ?? user;
26
- // Split into chunks so we stay under CU / account limits
40
+ // Split into batches; callers must choose a suitable compute budget.
27
41
  const chunks = [];
28
42
  for (let i = 0; i < pairs.length; i += chunkSize) {
29
43
  chunks.push(pairs.slice(i, i + chunkSize));
@@ -31,8 +45,9 @@ export async function buildBurnAndCloseTransactions(connection, programId, user,
31
45
  // Instruction data: [selector=0]
32
46
  // Use Uint8Array (browser-safe) and cast for web3.js' Buffer typing.
33
47
  const data = new Uint8Array([0]);
34
- const recentBlockhash = options.recentBlockhash ??
35
- (await connection.getLatestBlockhash({ commitment })).blockhash;
48
+ const { blockhash, lastValidBlockHeight } = options.recentBlockhash !== undefined
49
+ ? { blockhash: options.recentBlockhash, lastValidBlockHeight: options.lastValidBlockHeight }
50
+ : await connection.getLatestBlockhash({ commitment });
36
51
  const txs = [];
37
52
  for (const chunk of chunks) {
38
53
  const keys = [
@@ -53,7 +68,22 @@ export async function buildBurnAndCloseTransactions(connection, programId, user,
53
68
  });
54
69
  const tx = new Transaction().add(ix);
55
70
  tx.feePayer = feePayer;
56
- tx.recentBlockhash = recentBlockhash;
71
+ tx.recentBlockhash = blockhash;
72
+ tx.lastValidBlockHeight = lastValidBlockHeight;
73
+ let wireSize;
74
+ try {
75
+ wireSize = tx.serialize({ requireAllSignatures: false }).length;
76
+ }
77
+ catch (error) {
78
+ if (isPacketSizeError(error)) {
79
+ throw packetSizeError();
80
+ }
81
+ throw new Error("Burn and close: transaction could not be serialized. " +
82
+ "Check the supplied transaction inputs, including recentBlockhash and account keys.", { cause: error });
83
+ }
84
+ if (wireSize > PACKET_DATA_SIZE) {
85
+ throw packetSizeError();
86
+ }
57
87
  txs.push(tx);
58
88
  }
59
89
  return txs;
@@ -65,6 +95,8 @@ export async function buildBurnAndCloseTransactions(connection, programId, user,
65
95
  * Unlike `buildBurnAndCloseTransactions`, this helper does **not**
66
96
  * create or sign full transactions — it only constructs one
67
97
  * instruction for a batch of (mint, ATA) pairs.
98
+ * Instruction data is a browser-safe Uint8Array, typed as Buffer for web3.js;
99
+ * do not rely on Buffer-only methods on the returned data.
68
100
  */
69
101
  export async function buildBurnAndCloseInstruction(programId, user, pairs, tokenProgramId) {
70
102
  if (!pairs.length) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unclaimedsol/spl-burn-close-sdk",
3
- "version": "1.2.1",
4
- "description": "SDK to burn and close SPL token accounts via the Unclaimed SOL program (with a built-in 5% fee).",
3
+ "version": "1.3.0",
4
+ "description": "Build unsigned Solana transactions to burn SPL tokens, close token accounts, and reclaim rent with the Unclaimed SOL program.",
5
5
  "license": "MIT",
6
6
  "author": "Unclaimed SOL",
7
7
  "type": "module",
@@ -15,9 +15,14 @@
15
15
  },
16
16
  "exports": {
17
17
  ".": {
18
- "types": "./dist/index.d.ts",
19
- "import": "./dist/index.js",
20
- "require": "./dist/index.cjs"
18
+ "import": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.js"
21
+ },
22
+ "require": {
23
+ "types": "./dist/index.d.cts",
24
+ "default": "./dist/index.cjs"
25
+ }
21
26
  }
22
27
  },
23
28
  "main": "./dist/index.cjs",
@@ -25,11 +30,14 @@
25
30
  "types": "./dist/index.d.ts",
26
31
  "files": [
27
32
  "dist",
28
- "README.md"
33
+ "README.md",
34
+ "CHANGELOG.md"
29
35
  ],
30
36
  "scripts": {
31
37
  "build": "tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && node ./scripts/build-cjs.js",
32
- "prepublishOnly": "npm run build"
38
+ "prepack": "npm run build",
39
+ "test": "npm run build && node --test test/*.test.js",
40
+ "test:package": "node scripts/test-package.js"
33
41
  },
34
42
  "peerDependencies": {
35
43
  "@solana/web3.js": "^1.98.4"