Expand description
Decode, reconstruct, replay, and mutate Solana transactions.
Point svmscope at a mainnet signature and it (1) decodes the transaction — the full cross-program invocation tree with every instruction named from its on-chain Anchor IDL or known native layout, balance and token changes, and compute units per program; (2) replays it locally in an embedded SVM (LiteSVM), re-executing the real program binaries against the transaction’s reconstructed state; and (3) mutates — change an account’s lamports or data, warp the clock, flip feature gates, then replay again to ask “what if this had been different?”.
§Installation
svmscope is a testing tool, so add it as a dev-dependency:
cargo add --dev svmscopeor in Cargo.toml:
[dev-dependencies]
svmscope = "0.4"§Quickstart
Two nouns: a Scope fetches and caches, a Replay is one transaction’s
reconstructed world. All RPC happens in Scope::replay; every run after
that is local and free.
use svmscope::{Mutation, Scope};
let scope = Scope::new("https://api.mainnet-beta.solana.com");
let sig = "your transaction signature";
// 1. Decode: CPI tree, named instructions, balance/token diffs, CU per program.
let analysis = scope.analyze(sig)?;
println!("fee: {} lamports, {} top-level instructions",
analysis.overview.fee, analysis.cpi_tree.len());
// 2. Replay the real programs locally in LiteSVM.
let mut replay = scope.replay(sig)?;
println!("replay success: {}", replay.run()?.result.success);
// 3. What-if: zero out an account, jump 30 days ahead, and replay again —
// zero further RPC.
replay.advance_seconds(30 * 86_400);
let what_if = replay.simulate(&[Mutation::lamports("SomeAccount111...", 0)])?;
println!("mutated replay success: {}", what_if.result.success);§Building and submitting transactions
You don’t have to start from an existing signature. Against a local
validator, Scope::program_with_idl gives an IDL-driven builder: pick a
method, supply accounts and JSON arguments, and
MethodBuilder::send_and_capture signs, submits, waits for the
transaction to land, and returns a CapturedTransaction whose replay
holds the exact pre-transaction world — ready for mutation and time travel
with no further RPC.
let captured = scope
.program_with_idl(program_id, idl)
.method("setValue")?
.payer(&payer)
.account("state", state)
.args(json!({ "value": 42 }))?
.send_and_capture()?;
println!("landed: {}", captured.signature);§Hermetic testing
Replays against live RPC state drift as the chain moves on. To pin a
transaction’s world forever, Scope::capture snapshots the transaction,
every account it touched, and every program ELF into a Fixture;
Replay::from_fixture then rebuilds the world and runs what-if scenario
suites (mutations + expectations + named-field assertions) against that
frozen state — offline, deterministic, CI-friendly.
§Public API
Consumer-facing types are re-exported from the crate root. Prefer imports
such as svmscope::{Scope, Replay, Mutation, Check, Fixture}; implementation
modules are private. The idl, report, and spec modules expose the
specialized IDL, HTML-report, and JSON-suite APIs.
§Errors
A reverting replay is not an error — it comes back as a successful
observation with result.success == false. Error always means svmscope
itself couldn’t do what was asked (RPC failure, unknown transaction, a
mutation targeting an account that isn’t loaded, an unknown field name…).
§Feature flags
None — the crate is a plain library. The HTTP API server lives in a separate (unpublished) workspace crate, so library consumers never compile axum/tokio.
This same library powers the svmscope CLI, the HTTP API, and the hosted UI at https://svmscope.vercel.app — identical results in all four.
Re-exports§
pub use scan::scan_breaking_points;pub use scan::BreakingPoint;pub use scan::ScanOptions;
Modules§
- idl
- On-chain Anchor IDL fetching, parsing, and account/instruction decoding.
- profile
- Compute profiler: where every BPF instruction of a transaction went.
- reconstruct
- Historical state reconstruction — rebuild an account’s state at a past slot by replaying its own write history forward, instead of buying it from a paid archive. This is the free, self-owned path to “replay at any slot”.
- report
- Render a scenario-suite run as a self-contained HTML report — the human-facing artifact an auditor attaches to a finding (“here’s what happens under each edge case”). No external assets, opens offline.
- scan
- Auto breaking-point scan — the deterministic “beast” that finds every single-change way a transaction can break, driven by each account’s schema.
- spec
- The JSON suite-file format — the on-disk spec for
svmscope test, and the wire types the web server and browser share.
Structs§
- Account
Check - Builder for state checks against one account, finished with
AccountCheck::build. All checks read post-replay state;*_deltavariants compare against the pre-transaction value. - Account
Diff - One account’s before → after, with named field changes where the layout is known.
- Account
Info - One account’s summary plus (if recognized) its decoded fields.
- Account
Overview - An account/program’s on-chain overview — what an explorer’s address page shows.
- Account
Provenance - One account’s provenance within a replay.
- Account
Role - An account’s role in the transaction — the signer/writable classification Solana Explorer’s inspector shows, derived from the message header + key ordering (static writable-signers, readonly-signers, writable-unsigned, readonly-unsigned, then ALT writable, then ALT readonly).
- Account
State - A reconstructed account’s raw state — its data bytes, lamports, and owner.
- Analysis
- The full analysis of a transaction — the payload the CLI prints and the API serves.
- Assert
Outcome - The result of one post-replay assertion.
- Balance
Change - A change in an account’s SOL (lamport) balance.
- Captured
Transaction - A submitted transaction together with the pre-transaction world captured for deterministic local replay, mutation, and time travel.
- Check
- One declarative check on a replay’s outcome or resulting state.
Construct via the associated functions; combine on a
Scenario. - Cmp
- A comparison against a numeric value:
Cmp::eq(5),Cmp::ge(-100). - CpiEntry
- One instruction in the transaction’s cross-program invocation tree.
- CuUsage
- Compute units one program consumed within a transaction.
- Decoded
Account - A recognized account, broken into named fields.
- Decoded
Event - One Anchor event, decoded.
- Diagnosis
- A plain-English diagnosis of a transaction’s outcome.
- Explanation
- A program failure translated into plain language.
- Feature
Toggle - A Solana runtime feature gate to flip for a replay: activate one that isn’t live on mainnet yet (“will my tx still work when this ships?”), or deactivate an active one. Most execution-affecting SIMDs land on-chain as one of these.
- Fidelity
Certificate - An honest report of how faithful a replay’s starting state is: the verdict, where every account’s bytes came from, which accounts may have drifted from the transaction’s true slot, and whether there is a recorded on-chain outcome to check the replay against. Trust is a product feature — svmscope should never silently hand back a convincing but historically inaccurate replay.
- Field
- One field within a decoded account.
- Field
Diff - One named field’s before → after inside an
AccountDiff. - Fixture
- A portable, self-contained snapshot of a transaction and its world.
- Invariant
- A named security property over a replay’s resulting state. Every constructor
returns a
Check; drop it into aScenarioorReplay::verifyalongside your mutations. - IxAccount
- One account an instruction touches, with its IDL role name where known.
- IxArg
- One decoded instruction argument.
- Method
Builder - A fluent request to invoke one IDL method.
- Onchain
Record - The transaction’s actual on-chain outcome, kept alongside the replay so local results can be compared against what really happened.
- Overview
- Headline facts about the transaction as it actually ran on-chain.
- Patch
Comparison - The result of replaying a transaction against an original program and a patched one — the pre-deployment “does this patch change what happened?” gate.
- Preflight
Ix - One decoded top-level instruction of a pre-flight transaction.
- Preflight
Overview - The pre-sign overview block of a
crate::SimulationReport. - Program
Client - An IDL-backed client for one deployed Solana program.
- Program
Info - Deployment details for an executable program account.
- Replay
- A transaction’s reconstructed world — fetched once via
Scope::replay, then replayed locally any number of times. Every run builds a pristine SVM, so runs are independent, repeatable, and free. - Replay
Result - The outcome of one local replay run.
- Replayed
- The outcome of one local replay: the result itself, what changed, and — on failure — a plain-language explanation.
- Return
Data - Return data a program set during a step.
- Scenario
- One named test case: what-if mutations plus the checks that must hold.
A scenario with no outcome check implicitly asserts
Check::success. - Scenario
Outcome - The result of running one scenario.
- Scope
- An RPC-backed client with caches. Everything svmscope fetches — transaction
JSON, program IDLs — is fetched once per
Scopeand reused, soanalyze(sig)followed byreplay(sig)costs one transaction fetch, and repeated simulations cost zero. - SigInfo
- One entry in an address’s recent transaction history.
- Simulation
Report - A simulation result enriched with what a developer actually needs: a human-readable failure reason and the field-level account diff.
- Step
- One instruction or CPI.
- Step
Account State - One account as it stands after a step.
- Step
Diff - One step’s before/after across two traces.
Noneon a side means the step did not execute in that trace (an earlier step failed). - Step
Error - A failure attributed to a step.
- Step
Summary - One step’s outcome, compact enough to compare across two traces.
- Threshold
- The result of a counterfactual threshold search: the value at which the transaction’s outcome flips, and the outcomes at the search bounds.
- Time
Travel - Move the SVM’s clock forward (or to an absolute point) so time-gated program logic can be tested without waiting: unstake after an epoch, claim after a vesting cliff, withdraw after a cooldown, settle after an auction ends.
- Token
Change - A change in an SPL token account’s balance, in raw base units (client divides by 10^decimals for display).
- Trace
- The whole transaction, unrolled.
- Trace
Diff - What changed between two traces of the same transaction (typically before and after a mutation).
Enums§
- Error
- Everything that can go wrong short of the transaction itself reverting.
- Fidelity
- How faithful a replay’s starting state is to the transaction’s real slot — the honest label on every replay, so a convincing-but-drifted run is never mistaken for an exact one.
- Fixture
Entry - One captured account: either a data account (loaded verbatim) or a program (its resolved ELF bytecode, ready for LiteSVM’s loader).
- Mutation
- A change to apply to an account before replaying.
- Provenance
- Where an account’s loaded bytes came from — the honest per-account source.
Constants§
- FIXTURE_
VERSION - The highest fixture schema version this build reads and writes.
Functions§
- compute_
breakdown - Per-program compute breakdown for a preflight simulation — fills
PreflightOverview::computeonce the simulation has produced logs and a total. Same attribution as the analyze view’s Compute Units panel. - resolve_
rpc_ url - Resolve a cluster name or explicit RPC URL to an endpoint. Precedence:
explicit
rpcURL >clustername >default.
Type Aliases§
- Result
- Convenience alias used across the crate.