{"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"]}}