LayerHopDocsLaunch app (opens in a new tab)

Transaction preview

Explain a raw EVM transaction, an EIP-712 signature request or a Solana transaction in plain language before anyone signs it, with balance changes, approvals and drainer red flags.

Wallet drainers work because a confirmation screen shows hex. POST /v1/preview turns what a dapp asked a wallet to sign into plain language: what leaves the wallet, what comes back, which permissions it grants, who gets what, and red flags. It never asks for a signature and never sends anything. The same tool runs at layerhop.com/preview and app.layerhop.com/preview.

Terminal
curl -X POST https://api.layerhop.com/v1/preview \
  -H "content-type: application/json" \
  -d '{
    "kind": "evm_tx",
    "chain": 8453,
    "tx": {
      "from": "0x1111111111111111111111111111111111111111",
      "to": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "data": "0x095ea7b30000000000000000000000002222222222222222222222222222222222222222ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
    }
  }'
JSON
{
  "preview": {
    "kind": "evm_tx",
    "chainId": 8453,
    "summary": "Danger: lets 0x2222…2222 spend unlimited USDC from your wallet",
    "risk": "danger",
    "approvals": [{ "token": "0x8335…2913", "symbol": "USDC", "spender": "0x2222…2222", "unlimited": true, "via": "approve", "spenderIsContract": false }],
    "flags": [{ "code": "approval_to_eoa", "level": "danger", "message": "0x2222…2222 is a wallet, not an app's contract. Giving a wallet permission to move your USDC is how most drainers work." }],
    "simulation": { "method": "eth_simulateV1", "ok": true, "gasUsed": "55906" }
  }
}

What you can send#

kind Fields How it's explained
evm_tx chain, tx.from, tx.to, tx.data, tx.value (base units) Simulated against the latest block, and the calldata decoded
typed_data typedData (object or JSON string), optional from, chain Decoded (a signature can't be simulated)
solana_tx tx (base64, legacy or v0), optional from simulateTransaction with the accounts before and after

How EVM transactions are simulated#

  1. eth_simulateV1 with traceTransfers: every ERC-20, ERC-721 and ERC-1155 transfer, plus native-coin transfers as synthetic logs. Most public RPCs serve it (checked on Ethereum, Base and Arbitrum, 2026-10-28).
  2. Else debug_traceCall with the call tracer's logs (native transfers from the call frames; reverted frames are skipped).
  3. Else a plain eth_call: it tells whether the transaction would revert, and the balance changes come from decoding the calldata.

simulation.method says which one ran; simulation.ok: false with error means the transaction would fail right now (it also adds a simulation_failed flag). A revert is told apart from a node that can't simulate even when the node reports it as -32000 / -32603. method: "none" (no RPC could run it) adds a simulation_failed caution too: what the transaction moves is unknown.

The calldata is decoded either way: approve, increaseAllowance, setApprovalForAll, transfer, transferFrom, safeTransferFrom (ERC-721 and ERC-1155), safeBatchTransferFrom, EIP-2612 permit, Permit2 approve / permit / transferFrom, and the calls inside multicall and Multicall aggregate.

Signature requests#

A signature can move tokens later without another confirmation, which is why drainers ask for one. Decoded types:

  • EIP-2612 Permit and DAI-style Permit (allowed: true is unlimited and, with expiry: 0, never expires).
  • Permit2: PermitSingle, PermitBatch, PermitTransferFrom, PermitBatchTransferFrom and their witness variants.
  • Seaport OrderComponents and BulkOrder (a tree of orders under one signature, each order checked): what the signer offers and who receives what. gives_away_assets flags an order that pays the signer nothing back, only dust (under 1/10,000 of a token), sends most of a payment token to someone else, or returns less of a token than it takes (the fake "listing" NFT drain). Prices aren't known, so an order paid in a worthless token isn't caught.

Anything else is reported as unknown_function: only sign it on a site you trust. An unreadable order-like message (Blur, 1inch, 0x and other …Order types) says so: treat signing it as handing over everything it offers.

Red flags#

Code Level When
approval_to_eoa, permit_to_eoa danger The spender is a wallet, not a contract
approval_to_unknown, permit_to_unknown danger if unlimited, else caution A contract LayerHop can't name
approve_all_nfts danger (unknown) / caution (named) setApprovalForAll(true)
unlimited_approval caution Unlimited, to a named spender
long_permit caution The permission lasts more than a year or never expires
value_to_eoa caution, danger with calldata Native coin sent straight to a wallet
unverified_contract, new_contract caution (new_contract spender: danger) Source not published / deployed less than 7 days ago (needs ETHERSCAN_API_KEY on the deployment)
gives_away_assets danger Assets leave the wallet, nothing comes back, and they go to an address the call doesn't name and LayerHop doesn't recognize (a fake claim() spending an old allowance, value paid into an unknown contract; a plain transfer you send yourself isn't flagged); a Seaport order as above; on Solana, a signer other than the fee payer losing assets, a token account handed to someone else, or a signer's account assigned to another program
community_reports caution, danger from 3 approved reports An address involved has community reports a LayerHop admin approved, on the preview's chain. Unreviewed reports are listed in community without a flag; Permit2, named spenders and listed tokens never get one
simulation_failed, unknown_function, wrong_chain caution The transaction would revert (or couldn't be simulated); we can't read the call (even when the simulation shows what it moved); the signature names another chain

Named spenders are the approval targets LayerHop's own routes use (Permit2, LI.FI, 0x, Relay, deBridge, Mayan, KyberSwap …) and the major DEX routers: the same list as the approvals page. risk is the worst flag's level and summary starts with "Danger:" when it's danger.

Solana#

simulateTransaction runs with sigVerify: false and a replaced blockhash, so an unsigned transaction works. Address lookup tables are resolved read-only (up to 100 accounts). For from (default: the fee payer) the preview reports SOL changes (network fee included) and token balance changes per mint in balanceChanges. For every signer it reports new token delegates (unlimited_approval when the delegate can move everything), token accounts whose owner would change and signer accounts assigned to another program (gives_away_assets). Other signers' changes are listed in actions; without from, a signer other than the fee payer that loses assets and gets nothing back is gives_away_assets (drainers pay the fee themselves and make the victim a second signer). Send from with a multi-signer transaction to see your own wallet's changes.

Limits#

20 previews per minute per API key or IP (RATE_LIMITED), and a shared budget for all clients; a preview answers within 25 seconds or fails with PROVIDER_ERROR. Identical requests within 30 seconds are served from cache (x-cache: hit). A preview is a snapshot of the latest block: the result can change by the time the user signs. Flags catch common drainer patterns, not every scam.

In the app#

  • app.layerhop.com/health scores any wallet 0–100 from open approvals, risky tokens held, address-poisoning traps, stuck withdrawals and dust, each with a fix-it link; the share card shows only the score.
  • Community reports show up in the recipient check, the token risk badge and the preview page. See Community reports.

Last updated