The Transaction Is the Unit of Work
Everything that happens on Solana happens inside a transaction. Account balances change, tokens move, programs execute all of it is packaged into transactions, confirmed by validators, and recorded permanently on-chain.
Solana Explorer makes every transaction readable. But if you're new to Solana, the transaction detail page has a lot of information and it's not immediately obvious what to focus on.
This is a field guide to reading a Solana transaction in Explorer. By the end you'll know what every section means, what to look at first, and how to use transactions to debug your own programs.
Explorer used: explorer.solana.com
How to Find a Transaction
You need a transaction signature the long base58 string that every sendTransaction() call returns. If you've been doing 100 Days of Solana, you've logged hundreds of these to your console and probably never looked at them again.
Go back to any script you've run and grab a signature. Paste it into the Explorer search bar. You'll land on the transaction detail page.
Alternatively: search your wallet address, go to Transaction History, and click any entry.
Section 1: The Header
The first thing you see is the result banner green for success, red for failure. This is the single most important piece of information on the page.
Below that:
Signature The unique identifier for this transaction. This is what you'd share if you wanted someone else to look at the same transaction. Think of it like a receipt number.
Block The slot (Solana's equivalent of a block number) when this transaction was confirmed. Solana produces a new slot roughly every 400ms.
Timestamp When the slot was confirmed. The gap between when you submitted the transaction and this timestamp is your actual confirmation time.
Fee Almost always 5,000 lamports (0.000005 SOL) for standard transactions. This is the base fee. Transactions that consume more compute units may pay higher fees, but for most operations you'll see this flat amount.
Fee Payer The wallet that paid the fee. Usually the transaction signer, but can be a different account if you're building apps that sponsor fees for users.
Section 2: Account Inputs
This section lists every account the transaction touched, with flags showing how each was used.
Writable This account's data or balance was modified by the transaction. If you're transferring SOL, both the sender and recipient are writable.
Signer This account signed the transaction, authorizing it. The fee payer is always a signer. In most user transactions, your wallet is the only signer.
Program This account is a program that was invoked during the transaction. It's not modified by the transaction; it's the code that processed it.
Reading the account inputs list tells you: who authorized this transaction, what accounts were changed, and which programs handled the execution. This is the "cast of characters" for everything that follows.
What to look for: If a transaction failed and you're debugging, check that the accounts you expected to be writable are actually marked writable. A common mistake is forgetting to mark an account as writable when constructing the transaction the runtime will reject it.
Section 3: Instructions
Each instruction in a transaction maps to one program invocation. A simple SOL transfer has one instruction. A DEX swap might have five.
For each instruction you'll see:
- Which program handled it
- The accounts passed to that instruction
- The raw instruction data (usually encoded, but Explorer decodes it for standard programs)
For the System Program's transfer instruction, Explorer shows you the decoded fields: from, to, and lamports. For custom programs without a known IDL, you'll see raw bytes.
What to look for: If a transaction involves multiple instructions and one failed, the instruction breakdown shows you which one. The error will trace back to a specific program invocation, which narrows down where the problem is.
Section 4: Log Messages
This is the most useful section for developers. Every msg!() call from every program invoked in the transaction appears here, in execution order.
A successful simple transfer:
Program 11111111111111111111111111111111 invoke [1]
Program 11111111111111111111111111111111 success
A failed transaction with a custom program:
Program YourProgram1111111111111111111111111111111 invoke [1]
Program log: Checking account ownership
Program log: Error: account not owned by this program
Program YourProgram1111111111111111111111111111111 failed: custom program error: 0x0
The log messages tell you the story of execution. What was checked, what was found, where it went wrong. For any non-trivial program, this is your primary debugging tool.
What to look for: The error message at the end of a failed program invocation. Cross-reference it with the program's source code to find the msg!() or return Err() call that produced it.
Section 5: Token Balances (if applicable)
If the transaction involved SPL tokens, Explorer shows a before/after table for every token account that changed.
This is invaluable for verifying token transfers: you can see the exact amount that moved, from which account, to which account, and confirm it matches what your code intended.
Putting It Together: A Debugging Workflow
When one of your transactions fails:
- Grab the signature from your console output
- Open it in Explorer (switch to devnet if needed)
- Check the result banner failure confirmed
- Read the log messages section from top to bottom
- Find the
failed:line and the error message above it - Trace that error back to your program code
- Check the account inputs are all writable accounts marked writable? Is the right wallet signing?
- Fix, redeploy or re-run, and paste the new signature back into Explorer to verify
This workflow has saved me more debugging time than any other single practice in the challenge. Explorer isn't optional infrastructure it's a core part of the development loop.
Top comments (0)