Parse Solana transactions in TypeScript

Parse Solana transactions in TypeScript

The transactions received from Yellowstone Dragon’s Mouth gRPC in your Solana applications are in raw binary format. The data received from Solana RPC supports the jsonjsonParsedbase64base58 formats. In your applications you need to encode/parse the data and writing parsers is not an easy task.

At the very least, if you’re switching from RPC getTransaction or websockets to gRPC to get transaction data, you’d want it in json or jsonParsed. The encode function from the Rust crate solana_transaction_status does the encoding in Rust and there’s no easy way to do it in TypeScript/JavaScript until now.

We took the VersionedTransactionWithStatusMeta.encode and put it in WASM to make it available in TypeScript.

Usage

The encode function is available in the @triton-one/yellowstone-grpc v1.2.0. You can find the full usage example here

stream.on("data", (data) => {
    if (
      data.transaction &&
      (args.transactionsParsed || args.transactionsDecodeErr)
    ) {
      const slot = data.transaction.slot;
      const message = data.transaction.transaction;
      if (args.transactionsParsed) {

        // Encoding raw transaction into `jsonParsed`
        const tx = txEncode.encode(message, txEncode.encoding.JsonParsed, 255, true);

        console.log(
          `TX filters: ${data.filters}, slot#${slot}, tx: ${JSON.stringify(tx)}`
        );
      }
      if (message.meta.err && args.transactionsDecodeErr) {
        const err = txErrDecode.decode(message.meta.err.err);
        console.log(
          `TX filters: ${data.filters}, slot#${slot}, err: ${inspect(err)}}`
        );
      }
      return;
    }

    console.log("data", data);
  });

The function syntax is as follows:

import { txEncode } from "@triton-one/yellowstone-grpc";

// Encode a transaction into Base58 format
const encodedTx = txEncode.encode(
  message,                      // SubscribeUpdateTransactionInfo message
  txEncode.encoding.Base58,     // Desired encoding format
  0,                            // Max supported transaction version
  true                          // Show rewards
);

The supported encodings are BinaryBase64Base58JsonJsonParsed.

How It Works

The transaction encoding functionality is implemented as a WebAssembly module in solana-encoding-wasm. The Rust code compiles to WASM and exposes encoding functions that are called from TypeScript.

The key components are:

  1. WASM Module: The lib.rs file contains the core encoding logic written in Rust, leveraging Solana's native transaction encoding libraries.
  2. Encoding Interface: The TypeScript interface in index.ts provides a clean API with:
  • Pre-defined encoding formats (BinaryBase64Base58JsonJsonParsed)
  • Type-safe encoding function that returns the correct type based on the chosen format
  • Direct access to raw encoding functions if needed

Memory Management

  1. Zero-Copy Transfers:
  • Uses wasm_bindgen to avoid unnecessary copying
  • Direct memory access between JavaScript and WASM
  • Efficient handling of large transaction batches
  1. Memory Layout:

[JavaScript Heap] <-> [WASM Linear Memory] <-> [Rust Stack]

Conclusion

The WASM based encoder/parser aims to provide ease of development with gRPC as well as make migration to gRPC based system seamless.

If you need a break from WASM, checkout other cool stuff Triton has.