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 json, jsonParsed, base64, base58 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 Binary, Base64, Base58, Json, JsonParsed.
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:
- WASM Module: The lib.rs file contains the core encoding logic written in Rust, leveraging Solana's native transaction encoding libraries.
- Encoding Interface: The TypeScript interface in index.ts provides a clean API with:
- Pre-defined encoding formats (
Binary,Base64,Base58,Json,JsonParsed) - Type-safe encoding function that returns the correct type based on the chosen format
- Direct access to raw encoding functions if needed
Memory Management
- Zero-Copy Transfers:
- Uses
wasm_bindgento avoid unnecessary copying - Direct memory access between JavaScript and WASM
- Efficient handling of large transaction batches
- 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.