Transaction Introspection

Summary

@solana/transaction-introspection turns a getTransaction RPC response into a list of instructions with real addresses. It resolves account indices (including lookup-table addresses), decodes inner CPI instructions, and walks the full instruction tree in explorer order.

Looking for how a program inspects sibling instructions on-chain at runtime? That is the Instructions sysvar - see Instruction Introspection. This page is about decoding a transaction off-chain from an RPC response.

A getTransaction response does not hand you a ready-to-use list of instructions. Accounts are stored as numeric indices, versioned transactions split those accounts into static keys plus addresses loaded from Address Lookup Tables, and inner instructions from cross-program invocations (CPIs) arrive as encoded blobs in the transaction metadata.

@solana/transaction-introspection does this resolution for you. It decodes the wire transaction, maps every account index back to its Address, normalizes the inner instructions, and returns instructions in the same outer-then-inner order a block explorer shows. The returned instructions plug directly into the codama-generated clients' (e.g., @solana-program/* ) parseXInstruction helpers.

Terminal
npm install @solana/transaction-introspection @solana/kit @solana/instructions @solana-program/token

Decode the response

Fetch the transaction with a wire-format encoding and pass the response to decodeTransactionFromRpcResponse.

Decode a transaction
import { createSolanaRpc, signature } from "@solana/kit";
import { decodeTransactionFromRpcResponse } from "@solana/transaction-introspection";
const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
const txid =
"3jUKrQp1UGq5ih6FTDUUt2kkqUfoG2o4kY5T1DoVHK2tXXDLdxJSXzuJGY4JPoRivgbi45U2bc7LZfMa6C4R3szX";
const rpcTx = await rpc
.getTransaction(signature(txid), {
commitment: "confirmed",
encoding: "base64",
maxSupportedTransactionVersion: 0
})
.send();
if (!rpcTx) throw new Error(`Transaction ${txid} not found`);
const { compiledMessage, loadedAddresses } =
decodeTransactionFromRpcResponse(rpcTx);

The remaining snippets reuse rpcTx, compiledMessage, and loadedAddresses from this step.

Fetch with base64, base58, or json encoding. decodeTransactionFromRpcResponse rejects jsonParsed responses - that encoding asks the RPC node to parse instructions server-side, so there is nothing left to decode on the client.

Walk the instructions

walkInstructions returns every instruction - outer and inner - as an array in the order a block explorer shows: each outer instruction followed immediately by the inner instructions its CPIs produced. Each instruction carries a trace field describing where it sits in the call hierarchy.

Walk every instruction
import { walkInstructions } from "@solana/transaction-introspection";
for (const ix of walkInstructions({
compiledMessage,
loadedAddresses,
meta: rpcTx.meta
})) {
const location =
ix.trace.kind === "outer"
? `outer[${ix.trace.index}]`
: `inner[${ix.trace.outerIndex}/${ix.trace.innerIndex}]`;
console.log(location, ix.programAddress, ix.accounts?.length ?? 0);
}

The trace is a discriminated union: { kind: "outer", index } for a top-level instruction, or { kind: "inner", outerIndex, innerIndex, stackHeight? } for a CPI instruction nested under an outer one.

meta is optional - pass rpcTx.meta directly even when it may be null. With no meta, walkInstructions returns only the outer instructions.

Parse with a program client

Each instruction from walkInstructions is a ResolvedInstruction, so it works directly with the predicates from @solana/instructions and the identifyXInstruction / parseXInstruction helpers generated by the @solana-program/* clients - no conversion step.

This example audits every Token Program SyncNative instruction in a transaction, whether it ran at the top level or inside a CPI.

Find and parse SyncNative instructions
import {
isInstructionForProgram,
isInstructionWithAccounts,
isInstructionWithData
} from "@solana/instructions";
import { walkInstructions } from "@solana/transaction-introspection";
import {
identifyTokenInstruction,
parseSyncNativeInstruction,
TOKEN_PROGRAM_ADDRESS,
TokenInstruction
} from "@solana-program/token";
for (const ix of walkInstructions({
compiledMessage,
loadedAddresses,
meta: rpcTx.meta
})) {
if (!isInstructionForProgram(ix, TOKEN_PROGRAM_ADDRESS)) continue;
if (!isInstructionWithData(ix) || !isInstructionWithAccounts(ix)) continue;
if (identifyTokenInstruction(ix) !== TokenInstruction.SyncNative) continue;
const parsed = parseSyncNativeInstruction(ix);
console.log(ix.trace, parsed);
}

Lower-level helpers

walkInstructions covers most needs, but the package also exposes the pieces it builds on:

  • getInstructionsFromCompiledTransactionMessage(compiledMessage, loadedAddresses?) returns only the outer instructions, with resolved accounts and decoded data.
  • getInnerInstructionsFromMeta(meta, accountMetas) decodes the inner CPI instructions from the transaction metadata.
  • getAccountMetasFromCompiledTransactionMessage(compiledMessage, loadedAddresses?) returns the full account list in transaction order - the input the previous helper needs to resolve inner-instruction account indices.
Resolve outer and inner instructions separately
import {
getAccountMetasFromCompiledTransactionMessage,
getInnerInstructionsFromMeta,
getInstructionsFromCompiledTransactionMessage
} from "@solana/transaction-introspection";
const outer = getInstructionsFromCompiledTransactionMessage(
compiledMessage,
loadedAddresses
);
const accountMetas = getAccountMetasFromCompiledTransactionMessage(
compiledMessage,
loadedAddresses
);
if (!rpcTx.meta) throw new Error("Transaction metadata missing");
const inner = getInnerInstructionsFromMeta(rpcTx.meta, accountMetas);

Using Rust?

There is no Rust equivalent of this package. To get parsed instructions from Rust, request UiTransactionEncoding::JsonParsed from getTransaction and let the RPC node resolve accounts and inner instructions for you.

See also

Is this page helpful?

목차

페이지 편집
Transaction Introspection | Solana