Skip to content

Commit 0b8d3c8

Browse files
committed
feat(wasm-solana): widen parseTransaction to accept Transaction objects
parseTransaction now accepts Uint8Array, Transaction, or VersionedTransaction directly, avoiding the need for callers to explicitly call .toBytes() when parsing a transaction that was just built. Ticket: BTC-2988
1 parent ec5d77f commit 0b8d3c8

3 files changed

Lines changed: 39 additions & 43 deletions

File tree

packages/wasm-solana/js/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export {
4545
// Type exports
4646
export type { AccountMeta, Instruction } from "./transaction.js";
4747
export type {
48+
TransactionInput,
4849
ParsedTransaction,
4950
DurableNonce,
5051
InstructionParams,

packages/wasm-solana/js/parser.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@
88
*/
99

1010
import { ParserNamespace } from "./wasm/wasm_solana.js";
11+
import type { Transaction } from "./transaction.js";
12+
import type { VersionedTransaction } from "./versioned.js";
13+
14+
/**
15+
* Input type for parseTransaction - accepts bytes or Transaction objects.
16+
*/
17+
export type TransactionInput = Uint8Array | Transaction | VersionedTransaction;
1118

1219
// =============================================================================
1320
// Instruction Types - matching BitGoJS InstructionParams
@@ -273,10 +280,10 @@ export interface ParsedTransaction {
273280
// =============================================================================
274281

275282
/**
276-
* Parse a serialized Solana transaction into structured data.
283+
* Parse a Solana transaction into structured data.
277284
*
278285
* This is the main entry point for transaction parsing. It deserializes the
279-
* transaction bytes and decodes all instructions into semantic types.
286+
* transaction and decodes all instructions into semantic types.
280287
*
281288
* All monetary amounts (amount, fee, lamports, poolTokens) are returned as bigint
282289
* directly from WASM - no post-processing needed.
@@ -285,17 +292,22 @@ export interface ParsedTransaction {
285292
* Consumers (like BitGoJS) may choose to filter NonceAdvance from instructionsData
286293
* since that info is also available in durableNonce.
287294
*
288-
* @param bytes - The raw transaction bytes (wire format)
295+
* @param input - Raw transaction bytes, Transaction, or VersionedTransaction
289296
* @returns A ParsedTransaction with all instructions decoded
290297
* @throws Error if the transaction cannot be parsed
291298
*
292299
* @example
293300
* ```typescript
294-
* import { parseTransaction } from '@bitgo/wasm-solana';
301+
* import { parseTransaction, buildTransaction, Transaction } from '@bitgo/wasm-solana';
295302
*
303+
* // From bytes
296304
* const txBytes = Buffer.from(base64EncodedTx, 'base64');
297305
* const parsed = parseTransaction(txBytes);
298306
*
307+
* // Directly from a Transaction object (no roundtrip through bytes)
308+
* const tx = buildTransaction(intent);
309+
* const parsed = parseTransaction(tx);
310+
*
299311
* console.log(parsed.feePayer);
300312
* for (const instr of parsed.instructionsData) {
301313
* if (instr.type === 'Transfer') {
@@ -304,6 +316,8 @@ export interface ParsedTransaction {
304316
* }
305317
* ```
306318
*/
307-
export function parseTransaction(bytes: Uint8Array): ParsedTransaction {
319+
export function parseTransaction(input: TransactionInput): ParsedTransaction {
320+
// If input is a Transaction or VersionedTransaction, extract bytes
321+
const bytes = input instanceof Uint8Array ? input : input.toBytes();
308322
return ParserNamespace.parse_transaction(bytes) as ParsedTransaction;
309323
}

packages/wasm-solana/test/builder.ts

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ describe("buildTransaction", () => {
3030
assert.ok(txBytes instanceof Uint8Array);
3131
assert.ok(txBytes.length > 0);
3232

33-
// Parse it back to verify structure
34-
const parsed = parseTransaction(txBytes);
33+
const parsed = parseTransaction(tx);
3534
assert.strictEqual(parsed.feePayer, SENDER);
3635
assert.strictEqual(parsed.nonce, BLOCKHASH);
3736
assert.strictEqual(parsed.instructionsData.length, 1);
@@ -53,8 +52,7 @@ describe("buildTransaction", () => {
5352
};
5453

5554
const tx = buildTransaction(intent);
56-
const txBytes = tx.toBytes();
57-
const parsed = parseTransaction(txBytes);
55+
const parsed = parseTransaction(tx);
5856

5957
const transfer = parsed.instructionsData[0];
6058
assert.strictEqual(transfer.type, "Transfer");
@@ -79,8 +77,7 @@ describe("buildTransaction", () => {
7977
};
8078

8179
const tx = buildTransaction(intent);
82-
const txBytes = tx.toBytes();
83-
const parsed = parseTransaction(txBytes);
80+
const parsed = parseTransaction(tx);
8481

8582
assert.strictEqual(parsed.instructionsData.length, 2);
8683
assert.strictEqual(parsed.instructionsData[0].type, "Transfer");
@@ -106,8 +103,7 @@ describe("buildTransaction", () => {
106103
};
107104

108105
const tx = buildTransaction(intent);
109-
const txBytes = tx.toBytes();
110-
const parsed = parseTransaction(txBytes);
106+
const parsed = parseTransaction(tx);
111107

112108
assert.strictEqual(parsed.instructionsData.length, 2);
113109
assert.strictEqual(parsed.instructionsData[0].type, "SetComputeUnitLimit");
@@ -130,8 +126,7 @@ describe("buildTransaction", () => {
130126
};
131127

132128
const tx = buildTransaction(intent);
133-
const txBytes = tx.toBytes();
134-
const parsed = parseTransaction(txBytes);
129+
const parsed = parseTransaction(tx);
135130

136131
assert.strictEqual(parsed.instructionsData.length, 2);
137132
assert.strictEqual(parsed.instructionsData[0].type, "SetPriorityFee");
@@ -164,8 +159,7 @@ describe("buildTransaction", () => {
164159
};
165160

166161
const tx = buildTransaction(intent);
167-
const txBytes = tx.toBytes();
168-
const parsed = parseTransaction(txBytes);
162+
const parsed = parseTransaction(tx);
169163

170164
// Should have 2 instructions: NonceAdvance + Transfer
171165
assert.strictEqual(parsed.instructionsData.length, 2);
@@ -204,8 +198,7 @@ describe("buildTransaction", () => {
204198
};
205199

206200
const tx = buildTransaction(intent);
207-
const txBytes = tx.toBytes();
208-
const parsed = parseTransaction(txBytes);
201+
const parsed = parseTransaction(tx);
209202

210203
assert.strictEqual(parsed.instructionsData.length, 1);
211204
assert.strictEqual(parsed.instructionsData[0].type, "CreateAccount");
@@ -293,8 +286,7 @@ describe("buildTransaction", () => {
293286
};
294287

295288
const tx = buildTransaction(intent);
296-
const txBytes = tx.toBytes();
297-
const parsed = parseTransaction(txBytes);
289+
const parsed = parseTransaction(tx);
298290

299291
assert.strictEqual(parsed.instructionsData.length, 1);
300292
assert.strictEqual(parsed.instructionsData[0].type, "StakeInitialize");
@@ -322,8 +314,7 @@ describe("buildTransaction", () => {
322314
};
323315

324316
const tx = buildTransaction(intent);
325-
const txBytes = tx.toBytes();
326-
const parsed = parseTransaction(txBytes);
317+
const parsed = parseTransaction(tx);
327318

328319
assert.strictEqual(parsed.instructionsData.length, 1);
329320
assert.strictEqual(parsed.instructionsData[0].type, "StakingDelegate");
@@ -350,8 +341,7 @@ describe("buildTransaction", () => {
350341
};
351342

352343
const tx = buildTransaction(intent);
353-
const txBytes = tx.toBytes();
354-
const parsed = parseTransaction(txBytes);
344+
const parsed = parseTransaction(tx);
355345

356346
assert.strictEqual(parsed.instructionsData.length, 1);
357347
assert.strictEqual(parsed.instructionsData[0].type, "StakingDeactivate");
@@ -379,8 +369,7 @@ describe("buildTransaction", () => {
379369
};
380370

381371
const tx = buildTransaction(intent);
382-
const txBytes = tx.toBytes();
383-
const parsed = parseTransaction(txBytes);
372+
const parsed = parseTransaction(tx);
384373

385374
assert.strictEqual(parsed.instructionsData.length, 1);
386375
assert.strictEqual(parsed.instructionsData[0].type, "StakingWithdraw");
@@ -426,8 +415,7 @@ describe("buildTransaction", () => {
426415
};
427416

428417
const tx = buildTransaction(intent);
429-
const txBytes = tx.toBytes();
430-
const parsed = parseTransaction(txBytes);
418+
const parsed = parseTransaction(tx);
431419

432420
// Parser returns individual instructions; combining is done in BitGoJS wasmInstructionCombiner
433421
assert.strictEqual(parsed.instructionsData.length, 3);
@@ -477,8 +465,7 @@ describe("buildTransaction", () => {
477465
};
478466

479467
const tx = buildTransaction(intent);
480-
const txBytes = tx.toBytes();
481-
const parsed = parseTransaction(txBytes);
468+
const parsed = parseTransaction(tx);
482469

483470
assert.strictEqual(parsed.instructionsData.length, 1);
484471
assert.strictEqual(parsed.instructionsData[0].type, "TokenTransfer");
@@ -508,8 +495,7 @@ describe("buildTransaction", () => {
508495
};
509496

510497
const tx = buildTransaction(intent);
511-
const txBytes = tx.toBytes();
512-
const parsed = parseTransaction(txBytes);
498+
const parsed = parseTransaction(tx);
513499

514500
assert.strictEqual(parsed.instructionsData.length, 1);
515501
assert.strictEqual(parsed.instructionsData[0].type, "CreateAssociatedTokenAccount");
@@ -537,8 +523,7 @@ describe("buildTransaction", () => {
537523
};
538524

539525
const tx = buildTransaction(intent);
540-
const txBytes = tx.toBytes();
541-
const parsed = parseTransaction(txBytes);
526+
const parsed = parseTransaction(tx);
542527

543528
assert.strictEqual(parsed.instructionsData.length, 1);
544529
assert.strictEqual(parsed.instructionsData[0].type, "CloseAssociatedTokenAccount");
@@ -576,8 +561,7 @@ describe("buildTransaction", () => {
576561
};
577562

578563
const tx = buildTransaction(intent);
579-
const txBytes = tx.toBytes();
580-
const parsed = parseTransaction(txBytes);
564+
const parsed = parseTransaction(tx);
581565

582566
assert.strictEqual(parsed.instructionsData.length, 3);
583567
assert.strictEqual(parsed.instructionsData[0].type, "CreateAssociatedTokenAccount");
@@ -620,8 +604,7 @@ describe("buildTransaction", () => {
620604
};
621605

622606
const tx = buildTransaction(intent);
623-
const txBytes = tx.toBytes();
624-
const parsed = parseTransaction(txBytes);
607+
const parsed = parseTransaction(tx);
625608

626609
assert.strictEqual(parsed.instructionsData.length, 1);
627610
assert.strictEqual(parsed.instructionsData[0].type, "StakePoolDepositSol");
@@ -658,8 +641,7 @@ describe("buildTransaction", () => {
658641
};
659642

660643
const tx = buildTransaction(intent);
661-
const txBytes = tx.toBytes();
662-
const parsed = parseTransaction(txBytes);
644+
const parsed = parseTransaction(tx);
663645

664646
assert.strictEqual(parsed.instructionsData.length, 1);
665647
assert.strictEqual(parsed.instructionsData[0].type, "StakePoolWithdrawStake");
@@ -702,8 +684,7 @@ describe("buildTransaction", () => {
702684
};
703685

704686
const tx = buildTransaction(intent);
705-
const txBytes = tx.toBytes();
706-
const parsed = parseTransaction(txBytes);
687+
const parsed = parseTransaction(tx);
707688

708689
assert.strictEqual(parsed.instructionsData.length, 2);
709690
assert.strictEqual(parsed.instructionsData[0].type, "CreateAssociatedTokenAccount");

0 commit comments

Comments
 (0)