{"freeCallsPerTool":25,"freeCallsReset":"daily at 00:00 UTC","payments":{"protocol":"x402","x402Version":2,"scheme":"exact","network":"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp","asset":"USDC","payTo":"Brpc8HoPo1d3Uiyo7kbERnjMqwLJJmbWxtwxHxzar6DU"},"tools":[{"name":"check_tx","oldName":"preflight_transaction","title":"Safe to sign?","category":"transactions","useWhen":"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.","benefit":{"kind":"money","text":"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."},"description":"Decodes 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).","price":"$0.02","priceText":"25 free calls a day, then $0.02 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/check_tx","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"check_tx"},"inputs":[{"name":"tx","type":"string (base64)","required":true,"lookingFor":"Base64 transaction, signed or not, legacy, v0 or v1.","whereToGet":"Before signing: Buffer.from(tx.serialize({ requireAllSignatures: false })).toString('base64'), or an aggregator's swap tx."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"verdict","type":"\"OK\" | \"REVIEW\" | \"BLOCK\"","is":"The answer. BLOCK: don't sign. REVIEW: a person or your rules should look first. OK: nothing wrong found.","howWorkedOut":"The worst check wins: any fail is BLOCK, any warn is REVIEW, otherwise OK."},{"field":"summary","type":"string","is":"One sentence: the verdict and the main reason.","howWorkedOut":"Built from the worst check and what your wallet sends."},{"field":"fee_payer / signers","type":"string / string[]","is":"The wallet paying the fee, and every wallet that signs.","howWorkedOut":"Read from the transaction."},{"field":"checks[].name","type":"string","is":"Which check: simulation, blockhash, already_landed, fee_payer_balance, token_approval, authority_change, wallet_reassigned, close_to_other, unknown_programs, priority_fee or outflow.","howWorkedOut":"A fixed list."},{"field":"checks[].result","type":"\"pass\" | \"info\" | \"warn\" | \"fail\"","is":"How the check came out.","howWorkedOut":"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."},{"field":"checks[].detail","type":"string","is":"What the check found, in plain words.","howWorkedOut":"Built from the decoded steps and the dry run."},{"field":"balance_changes[].wallet","type":"string","is":"The wallet whose balance changes.","howWorkedOut":"For SOL, the account itself. For tokens, the owner of the token account."},{"field":"balance_changes[].is_you","type":"boolean","is":"True when this wallet signs the transaction, so it's you.","howWorkedOut":"The wallet is one of the required signers."},{"field":"balance_changes[].token / symbol","type":"string","is":"\"SOL\" or the token address, and its ticker.","howWorkedOut":"From the account data. Ticker from Jupiter."},{"field":"balance_changes[].before / after / change","type":"string (decimal)","is":"Balance before, after, and the difference. Negative means the wallet loses it.","howWorkedOut":"Before: live account data. After: the dry run's account data. Exact decimals. SOL changes include fees."},{"field":"balance_changes[].raw_change / decimals","type":"string / number","is":"The change in raw units, and the token's decimals.","howWorkedOut":"after minus before, in base units."},{"field":"steps[]","type":"object[]","is":"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.","howWorkedOut":"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."},{"field":"fee.base_lamports / priority_lamports / total_lamports / total_sol","type":"string","is":"What this transaction costs in fees.","howWorkedOut":"Base: 5000 lamports per signature. Priority: compute_unit_price x compute_unit_limit / 1,000,000, rounded up."},{"field":"fee.compute_unit_limit / compute_unit_limit_from / compute_unit_price","type":"number | string","is":"The compute settings the fee is charged on. compute_unit_price is in micro-lamports per compute unit.","howWorkedOut":"From the transaction's Compute Budget steps, or the runtime default when there are none."},{"field":"simulation.worked / error / compute_used / logs","type":"object","is":"The raw dry run: whether it worked, the error, compute used, and the last 25 log lines.","howWorkedOut":"simulateTransaction with signature checks off and a fresh blockhash."},{"field":"simulation.error_explained","type":"object | null","is":"What the failure means, in plain words.","howWorkedOut":"why_failed run on the dry-run error."}],"notes":["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."],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"tx":{"type":"string","minLength":20,"description":"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":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["tx"]}},{"name":"tx_matches","oldName":"check_transaction_intent","title":"Does it do what I asked?","category":"transactions","useWhen":"Run just before signing a transfer built from a request like \"send 5 USDC to X\", or a swap built for \"swap 1 USDC for JUP\". Confirms it moves exactly that token, amount and recipient, nothing more, or that the swap sells exactly that amount and pays the bought token back to you. Catches made-up amounts, wrong decimals, hidden steps and swaps that pay someone else.","benefit":{"kind":"accuracy","text":"Asked to send 5 USDC, an agent can build a transaction for 50 (a decimals slip) or to a made-up address. This says MISMATCH and names the exact field."},"description":"Compares the transaction with your request (token, exact amount, recipient, sender), flags every step that isn't the transfer, and checks dry-run balances so money moved any other way is caught. For a swap it reads the dry run: exactly the amount sold, the bought token reaching your wallet, and nothing else leaving it. Measured on 200 real mainnet transactions: 80 of 80 transfers and 26 of 27 swaps matched (the other paid a bot 1.54%).","price":"$0.02","priceText":"25 free calls a day, then $0.02 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/tx_matches","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"tx_matches"},"inputs":[{"name":"tx","type":"string (base64)","required":true,"lookingFor":"Base64 transaction, signed or not, legacy, v0 or v1.","whereToGet":"Before signing: Buffer.from(tx.serialize({ requireAllSignatures: false })).toString('base64'), or an aggregator's swap tx."},{"name":"expected.action","type":"\"transfer\" | \"swap\"","required":false,"lookingFor":"Default \"transfer\". \"swap\" takes sell, amount, buy and from instead of token, amount and to.","whereToGet":"From the request you were given."},{"name":"expected.token","type":"string (\"SOL\" or token address)","required":true,"lookingFor":"The token to send.","whereToGet":"\"SOL\", or the token address from find_token."},{"name":"expected.amount","type":"string (decimal)","required":true,"lookingFor":"Normal units (for a swap: the amount sold): \"5\" means 5 USDC.","whereToGet":"The user's amount, as a string."},{"name":"expected.to","type":"string (wallet address)","required":true,"lookingFor":"The person's wallet, not their token account.","whereToGet":"The address the user gave you. Never take it from the transaction."},{"name":"expected.from","type":"string (wallet address)","required":false,"lookingFor":"The wallet that pays (for a swap: sells and gets the bought token). Default: the fee payer.","whereToGet":"Your agent's wallet address."},{"name":"expected.sell","type":"string (\"SOL\" or token address)","required":false,"lookingFor":"Swaps only: the token sold.","whereToGet":"\"SOL\", or the token address from find_token."},{"name":"expected.buy","type":"string (\"SOL\" or token address)","required":false,"lookingFor":"Swaps only: the token bought.","whereToGet":"\"SOL\", or the token address from find_token. Never take it from the transaction."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"verdict","type":"\"MATCH\" | \"MISMATCH\"","is":"The answer. MATCH: it does exactly what you asked. MISMATCH: something is off. Don't sign.","howWorkedOut":"MATCH only when every compared field is ok and unexpected is empty."},{"field":"summary","type":"string","is":"One sentence, naming the first thing that's off.","howWorkedOut":"Built from the failed comparisons."},{"field":"expected.token_address / raw_amount / decimals / to / from","type":"string | number","is":"What you asked for, in exact on-chain terms.","howWorkedOut":"SOL uses 9 decimals. Tokens use their real on-chain decimals. Converted with exact integer math."},{"field":"compared[].what","type":"\"token\" | \"amount\" | \"to\" | \"from\" | \"simulation\"","is":"What was compared.","howWorkedOut":"A fixed list. A swap has no \"token\" row: its amount row names the sold token, and its to row says who gets the bought one."},{"field":"compared[].expected / actual","type":"string","is":"What you asked for, and what the transaction really does.","howWorkedOut":"actual comes from the decoded transfer. For tokens, the recipient is the owner of the receiving token account (read on chain, or from a create-account step in the same transaction)."},{"field":"compared[].ok","type":"boolean","is":"Whether they match.","howWorkedOut":"Exact equality. Amounts compared in raw units."},{"field":"transfers[]","type":"object[]","is":"Every transfer in the transaction: step, from, to, token, amount and raw amount.","howWorkedOut":"Decoded System and Token transfers. Token account owners read on chain."},{"field":"fees","type":"{ wallet, token, amount, raw_amount, share }[]","is":"Swaps only: small cuts of the bought token that go to other wallets, like an exchange's or app's fee.","howWorkedOut":"Other wallets' gain in the bought token in the dry run, when together it is at most 1% of what you get (real swaps paid 0.47-0.77%). More than 1% goes in unexpected and the verdict is MISMATCH."},{"field":"extra_spent","type":"{ token, amount, raw_amount, share } | null","is":"Swaps only: tips or fees paid in the token you sell, on top of the swap amount.","howWorkedOut":"What the sender loses of the sold token beyond the amount, when it is at most 1% of the amount (a real swap tipped 0.005%). More than 1% makes the amount wrong and the verdict MISMATCH."},{"field":"received","type":"{ token, amount, raw_amount, decimals } | null","is":"Swaps only: how much of the bought token reaches your wallet in the dry run.","howWorkedOut":"The wallet's change in that token across all its token accounts (SOL and wrapped SOL together), with the fee and the deposits for its own new accounts added back. null when the dry run fails."},{"field":"unexpected[]","type":"string[]","is":"Anything you didn't ask for: extra transfers, approvals, authority changes, closed accounts, other programs, or the sender losing more than the transfer explains.","howWorkedOut":"Every step except the matched transfer, Compute Budget, Memo and creating the recipient's token account is listed. Then the sender's dry-run losses are compared with the amount (plus fees and the recipient's account deposit for SOL). Any bigger loss is listed."}],"notes":["Creating the recipient's token account (about 0.002 SOL deposit) is allowed, since sending a token to a new holder needs it.","Any other step gives MISMATCH, even a harmless one, because a transfer shouldn't need it. Read unexpected before overriding.","A swap is judged by its dry run, since the money moves inside the aggregator's pools: you sell exactly the amount, the bought token arrives in your wallet, nobody else gets any of it (a front end's fee in the bought token counts), you lose nothing else beyond fees and your own new accounts' deposits, and no step hands control of an account to anyone. It doesn't judge the price: compare received with your quote."],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"tx":{"type":"string","minLength":20,"description":"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."},"expected":{"anyOf":[{"type":"object","properties":{"action":{"type":"string","const":"swap"},"sell":{"type":"string"},"amount":{"type":"string"},"buy":{"type":"string"},"from":{"type":"string"}},"required":["action","sell","amount","buy"]},{"type":"object","properties":{"action":{"type":"string","const":"transfer"},"token":{"type":"string"},"amount":{"type":"string"},"to":{"type":"string"},"from":{"type":"string"}},"required":["token","amount","to"]}],"description":"action: Default \"transfer\". \"swap\" takes sell, amount, buy and from instead of token, amount and to. From the request you were given. token: The token to send. \"SOL\", or the token address from find_token. amount: Normal units (for a swap: the amount sold): \"5\" means 5 USDC. The user's amount, as a string. to: The person's wallet, not their token account. The address the user gave you. Never take it from the transaction. from: The wallet that pays (for a swap: sells and gets the bought token). Default: the fee payer. Your agent's wallet address. sell: Swaps only: the token sold. \"SOL\", or the token address from find_token. buy: Swaps only: the token bought. \"SOL\", or the token address from find_token. Never take it from the transaction."},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["tx","expected"]}},{"name":"explain_tx","oldName":"explain_transaction","title":"What did this transaction do?","category":"transactions","useWhen":"Run after a transaction lands or fails, to report what happened instead of guessing from logs. For failures it names the failing program and the fix.","benefit":{"kind":"accuracy","text":"Reports the real balance changes from chain data, not a model's guess from raw logs. For failures it names the program and the reason."},"description":"Reads a confirmed transaction: whether it worked, the fee, each wallet's SOL and token changes, the programs used, and why it failed.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/explain_tx","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"explain_tx"},"inputs":[{"name":"tx_id","type":"string (base58)","required":true,"lookingFor":"The transaction's signature.","whereToGet":"Returned when you send, or from history. Never make one up."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"result","type":"\"success\" | \"failed\"","is":"Whether it worked. Failed transactions still pay fees.","howWorkedOut":"meta.err is empty for success."},{"field":"summary","type":"string","is":"What happened, in a few plain sentences.","howWorkedOut":"Built from the result, the fee and the biggest balance changes."},{"field":"time / slot","type":"string | number","is":"When and where it landed.","howWorkedOut":"Block time in ISO 8601, and the slot."},{"field":"fee_payer / signers","type":"string / string[]","is":"Who paid the fee and who signed.","howWorkedOut":"The first account, and the accounts marked as signers."},{"field":"fee.lamports / fee.sol","type":"string","is":"The fee charged.","howWorkedOut":"meta.fee."},{"field":"programs[]","type":"{ address, name }[]","is":"The programs the transaction called.","howWorkedOut":"Each top-level step's program, with its name when we know it."},{"field":"sol_changes[]","type":"{ account, before, after, change, raw_change }[]","is":"Every account whose SOL changed, fee included.","howWorkedOut":"Balances before vs after, exact decimals."},{"field":"token_changes[]","type":"{ owner, token, symbol, before, after, change, raw_change }[]","is":"Every token balance that changed, by owner wallet and token.","howWorkedOut":"Token balances before vs after, with each token's decimals. Tickers from Jupiter."},{"field":"compute_used","type":"number | null","is":"Compute units used.","howWorkedOut":"meta.computeUnitsConsumed."},{"field":"failure","type":"object | null","is":"For failed transactions: the raw error, the step and program that failed, what it means, and the last log lines.","howWorkedOut":"meta.err decoded. The failing program is the program of the failing step. The meaning comes from why_failed."}],"notes":[],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"tx_id":{"type":"string","minLength":64,"maxLength":100,"description":"The transaction's signature. Returned when you send, or from history. Never make one up."},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["tx_id"]}},{"name":"fee","oldName":"fee_advice","title":"What fee to pay","category":"network","useWhen":"Run before setting a priority fee. Gives the price in the unit Compute Budget expects (micro-lamports per compute unit) and the total in SOL, so a unit mix-up never overpays.","benefit":{"kind":"money","text":"Prices are in micro-lamports per compute unit, the unit setComputeUnitPrice takes. Mixing that up with lamports overpays a million times."},"description":"Turns what recent transactions paid for priority into three prices: cheap, normal, fast. Pass your transaction to get its compute limit and exact cost at each.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/fee","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"fee"},"inputs":[{"name":"tx","type":"string (base64)","required":false,"lookingFor":"Your transaction, so fees match its accounts and compute comes from a dry run.","whereToGet":"Before signing: Buffer.from(tx.serialize({ requireAllSignatures: false })).toString('base64'), or an aggregator's swap tx."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"unit","type":"string","is":"Always \"micro-lamports per compute unit\". 1,000,000 micro-lamports = 1 lamport. It is the unit setComputeUnitPrice takes.","howWorkedOut":"Fixed."},{"field":"based_on","type":"string","is":"What the prices come from: the transactions in the latest blocks, plus your transaction's writable accounts when given.","howWorkedOut":"The blocks read (slots listed); with a transaction, also getRecentPrioritizationFees on its writable accounts."},{"field":"samples / share_paying","type":"number","is":"How many recent transactions were sampled, and the share of them that paid any priority fee.","howWorkedOut":"Every non-vote transaction in the latest 2 readable blocks (getBlock, version 1 included)."},{"field":"prices.cheap / normal / fast .compute_unit_price","type":"number","is":"The price to set with setComputeUnitPrice. cheap is what half of recent transactions paid or more; fast is for urgent trades.","howWorkedOut":"The 50th, 75th and 90th percentile of what those transactions paid per compute unit (a v1 transaction's lamport total over its compute limit). With a transaction, each is raised to the same percentile of the lowest fees that landed on its accounts, if that is higher."},{"field":"prices.*.priority_lamports / total_lamports / total_sol","type":"string","is":"What the transaction would pay at that price.","howWorkedOut":"priority = price x compute units / 1,000,000, rounded up. total = priority + 5000 lamports per signature."},{"field":"compute_units","type":"number","is":"The compute units the costs are worked out for.","howWorkedOut":"With a transaction: dry-run units used + 10%. Without: 200,000 (a typical one-step default)."},{"field":"compute_units_from","type":"string","is":"Whether compute_units came from a dry run or the default.","howWorkedOut":"\"simulation\" or \"default\"."},{"field":"how_to_use","type":"string","is":"The two Compute Budget steps to add (for a v1 transaction, the two config fields to set).","howWorkedOut":"Built from the normal price and compute_units."}],"notes":[],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"tx":{"description":"Your transaction, so fees match its accounts and compute comes from a dry run. Before signing: Buffer.from(tx.serialize({ requireAllSignatures: false })).toString('base64'), or an aggregator's swap tx.","type":"string","minLength":20},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}}}},{"name":"tx_version","title":"Which transaction version is this?","category":"transactions","useWhen":"Run when code can't find or read a transaction that is on chain, or before relying on code that reads other people's transactions.","benefit":{"kind":"money","text":"Over 40% of Solana transactions are version 1 since September 15, 2026 (42% in Oct 16-30), and apps that read with version 0 silently miss them: payments rejected, trades not copied, burns not credited."},"description":"Says whether a transaction is legacy, version 0 or version 1, and which readers (RPC settings and library versions) can read it.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/tx_version","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"tx_version"},"inputs":[{"name":"tx_id","type":"string (base58)","required":false,"lookingFor":"A landed transaction's signature. Give this or tx.","whereToGet":"Returned when it was sent, or from history. Never make one up."},{"name":"tx","type":"string (base64)","required":false,"lookingFor":"A raw transaction, signed or not. Give this or tx_id.","whereToGet":"The bytes a wallet or builder gave you, base64-encoded."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"version","type":"\"legacy\" | \"0\" | \"1\" | \"unknown\"","is":"The transaction's format.","howWorkedOut":"tx_id: the version the RPC reports, asked with maxSupportedTransactionVersion 1. tx: read from the first bytes (see notes)."},{"field":"readable_with_max_version_0","type":"boolean | null","is":"Whether code asking with maxSupportedTransactionVersion: 0 can read it. null when the version is unknown.","howWorkedOut":"True for legacy and 0, false for 1."},{"field":"who_can_read_it","type":"string","is":"Which RPC settings and library versions can read this format.","howWorkedOut":"Fixed text per version, from mainnet tests of each library version (2026-10-30)."},{"field":"fix","type":"string | null","is":"What to change so code reads it. null when nothing needs changing.","howWorkedOut":"Given for version 1."},{"field":"found / slot / time","type":"boolean / number | null / string | null","is":"For tx_id: whether the transaction was found, and where and when it landed.","howWorkedOut":"From getTransaction (finalized or confirmed)."},{"field":"source","type":"string","is":"Where the version came from.","howWorkedOut":"\"rpc getTransaction\" or \"transaction bytes\"."}],"notes":["Version 1 transactions start with the byte 0x81, before the signatures; legacy and version 0 start with the signature count. Code that parses raw bytes the old way breaks on version 1 too.","Version 1 went live on mainnet on 2026-09-15; the first one we found is in slot 447120004."],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"tx_id":{"description":"A landed transaction's signature. Give this or tx. Returned when it was sent, or from history. Never make one up.","type":"string","minLength":64,"maxLength":100},"tx":{"description":"A raw transaction, signed or not. Give this or tx_id. The bytes a wallet or builder gave you, base64-encoded.","type":"string"},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}}}},{"name":"build_tx","title":"Build it, checked","category":"transactions","useWhen":"Run when an agent needs to send SOL or a token, or swap through Jupiter: it returns the unsigned transaction already checked, with ready_to_sign and the reasons. Sign only when ready_to_sign is true.","benefit":{"kind":"money","text":"An agent that builds its own transactions can get the token, amount, decimals or recipient wrong. This builds exactly what was asked, then refuses to call it ready unless check_tx says OK and tx_matches says MATCH."},"description":"Builds a SOL or token transfer, or a Jupiter swap, as an unsigned transaction with a fresh blockhash and a fair priority fee, then runs check_tx and tx_matches on it (and token_safety on a token being bought). Never signs or sends.","price":"$0.03","priceText":"25 free calls a day, then $0.03 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/build_tx","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"build_tx"},"inputs":[{"name":"action","type":"\"transfer\" | \"swap\"","required":true,"lookingFor":"Send a token to someone, or swap one token for another through Jupiter.","whereToGet":"From the request."},{"name":"from","type":"string (base58 address)","required":true,"lookingFor":"The wallet that pays and will sign.","whereToGet":"The agent's or user's own wallet address."},{"name":"to","type":"string (base58 address)","required":false,"lookingFor":"Transfers: who receives it.","whereToGet":"From the request. Check it with whats_this first if it came from someone else."},{"name":"token","type":"string (\"SOL\" or mint address)","required":false,"lookingFor":"The token to send (transfer) or to sell (swap). Default \"SOL\".","whereToGet":"find_token turns a name like USDC into its mint address. Never guess a mint."},{"name":"amount","type":"string (decimal)","required":true,"lookingFor":"How much of token, in whole tokens: \"1.5\" means 1.5 USDC, not raw units.","whereToGet":"From the request."},{"name":"buy","type":"string (\"SOL\" or mint address)","required":false,"lookingFor":"Swaps: the token to buy.","whereToGet":"find_token gives the mint."},{"name":"slippage_bps","type":"integer 1-300","required":false,"lookingFor":"Swaps: the most the price may move against you, in basis points (50 = 0.5%). Default 50, at most 300.","whereToGet":"Leave the default unless the token is thinly traded."},{"name":"allow_avoid","type":"boolean","required":false,"lookingFor":"Swaps: build even when token_safety says AVOID for the token being bought. Default false.","whereToGet":"Only when the user has read the AVOID reasons and still wants it."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"ready_to_sign","type":"boolean","is":"True only when every check below passed. Sign only then.","howWorkedOut":"check_tx OK, tx_matches MATCH, and for a swap the bought token isn't AVOID (unless allow_avoid)."},{"field":"summary","type":"string","is":"What the transaction does and whether it's ready, in one or two sentences.","howWorkedOut":"From the request and the checks."},{"field":"tx","type":"string (base64)","is":"The unsigned transaction (version 0). Sign it with the from wallet and send it within about a minute, before the blockhash expires.","howWorkedOut":"Transfers built here (Compute Budget, then the transfer; token transfers create the recipient's account if needed). Swaps built by Jupiter's swap API."},{"field":"reasons[]","type":"string[]","is":"Why it isn't ready, in plain words. Empty when ready_to_sign is true.","howWorkedOut":"The failing checks' own summaries."},{"field":"checks","type":"object","is":"The full answers: check_tx (verdict, summary, checks, balance_changes), tx_matches (verdict, summary, compared), and token_safety for a swap's bought token.","howWorkedOut":"The same tools, run on the built transaction."},{"field":"quote","type":"object | null","is":"Swaps: in_amount, out_amount and min_out_amount in raw units, price_impact_pct and slippage_bps.","howWorkedOut":"Jupiter's quote that the transaction was built from."}],"notes":["Never signs or sends. The from wallet signs; keys never reach Pulse.","A blockhash lasts about a minute: sign and send soon, or build again.","The checks run on the transaction as built. If anything changes it afterwards, check it again."],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"action":{"type":"string","enum":["transfer","swap"],"description":"Send a token to someone, or swap one token for another through Jupiter. From the request."},"from":{"type":"string","description":"The wallet that pays and will sign. The agent's or user's own wallet address."},"to":{"description":"Transfers: who receives it. From the request. Check it with whats_this first if it came from someone else.","type":"string"},"token":{"default":"SOL","description":"The token to send (transfer) or to sell (swap). Default \"SOL\". find_token turns a name like USDC into its mint address. Never guess a mint.","type":"string"},"amount":{"type":"string","pattern":"^\\d+(\\.\\d+)?$","description":"How much of token, in whole tokens: \"1.5\" means 1.5 USDC, not raw units. From the request."},"buy":{"description":"Swaps: the token to buy. find_token gives the mint.","type":"string"},"slippage_bps":{"default":50,"description":"Swaps: the most the price may move against you, in basis points (50 = 0.5%). Default 50, at most 300. Leave the default unless the token is thinly traded.","type":"integer","minimum":1,"maximum":300},"allow_avoid":{"default":false,"description":"Swaps: build even when token_safety says AVOID for the token being bought. Default false. Only when the user has read the AVOID reasons and still wants it.","type":"boolean"},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["action","from","amount"]}},{"name":"find_token","oldName":"resolve_token","title":"Ticker to token address","category":"tokens","useWhen":"Run whenever a user names a token (\"buy BONK\"). Tickers aren't unique; copycats reuse them. Never take an address from memory.","benefit":{"kind":"money","text":"Copycats reuse popular tickers: a search for BONK finds several unverified fakes. This gives the verified token address so the agent doesn't buy a fake."},"description":"Finds the real address for a ticker or name, ranks matches by verification and liquidity, and warns when copycats share the ticker.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/find_token","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"find_token"},"inputs":[{"name":"name","type":"string","required":true,"lookingFor":"Ticker, name or address: \"BONK\", \"Jupiter\", \"USDC\".","whereToGet":"Exactly as the user wrote it."}],"outputs":[{"field":"name","type":"string","is":"What was searched.","howWorkedOut":"Your input, trimmed."},{"field":"best","type":"object | null","is":"The token we recommend, or null when it isn't safe to pick one for you.","howWorkedOut":"The verified token whose ticker exactly matches (any case, with or without a leading $) with the most liquidity. Null if there's no verified exact match."},{"field":"confidence","type":"\"high\" | \"medium\" | \"low\"","is":"How safe it is to use best without asking the user.","howWorkedOut":"high: a verified exact match and no other verified token shares the ticker. medium: another verified token shares it. low: no verified exact match."},{"field":"copycats","type":"number","is":"Unverified tokens using the same ticker. Usually scams copying the real one.","howWorkedOut":"Matches with the same ticker (any case, with or without a leading $) that aren't verified."},{"field":"candidates[].address","type":"string","is":"The token's address, its real identity.","howWorkedOut":"Jupiter token search."},{"field":"candidates[].symbol / name","type":"string","is":"Ticker and display name.","howWorkedOut":"Jupiter token search."},{"field":"candidates[].decimals","type":"number","is":"Decimal places. Needed to convert amounts.","howWorkedOut":"Jupiter token data."},{"field":"candidates[].verified","type":"boolean","is":"Whether Jupiter lists the token as verified.","howWorkedOut":"Jupiter's isVerified flag."},{"field":"candidates[].liquidity_usd","type":"number | null","is":"How much can be traded across DEX pools, in USD. Low means trades move the price a lot.","howWorkedOut":"Jupiter liquidity, rounded to dollars."},{"field":"candidates[].holders","type":"number | null","is":"How many wallets hold the token.","howWorkedOut":"Jupiter holderCount."},{"field":"candidates[].real_trading_score","type":"number | null","is":"Jupiter's 0-100 estimate of real (not bot) trading.","howWorkedOut":"Jupiter organicScore, rounded."},{"field":"candidates[].token_program","type":"\"spl-token\" | \"token-2022\"","is":"Which token program the token uses.","howWorkedOut":"Jupiter tokenProgram."},{"field":"candidates[].can_mint_more / can_freeze","type":"boolean | null","is":"Whether someone can still create more of it, or freeze holders' tokens. false is safer.","howWorkedOut":"Jupiter audit data. null when unknown. token_safety checks these on chain."},{"field":"next_step","type":"string","is":"What to do next, in one sentence.","howWorkedOut":"Built from confidence and copycats."}],"notes":[],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"Ticker, name or address: \"BONK\", \"Jupiter\", \"USDC\". Exactly as the user wrote it."}},"required":["name"]}},{"name":"token_safety","oldName":"token_verdict","title":"Is this token safe?","category":"tokens","useWhen":"Run before buying, accepting or recommending a token. Answers SAFE, CAUTION or AVOID with exact reasons from chain and market data.","benefit":{"kind":"money","text":"Flags tokens you can't sell, liquidity the creator can pull, creators who have rugged before, hidden insider wallets and issuers who can freeze or take your tokens, before you buy. Regulated stablecoins' powers count as expected."},"description":"Simulates a real holder selling, then checks if liquidity can be pulled, the creator's record, insider wallet networks, issuer powers (mint, freeze, Token-2022 traps), verification, liquidity, holders and age, for one verdict.","price":"$0.02","priceText":"25 free calls a day, then $0.02 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/token_safety","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"token_safety"},"inputs":[{"name":"token","type":"string (token address)","required":true,"lookingFor":"The token's address.","whereToGet":"From find_token (for a ticker) or tokens (for a wallet's tokens)."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"verdict","type":"\"SAFE\" | \"CAUTION\" | \"AVOID\"","is":"The answer. AVOID: at least one check failed. CAUTION: at least one warning. SAFE: no warnings.","howWorkedOut":"The worst check wins: any fail is AVOID, any warn is CAUTION, otherwise SAFE."},{"field":"summary","type":"string","is":"One sentence explaining the verdict.","howWorkedOut":"Built from the failed and warning checks."},{"field":"about.symbol / name","type":"string | null","is":"Ticker and name.","howWorkedOut":"Jupiter token data."},{"field":"about.decimals","type":"number","is":"Decimal places.","howWorkedOut":"The on-chain token account."},{"field":"about.supply","type":"string","is":"Total supply in whole tokens.","howWorkedOut":"On-chain supply / 10^decimals, exact."},{"field":"about.token_program","type":"\"spl-token\" | \"token-2022\"","is":"Which token program it uses.","howWorkedOut":"The owner of the token's account."},{"field":"about.who_can_mint","type":"string | null","is":"Who can create more tokens. null means nobody (fixed supply).","howWorkedOut":"The on-chain mint authority."},{"field":"about.who_can_freeze","type":"string | null","is":"Who can freeze holders' tokens. null means nobody.","howWorkedOut":"The on-chain freeze authority."},{"field":"about.extensions","type":"string[]","is":"Token-2022 extensions turned on.","howWorkedOut":"Read from the token's account."},{"field":"about.usd_price / liquidity_usd / holders / top10_share_pct / first_traded","type":"number | string | null","is":"Market facts the checks use.","howWorkedOut":"Jupiter token data. top10_share_pct is the share the 10 biggest holders own. first_traded is when its first pool was made."},{"field":"about.creator / creator_tokens_launched","type":"string | number | null","is":"The wallet that created the token, and how many tokens it has launched.","howWorkedOut":"Jupiter token data."},{"field":"about.metadata_can_change","type":"boolean | null","is":"Whether the name and logo can still be changed.","howWorkedOut":"RugCheck's report of the token's metadata."},{"field":"checks[].name","type":"string","is":"Which check: sell_test, liquidity_pull, creator_history, insiders, metadata, verified, mint_authority, freeze_authority, extension:<name>, liquidity, holder_concentration, age, known_stablecoin, market_data or rugcheck_data.","howWorkedOut":"A fixed list. market_data or rugcheck_data (warn) shows up only when Jupiter or RugCheck can't be reached. The checks that need them are then skipped, not guessed."},{"field":"checks[].result","type":"\"pass\" | \"info\" | \"warn\" | \"fail\"","is":"How the check came out. info means notable but expected, like a regulated stablecoin's freeze power.","howWorkedOut":"Sell test: fail if the token blocked a real holder's simulated sale, warn if there's no route to sell or it failed for another reason. Liquidity pull: fail when over 20% of the liquidity is unlocked and comes from 1 or 2 providers (warn for verified tokens), warn for 3 to 9 providers, info for established tokens (Jupiter-verified and trading 90+ days). Creator: fail if they have rugged before, warn if an unverified token's creator launched 20+ tokens or still holds over 20%. Insiders: warn over 10% of supply, fail over 30%, counting only networks of up to 500 wallets; unknown (info) when RugCheck's numbers add up to more than the whole supply. Metadata: warn if an unverified token's name and logo can change. Liquidity: fail under $10k, warn under $100k. Top 10 holders: warn over 50%, fail over 80% (established tokens: info up to 80%, warn over; info for known stablecoins and Jupiter-verified liquid staking tokens). Age: warn under 24 hours. Permanent delegate fails, except a known issuer's delegate (xStocks, Backpack Securities, Paxos), which warns and names the issuer. Frozen-by-default and non-transferable fail. Mint and freeze powers warn unless it's a known stablecoin or an established token (Jupiter-verified and trading 90+ days), where they are info and name who holds them."},{"field":"checks[].detail","type":"string","is":"The fact behind the result, in plain words.","howWorkedOut":"Built from the data."},{"field":"checks[].source","type":"\"on-chain\" | \"jupiter\" | \"rugcheck\" | \"simulation\"","is":"Where the fact came from.","howWorkedOut":"on-chain for token data, jupiter for market and creator data, rugcheck for liquidity locks, insiders and creator history, simulation for the sell test."},{"field":"history","type":"object | null","is":"What changed since Pulse first checked this token, when Pulse has been watching it. null when it hasn't.","howWorkedOut":"Pulse watches young tokens (under 3 days old) for 7 days after it first checks them, whether it found them on Jupiter's activity lists or someone ran token_safety on them, and re-reads them every 2 hours. Checking a young token starts the watch, so a later check shows what changed."},{"field":"history.watched_since / watching_until / verdict_then / found_in","type":"string","is":"When the watch started and ends, the verdict Pulse gave then, and how the token was found.","howWorkedOut":"Stored when the watch started."},{"field":"history.then / latest","type":"object","is":"The first and the newest reading: listed, liquidity_usd, usd_price, holders, top10_share_pct, who_can_mint, who_can_freeze (latest also has at).","howWorkedOut":"then is what this tool reported when the watch started. latest comes from Jupiter (market numbers) and the chain (authorities). A value no source answered is null."},{"field":"history.changes[]","type":"{ at, what, result, detail, source }[]","is":"Each change once, at the first reading that showed it: liquidity_pulled (fail), price_crashed (fail), liquidity_halved, holders_halved, top10_up, mint_authority_moved, freeze_authority_moved (warn), or mint_authority_revoked / freeze_authority_revoked (info).","howWorkedOut":"Liquidity pulled: down 90%+ or no longer listed by Jupiter while Jupiter answers. Price crashed: down 90%+. Halved: down 50%+. Top 10 up: their share rose 15+ points. Authorities: a different wallet now holds the power, or it was revoked. Empty means no change crossed those lines."}],"notes":["The check doesn't make a token safe, and it can't. It looks for the known ways people get robbed with a token. \"SAFE\" really means \"none of the traps we know about are present.\" Every rule exists because it matches a real scam.","It can't catch everything, such as a team abandoning a project or insiders it has no data on, and SAFE says nothing about whether the price will rise or fall.","history is not part of the verdict: the verdict is about the token now; history shows how it got here. Liquidity pulled since Pulse first saw it is the classic rug.","The sell test sells about $20 from a real holder's wallet in a simulation only: nothing is sent, and no funds move.","Top-holder share counts accounts, which can include exchanges and liquidity pools.","Established tokens (Jupiter-verified and trading for 90+ days) are judged on traps, not on how they're run: a mint or freeze authority, unlocked liquidity and a big treasury show up as info naming who holds them, because bridges, issuers and market makers run real tokens that way. New tokens get the strict checks, since that's when liquidity gets pulled."],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"token":{"type":"string","description":"The token's address. From find_token (for a ticker) or tokens (for a wallet's tokens)."},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["token"]}},{"name":"wallet","oldName":"wallet_snapshot","title":"What's in this wallet","category":"wallets","useWhen":"Run when asked what a wallet holds or is worth. One call instead of balance + tokens + history; spam is left out of the total.","benefit":{"kind":"accuracy","text":"Keeps priced and unpriced, verified and unverified holdings apart, so spam airdrops don't inflate what a wallet is worth."},"description":"SOL balance, top tokens with USD values, estimated total, and recent activity in one answer.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/wallet","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"wallet"},"inputs":[{"name":"wallet","type":"string (base58 address)","required":true,"lookingFor":"The wallet to sum up.","whereToGet":"The user's wallet address."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"sol","type":"string","is":"SOL balance.","howWorkedOut":"The balance tool."},{"field":"sol_usd","type":"number | null","is":"USD value of the SOL.","howWorkedOut":"sol x Jupiter's SOL price, rounded to cents."},{"field":"tokens_usd","type":"number","is":"USD value of the verified, priced tokens among the top 10.","howWorkedOut":"The tokens tool's total_usd for the top 10 (unverified tokens left out)."},{"field":"unverified_usd","type":"number","is":"Claimed USD value of unverified top tokens, kept out of the total because spam often carries a fake price.","howWorkedOut":"The tokens tool's unverified_usd for the top 10."},{"field":"total_usd","type":"number","is":"Estimated total worth: SOL plus verified, priced top tokens.","howWorkedOut":"sol_usd + tokens_usd. Unverified tokens, unpriced tokens and anything outside the top 10 aren't counted."},{"field":"partial","type":"boolean","is":"True when the total leaves something out (unpriced or unverified tokens, or more tokens than shown).","howWorkedOut":"A top token has no price or isn't verified, or the wallet holds more tokens than returned."},{"field":"token_count","type":"number","is":"How many token accounts with a balance the wallet has.","howWorkedOut":"The tokens tool's accounts_with_balance."},{"field":"unverified_count","type":"number","is":"Top tokens that aren't verified (maybe spam or scams). Don't present these as real value.","howWorkedOut":"The tokens tool's unverified_count for the top 10."},{"field":"top_tokens[]","type":"object[]","is":"Up to 10 tokens, highest USD value first, with address, symbol, amount, verified and value.","howWorkedOut":"The tokens tool with how_many 10. Fields explained there."},{"field":"activity.checked / failed","type":"number","is":"Recent transactions looked at, and how many failed.","howWorkedOut":"The history tool with how_many 10."},{"field":"activity.last_active","type":"string | null","is":"When the latest transaction happened (UTC).","howWorkedOut":"Time of the newest transaction."}],"notes":[],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"wallet":{"type":"string","description":"The wallet to sum up. The user's wallet address."},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["wallet"]}},{"name":"trace","title":"Where did the money go?","category":"wallets","useWhen":"Run when a wallet was drained or money went missing, or before trusting an address someone gave you: follows the money and flags sweeper, pass-through and lookalike-address patterns.","benefit":{"kind":"accuracy","text":"Shows each transaction's direction, amount and other side in one call, plus the drain patterns (sweeper fee payers, pass-through, address poisoning) with the transactions that show them, instead of a guess from a list of IDs."},"description":"Follows a wallet's money through its recent transactions: net SOL and token change and the other side of each, where most money went, and drain patterns with evidence.","price":"$0.02","priceText":"25 free calls a day, then $0.02 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/trace","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"trace"},"inputs":[{"name":"wallet","type":"string (base58 address)","required":true,"lookingFor":"The wallet to follow.","whereToGet":"The user's wallet, or an address from their report. Never make one up."},{"name":"how_many","type":"number","required":false,"lookingFor":"How many recent transactions to read, newest first (1-50, default 25).","whereToGet":"More covers a longer stretch of time."},{"name":"before","type":"string (signature)","required":false,"lookingFor":"Start below this transaction, to page further back.","whereToGet":"next_before from the previous answer."},{"name":"time_zone","type":"string (IANA time zone)","required":false,"lookingFor":"The person's time zone, so the report shows their clock time next to UTC, e.g. America/Chicago.","whereToGet":"Ask them, or leave it out for UTC only."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"wallet","type":"string","is":"The wallet that was followed.","howWorkedOut":"Your input, cleaned up."},{"field":"summary","type":"string","is":"What happened, in plain words, with the flags.","howWorkedOut":"Built from the fields below."},{"field":"period","type":"{ from, to }","is":"The time span the transactions cover (UTC).","howWorkedOut":"Oldest and newest block times."},{"field":"sol_now","type":"string | null","is":"SOL the wallet holds now. null if it couldn't be read.","howWorkedOut":"getBalance."},{"field":"flows[]","type":"array","is":"One entry per transaction, newest first: tx_id, time, result, direction (in / out / both / none), sol_change, token_changes (token, symbol, change, decimals), counterparty, fee_payer, wallet_signed, programs, memo.","howWorkedOut":"The wallet's own balance changes from each transaction's before/after balances; counterparty is the address whose change mirrors the wallet's biggest move; a fee-only change is direction none."},{"field":"top_destinations[]","type":"array","is":"Where most money went (up to 3, tokens first): address, transactions, sol_out, tokens_out (token, symbol, amount), and kind (wallet that can sign, program-controlled address, program, token account, or unknown).","howWorkedOut":"Outgoing flows grouped by counterparty; kind from the account's owner and whether the address is on the ed25519 curve."},{"field":"flags[]","type":"array","is":"Patterns found, each with name, level (warn / info), detail and the tx_ids that show it: fee_paid_by_other_wallet, passed_straight_through, lookalike_dust, dust_received, emptied, swept_to_collection_wallet.","howWorkedOut":"Fixed rules on the flows (see each detail). None says who anyone is."},{"field":"report","type":"object","is":"The same facts as a report a person can act on: problem (one line), evidence (every transaction that moved money, UTC and local time, what moved where, Solscan link), destinations (with Solscan links), confidence (high / medium / low and the reason), points_to, next_steps.","howWorkedOut":"Fixed rules on the flags: high only for the full drain pattern (swept and emptied) into anything but a busy collection wallet, medium for that case and for single signs, low when nothing matched. Built only from the fields above."},{"field":"unread","type":"number","is":"Transactions listed for the wallet that couldn't be loaded; they're left out, never guessed.","howWorkedOut":"Signatures minus loaded transactions."},{"field":"next_before","type":"string | null","is":"Pass as before to read the next, older page.","howWorkedOut":"The oldest transaction returned; null when there are no more."}],"notes":["Facts, not accusations: each flag says what the transactions show and what else can cause it.","No exchange or entity labels: Pulse has no verified source for them, so a destination is described only by what the chain says it is."],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"wallet":{"type":"string","description":"The wallet to follow. The user's wallet, or an address from their report. Never make one up."},"how_many":{"default":25,"description":"How many recent transactions to read, newest first (1-50, default 25). More covers a longer stretch of time.","type":"integer","minimum":1,"maximum":50},"before":{"description":"Start below this transaction, to page further back. next_before from the previous answer.","type":"string","minLength":64,"maxLength":100},"time_zone":{"description":"The person's time zone, so the report shows their clock time next to UTC, e.g. America/Chicago. Ask them, or leave it out for UTC only.","type":"string","maxLength":64},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["wallet"]}},{"name":"balance","oldName":"get_solana_balance","title":"SOL balance","category":"wallets","useWhen":"Run before sending SOL or paying fees, to confirm the wallet has enough. Never trust a remembered balance.","benefit":{"kind":"accuracy","text":"Reads the live balance, not one remembered from earlier in a chat, so the agent never builds a transfer the wallet can't cover."},"description":"A wallet's SOL balance, read from the chain.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/balance","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"balance"},"inputs":[{"name":"wallet","type":"string (base58 address)","required":true,"lookingFor":"The wallet to read the SOL balance of.","whereToGet":"The user's address (from their wallet app) or your agent's public key. Not a .sol name or ticker."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"wallet","type":"string","is":"The wallet that was read.","howWorkedOut":"Your input, cleaned up."},{"field":"network","type":"string","is":"The network that was read.","howWorkedOut":"Your input. Default mainnet-beta."},{"field":"lamports","type":"string (integer)","is":"The balance in lamports, SOL's smallest unit (1 SOL = 1,000,000,000 lamports).","howWorkedOut":"getBalance. A string so big numbers stay exact."},{"field":"sol","type":"string (decimal)","is":"The same balance in SOL.","howWorkedOut":"lamports / 10^9 with exact integer math."},{"field":"slot","type":"number","is":"The chain slot it was read at. Higher is newer.","howWorkedOut":"Returned with getBalance."}],"notes":[],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"wallet":{"type":"string","description":"The wallet to read the SOL balance of. The user's address (from their wallet app) or your agent's public key. Not a .sol name or ticker."},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["wallet"]}},{"name":"tokens","oldName":"get_token_accounts","title":"Tokens held","category":"wallets","useWhen":"Run to learn which tokens a wallet holds and how much. Ranked by USD value; unverified (often spam airdrop) tokens are flagged so you don't report fake holdings.","benefit":{"kind":"accuracy","text":"Ranks holdings by USD value and flags unverified tokens, so an agent doesn't report a wallet's spam airdrops as real money."},"description":"Lists a wallet's tokens (SPL Token and Token-2022) with exact amounts, whether each is verified, and USD value where priced.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/tokens","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"tokens"},"inputs":[{"name":"wallet","type":"string (base58 address)","required":true,"lookingFor":"The wallet to read the tokens of.","whereToGet":"The user's address (from their wallet app) or your agent's public key. Not a .sol name or ticker."},{"name":"how_many","type":"integer 1-100","required":false,"lookingFor":"How many tokens, highest USD value first, to return.","whereToGet":"Default 25."},{"name":"include_empty","type":"boolean","required":false,"lookingFor":"Include empty token accounts.","whereToGet":"True only to find empty accounts, e.g. to close them."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"wallet","type":"string","is":"The wallet that was read.","howWorkedOut":"Your input, cleaned up."},{"field":"accounts_total","type":"number","is":"Every token account the wallet owns, empty ones included.","howWorkedOut":"Token accounts across the SPL Token and Token-2022 programs."},{"field":"accounts_with_balance","type":"number","is":"Token accounts holding more than zero.","howWorkedOut":"Accounts with a raw amount above 0."},{"field":"returned","type":"number","is":"How many tokens are in this answer.","howWorkedOut":"Up to how_many, after sorting."},{"field":"unverified_count","type":"number","is":"Returned tokens Jupiter doesn't mark verified. A big number usually means spam airdrops.","howWorkedOut":"Tokens without Jupiter's verified flag, or that Jupiter doesn't know."},{"field":"total_usd","type":"number","is":"USD value of the returned tokens that are verified and priced. Spam often has a price from a tiny pool, so unverified tokens are left out.","howWorkedOut":"Sum of tokens[].usd_value for verified tokens. Unpriced tokens add nothing, so this can be low."},{"field":"unverified_usd","type":"number","is":"The claimed USD value of the unverified tokens, kept apart. Don't trust it.","howWorkedOut":"Sum of tokens[].usd_value for unverified tokens."},{"field":"tokens[].address","type":"string","is":"The token's address, its unique identity. Tickers aren't unique; addresses are.","howWorkedOut":"From the token account."},{"field":"tokens[].symbol / name","type":"string | null","is":"Ticker and name from Jupiter. Copycats can share a ticker, so trust the address, not the symbol.","howWorkedOut":"Jupiter token search by address."},{"field":"tokens[].verified","type":"boolean","is":"Whether Jupiter lists the token as verified.","howWorkedOut":"Jupiter's isVerified flag. false when unknown."},{"field":"tokens[].amount","type":"string (decimal)","is":"The balance in normal units.","howWorkedOut":"raw_amount / 10^decimals with exact integer math."},{"field":"tokens[].raw_amount","type":"string (integer)","is":"The balance in raw units, the number that goes into transfers.","howWorkedOut":"From the token account."},{"field":"tokens[].decimals","type":"number","is":"How many decimal places the token uses.","howWorkedOut":"From the token account."},{"field":"tokens[].holding_account","type":"string","is":"The account that holds this balance (not the wallet itself).","howWorkedOut":"The token account's address."},{"field":"tokens[].token_program","type":"\"spl-token\" | \"token-2022\"","is":"Which token program owns the account. Transfers must use the same one.","howWorkedOut":"Which program's lookup found it."},{"field":"tokens[].frozen","type":"boolean","is":"True if the issuer froze this account. Frozen tokens can't move.","howWorkedOut":"The account state is \"frozen\"."},{"field":"tokens[].usd_price","type":"number | null","is":"Price of one token in USD.","howWorkedOut":"Jupiter usdPrice. null when Jupiter has no price."},{"field":"tokens[].usd_value","type":"number | null","is":"USD value of this holding.","howWorkedOut":"amount x usd_price, rounded to cents. null without a price."}],"notes":["Prices come from Jupiter and can lag, or be missing for thinly traded tokens.","Very large wallets are capped: prices are looked up for at most 300 tokens."],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"wallet":{"type":"string","description":"The wallet to read the tokens of. The user's address (from their wallet app) or your agent's public key. Not a .sol name or ticker."},"how_many":{"default":25,"description":"How many tokens, highest USD value first, to return. Default 25.","type":"integer","minimum":1,"maximum":100},"include_empty":{"default":false,"description":"Include empty token accounts. True only to find empty accounts, e.g. to close them.","type":"boolean"},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["wallet"]}},{"name":"history","oldName":"get_recent_transactions","title":"Recent transactions","category":"wallets","useWhen":"Run to see a wallet's recent activity or get a real transaction ID. Never make one up.","benefit":{"kind":"accuracy","text":"Gives real transaction IDs. Models can make up realistic-looking fake ones, and every lookup after that fails."},"description":"Lists a wallet's latest transactions, newest first, whether each worked, and a plain error name for failures.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/history","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"history"},"inputs":[{"name":"wallet","type":"string (base58 address)","required":true,"lookingFor":"The wallet to read the transactions of.","whereToGet":"The user's address (from their wallet app) or your agent's public key. Not a .sol name or ticker."},{"name":"how_many","type":"integer 1-50","required":false,"lookingFor":"How many transactions to return.","whereToGet":"Default 10."},{"name":"before","type":"string (signature)","required":false,"lookingFor":"Start below this transaction, to page further back.","whereToGet":"next_before from the previous answer."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"wallet","type":"string","is":"The wallet that was read.","howWorkedOut":"Your input, cleaned up."},{"field":"count","type":"number","is":"How many transactions came back.","howWorkedOut":"Length of the list."},{"field":"failed_count","type":"number","is":"How many of them failed (failed transactions still pay fees).","howWorkedOut":"Entries with an error."},{"field":"transactions[].tx_id","type":"string","is":"The transaction's ID. Pass it to explain_tx.","howWorkedOut":"getSignaturesForAddress."},{"field":"transactions[].time","type":"string | null","is":"When it happened (UTC).","howWorkedOut":"Block time in ISO 8601. null if the node doesn't know."},{"field":"transactions[].slot","type":"number","is":"The slot it landed in.","howWorkedOut":"getSignaturesForAddress."},{"field":"transactions[].result","type":"\"success\" | \"failed\"","is":"Whether it worked.","howWorkedOut":"failed when the RPC reports an error."},{"field":"transactions[].error","type":"string | null","is":"The failure's short name, e.g. InsufficientFundsForRent.","howWorkedOut":"why_failed run on the raw error. The raw error text when unknown."},{"field":"transactions[].memo","type":"string | null","is":"Memo text attached to the transaction, if any.","howWorkedOut":"getSignaturesForAddress."},{"field":"next_before","type":"string | null","is":"Pass as before to read the next, older page. For amounts and the other side of each transaction, use trace.","howWorkedOut":"The oldest transaction returned; null when there are no more."}],"notes":[],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"wallet":{"type":"string","description":"The wallet to read the transactions of. The user's address (from their wallet app) or your agent's public key. Not a .sol name or ticker."},"how_many":{"default":10,"description":"How many transactions to return. Default 10.","type":"integer","minimum":1,"maximum":50},"before":{"description":"Start below this transaction, to page further back. next_before from the previous answer.","type":"string","minLength":64,"maxLength":100},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["wallet"]}},{"name":"blockhash","oldName":"get_solana_blockhash","title":"Fresh blockhash","category":"network","useWhen":"Run just before building a transaction to sign. Blockhashes expire in about 60-90 seconds; this says how long is left.","benefit":{"kind":"money","text":"Says how many seconds the blockhash has left. A transaction built on an expired one gets rejected after the agent has done all the work."},"description":"A fresh blockhash and how many blocks (and about how many seconds) are left before it expires.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/blockhash","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"blockhash"},"inputs":[{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"blockhash","type":"string","is":"The blockhash to put in your transaction.","howWorkedOut":"getLatestBlockhash."},{"field":"valid_until_height","type":"number","is":"Once the chain passes this block height, the transaction is rejected.","howWorkedOut":"Returned with the blockhash."},{"field":"current_height","type":"number","is":"The chain's block height right now.","howWorkedOut":"getBlockHeight."},{"field":"blocks_left","type":"number","is":"Blocks left before the blockhash expires.","howWorkedOut":"valid_until_height minus current_height."},{"field":"seconds_left","type":"number","is":"Rough time left to sign and send.","howWorkedOut":"blocks_left x 0.4 seconds (the target block time). Real times vary, so leave a margin."}],"notes":[],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}}}},{"name":"token_account","oldName":"find_ata","title":"Where to send a token","category":"tokens","useWhen":"Run before sending a token. Tokens go to the recipient's token account, not their wallet, and models can't work that address out.","benefit":{"kind":"money","text":"Works out the token account with the token's real program and prices creating it, so tokens aren't sent to a made-up or wrong-program address."},"description":"Finds the token account (ATA) for a wallet and token with the token's real program, says if it exists, and prices creating it.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/token_account","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"token_account"},"inputs":[{"name":"wallet","type":"string (base58 address)","required":true,"lookingFor":"The wallet that will own it (usually the recipient).","whereToGet":"The recipient's wallet address."},{"name":"token","type":"string (token address)","required":true,"lookingFor":"The token's address.","whereToGet":"From find_token or tokens. Not a ticker."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"address","type":"string","is":"The recipient's token account for this token. Send the tokens here.","howWorkedOut":"getAssociatedTokenAddressSync(token, wallet) with the token's own program."},{"field":"token_program","type":"\"spl-token\" | \"token-2022\"","is":"The token program the transfer must use.","howWorkedOut":"The program that owns the token."},{"field":"exists","type":"boolean","is":"Whether the account already exists on chain.","howWorkedOut":"Looked up on chain."},{"field":"balance","type":"string | null","is":"What the account holds now, when it exists.","howWorkedOut":"Token amount with the token's decimals."},{"field":"decimals","type":"number","is":"The token's decimals.","howWorkedOut":"From the token."},{"field":"create_cost_lamports","type":"string | null","is":"The SOL deposit (in lamports) to create the account when it doesn't exist. You get it back if the account is closed later.","howWorkedOut":"getMinimumBalanceForRentExemption for the account size, counting the token's Token-2022 extensions."},{"field":"create_cost_sol","type":"string | null","is":"The same deposit in SOL.","howWorkedOut":"create_cost_lamports / 10^9."},{"field":"owner_is_program","type":"boolean","is":"True when the wallet is a program-derived address, not a normal wallet. Fine for protocols, odd for people.","howWorkedOut":"The address is off the ed25519 curve."}],"notes":[],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"wallet":{"type":"string","description":"The wallet that will own it (usually the recipient). The recipient's wallet address."},"token":{"type":"string","description":"The token's address. From find_token or tokens. Not a ticker."},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["wallet","token"]}},{"name":"whats_this","oldName":"inspect_address","title":"What is this address?","category":"reference","useWhen":"Run when unsure what an address is, before sending to it or passing it on. SOL sent to a token or program address can be lost for good.","benefit":{"kind":"money","text":"Tells a normal wallet from a token, program or token account. SOL sent to a token or program address by mistake is stuck."},"description":"Says what any address is (wallet, token account, token, program, stake account and more) with its key facts.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/whats_this","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"whats_this"},"inputs":[{"name":"address","type":"string (base58 address)","required":true,"lookingFor":"Any Solana address.","whereToGet":"The address you're about to use."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"exists","type":"boolean","is":"Whether an account with SOL lives at this address. A wallet with no SOL doesn't, though it can still own tokens (see details.token_accounts).","howWorkedOut":"Looked up on chain."},{"field":"kind","type":"string","is":"wallet, token_account, mint (a token), program, program_data, stake_account, vote_account, lookup_table, program_owned_account or not_found.","howWorkedOut":"From the owner program, whether it's a program, and its data."},{"field":"summary","type":"string","is":"What it is, in plain words, and what's safe to do with it.","howWorkedOut":"Fixed text per kind."},{"field":"lamports / sol","type":"string","is":"SOL held by the account, in lamports and in SOL.","howWorkedOut":"The account's lamports; sol = lamports / 10^9."},{"field":"owner_program","type":"string | null","is":"The program that owns the account.","howWorkedOut":"The account owner."},{"field":"owner_program_name","type":"string | null","is":"That program's name, when we know it.","howWorkedOut":"Our table of program names."},{"field":"is_program","type":"boolean","is":"True for program accounts.","howWorkedOut":"The account's executable flag."},{"field":"can_sign","type":"boolean","is":"True for addresses that have a private key (normal keypairs). False for program-derived addresses, which can't sign.","howWorkedOut":"The address is on the ed25519 curve."},{"field":"details","type":"object","is":"Facts for this kind. Token accounts: token, owner, amount, delegate. Tokens: decimals, supply, who_can_mint, who_can_freeze. No SOL account: token_accounts, how many token accounts it owns, and has_history, whether it has any past transactions (each null if it couldn't be checked).","howWorkedOut":"From the account data; token_accounts from both token programs; has_history from the address's transaction signatures."}],"notes":[],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"address":{"type":"string","description":"Any Solana address. The address you're about to use."},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["address"]}},{"name":"convert","oldName":"convert_amount","title":"Convert token amounts","category":"tokens","useWhen":"Run before putting any token amount in a transaction. \"5 USDC\" is 5,000,000 raw units; wrong decimals send 1,000x too much or too little.","benefit":{"kind":"money","text":"5 USDC is 5,000,000 raw units because USDC has 6 decimals. Get the decimals wrong and you send 1,000 times too much or too little."},"description":"Converts between normal amounts and raw units with the token's real on-chain decimals.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/convert","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"convert"},"inputs":[{"name":"token","type":"string (token address) or \"SOL\"","required":true,"lookingFor":"The token, or \"SOL\" for SOL (9 decimals).","whereToGet":"From find_token or tokens."},{"name":"amount","type":"string (decimal)","required":true,"lookingFor":"The amount, as a string: \"5\" or \"0.25\".","whereToGet":"The user's amount. A string avoids rounding errors."},{"name":"to","type":"\"raw\" | \"readable\"","required":false,"lookingFor":"Direction. \"raw\" turns 5 into 5000000 (for transactions); \"readable\" turns raw units back. Default \"raw\".","whereToGet":"\"readable\" for amounts read from chain data."},{"name":"network","type":"\"mainnet-beta\" | \"devnet\"","required":false,"lookingFor":"Default \"mainnet-beta\" (real money).","whereToGet":"\"devnet\" only for test wallets."}],"outputs":[{"field":"token","type":"string","is":"The token converted (SOL's own address for SOL).","howWorkedOut":"Your input. \"SOL\" becomes So11111111111111111111111111111111111111112."},{"field":"symbol","type":"string | null","is":"Ticker from Jupiter, for display only.","howWorkedOut":"Jupiter token search by address."},{"field":"decimals","type":"number","is":"Decimal places the token uses.","howWorkedOut":"Read from the token on chain (SOL is always 9)."},{"field":"decimals_from","type":"string","is":"Where the decimals came from, so you can trust them.","howWorkedOut":"\"on-chain token\" or \"SOL (fixed)\"."},{"field":"raw_amount","type":"string (integer)","is":"The amount in raw units, exactly as it goes into a transfer.","howWorkedOut":"amount x 10^decimals with exact integer math. Refuses more decimal places than the token has."},{"field":"amount","type":"string (decimal)","is":"The normal, readable amount.","howWorkedOut":"raw_amount / 10^decimals with exact integer math."},{"field":"summary","type":"string","is":"One sentence stating the conversion.","howWorkedOut":"Built from the values above."}],"notes":[],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"token":{"type":"string","description":"The token, or \"SOL\" for SOL (9 decimals). From find_token or tokens."},"amount":{"type":"string","description":"The amount, as a string: \"5\" or \"0.25\". The user's amount. A string avoids rounding errors."},"to":{"default":"raw","description":"Direction. \"raw\" turns 5 into 5000000 (for transactions); \"readable\" turns raw units back. Default \"raw\". \"readable\" for amounts read from chain data.","type":"string","enum":["raw","readable","to_base_units","to_ui"]},"network":{"default":"mainnet-beta","description":"Default \"mainnet-beta\" (real money). \"devnet\" only for test wallets.","type":"string","enum":["mainnet-beta","devnet"]}},"required":["token","amount"]}},{"name":"why_failed","oldName":"explain_error","title":"Why did it fail?","category":"reference","useWhen":"Run whenever a Solana transaction or dry run fails, before retrying. Retrying blind burns fees.","benefit":{"kind":"money","text":"Explains the failure before the agent retries. 0x1771 from Jupiter means the price moved past the slippage limit, and a blind retry won't fix that."},"description":"Turns a Solana error (hex code, log line or RPC error) into the plain cause and fix. Offline, no chain call.","price":"$0.01","priceText":"25 free calls a day, then $0.01 USDC per call (x402)","http":{"method":"POST","path":"/api/tools/why_failed","body":"JSON object with the inputs below"},"mcp":{"method":"tools/call","name":"why_failed"},"inputs":[{"name":"error","type":"string or object","required":true,"lookingFor":"The error as you got it: \"custom program error: 0x1771\", \"InsufficientFundsForRent\", or the RPC error object.","whereToGet":"From your send or RPC error, a dry-run result, a wallet message, or history."},{"name":"program","type":"string (base58 address)","required":false,"lookingFor":"The failing program. Needed to read custom error codes right.","whereToGet":"From the log line \"Program <address> failed\", or from explain_tx."}],"outputs":[{"field":"known","type":"boolean","is":"Whether we know this error.","howWorkedOut":"At least one explanation matched."},{"field":"failed_step","type":"number | null","is":"Which step in the transaction failed (counting from 0).","howWorkedOut":"Read from InstructionError [step, ...] or \"instruction N\" in the text."},{"field":"program","type":"string | null","is":"The program the error was read against.","howWorkedOut":"Your input, or the program named in the error text."},{"field":"explanations[].name","type":"string","is":"The error's official name.","howWorkedOut":"Matched against tables for transaction errors, instruction errors, the System and Token programs, Anchor and selected programs."},{"field":"explanations[].scope","type":"string","is":"Which layer raised it: transaction, instruction, system_program, token_program, anchor_framework or program_specific.","howWorkedOut":"Which table matched."},{"field":"explanations[].meaning","type":"string","is":"What went wrong, in plain words.","howWorkedOut":"Written by hand."},{"field":"explanations[].likely_cause","type":"string","is":"The usual reason it happens.","howWorkedOut":"Written by hand."},{"field":"explanations[].fix","type":"string","is":"What to change before retrying, often naming the tool that helps.","howWorkedOut":"Written by hand."},{"field":"next_step","type":"string","is":"The one thing to do next.","howWorkedOut":"The first explanation's fix, or how to find the failing program when the error is unknown."}],"notes":["Custom codes 6000 and up are defined by each program. Without program we say so instead of guessing."],"inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"error":{"anyOf":[{"type":"string"},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}],"description":"The error as you got it: \"custom program error: 0x1771\", \"InsufficientFundsForRent\", or the RPC error object. From your send or RPC error, a dry-run result, a wallet message, or history."},"program":{"description":"The failing program. Needed to read custom error codes right. From the log line \"Program <address> failed\", or from explain_tx.","type":"string"}},"required":["error"]}}]}