Transactions/check_tx
Safe to sign?
$0.02per call after 25 free a dayDecodes each step, dry-runs it on live mainnet, finds each wallet's SOL and token changes, and answers OK, REVIEW or BLOCK with reasons. Measured: no false BLOCK on 200 real mainnet transactions; with tx_matches it caught 9 of 9 attack cases (benchmark/ in the repo).
Run on every transaction before signing. Shows what each wallet gains and loses, blocks drainer tricks, and catches failures and expired blockhashes before you pay a fee.
Saves money. Catches a drainer approval or a transaction that will fail, before you sign. Failed transactions still cost fees. One hidden approval can empty a wallet.
Call it
| Transport | How |
|---|---|
| HTTP | POST /api/tools/check_tx with a JSON body of the inputs below. |
| MCP | tools/call with name check_tx on /mcp. |
Inputs
| Name | What it's looking for | Where to get it |
|---|---|---|
txstring (base64), required | Base64 transaction, signed or not, legacy, v0 or v1. | Before signing: Buffer.from(tx.serialize({ requireAllSignatures: false })).toString('base64'), or an aggregator's swap tx. |
network"mainnet-beta" | "devnet", optional | Default "mainnet-beta" (real money). | "devnet" only for test wallets. |
Returned fields
Every field the tool returns, what it is, and exactly how it's worked out.
| Field | What it is | How it's worked out |
|---|---|---|
verdict"OK" | "REVIEW" | "BLOCK" | The answer. BLOCK: don't sign. REVIEW: a person or your rules should look first. OK: nothing wrong found. | The worst check wins: any fail is BLOCK, any warn is REVIEW, otherwise OK. |
summarystring | One sentence: the verdict and the main reason. | Built from the worst check and what your wallet sends. |
fee_payer / signersstring / string[] | The wallet paying the fee, and every wallet that signs. | Read from the transaction. |
checks[].namestring | Which check: simulation, blockhash, already_landed, fee_payer_balance, token_approval, authority_change, wallet_reassigned, close_to_other, unknown_programs, priority_fee or outflow. | A fixed list. |
checks[].result"pass" | "info" | "warn" | "fail" | How the check came out. | simulation fails if the dry run errors. blockhash warns if expired. already_landed fails if this exact signed transaction is already on chain (only checked for signed ones; info and unknown if the lookup fails). fee_payer_balance fails if the payer can't cover fees. Approvals to non-signers, authority changes, reassigning a signer and closing to a non-signer fail. Unknown programs warn. A priority fee over 0.01 SOL warns. Money leaving your wallet is info. |
checks[].detailstring | What the check found, in plain words. | Built from the decoded steps and the dry run. |
balance_changes[].walletstring | The wallet whose balance changes. | For SOL, the account itself. For tokens, the owner of the token account. |
balance_changes[].is_youboolean | True when this wallet signs the transaction, so it's you. | The wallet is one of the required signers. |
balance_changes[].token / symbolstring | "SOL" or the token address, and its ticker. | From the account data. Ticker from Jupiter. |
balance_changes[].before / after / changestring (decimal) | Balance before, after, and the difference. Negative means the wallet loses it. | Before: live account data. After: the dry run's account data. Exact decimals. SOL changes include fees. |
balance_changes[].raw_change / decimalsstring / number | The change in raw units, and the token's decimals. | after minus before, in base units. |
steps[]object[] | Every instruction, decoded: step number, program, type (sol_transfer, token_transfer, token_approve, token_set_authority, token_close_account, create_token_account, set_compute_unit_price, unknown_program and more) and its key details. | Decoded for the System, Token, Token-2022, Compute Budget, Associated Token Account and Memo programs. Exchanges on Jupiter's list of the programs it routes through are named, not unknown. |
fee.base_lamports / priority_lamports / total_lamports / total_solstring | What this transaction costs in fees. | Base: 5000 lamports per signature. Priority: compute_unit_price x compute_unit_limit / 1,000,000, rounded up. |
fee.compute_unit_limit / compute_unit_limit_from / compute_unit_pricenumber | string | The compute settings the fee is charged on. compute_unit_price is in micro-lamports per compute unit. | From the transaction's Compute Budget steps, or the runtime default when there are none. |
simulation.worked / error / compute_used / logsobject | The raw dry run: whether it worked, the error, compute used, and the last 25 log lines. | simulateTransaction with signature checks off and a fresh blockhash. |
simulation.error_explainedobject | null | What the failure means, in plain words. | why_failed run on the dry-run error. |
Limits
- The dry run uses the chain as it is now. If things change before you send, the real result can differ.
- Balance changes cover up to 64 writable accounts.