SIGNSOBER

SIGNSOBER docs

This is a simulation on the latest block, not an audit. State can change before your transaction lands. SIGNSOBER can be wrong; it cannot make a signature safe.

What it does

Paste what your wallet asks you to sign. SIGNSOBER decodes it, simulates it on the latest Robinhood Chain block with eth_simulateV1, and turns the resulting facts into plain words. It never asks you to sign anything and never sends a transaction.

You always get the same three lines and one of three verdicts:

You lose
Assets that leave your address in this transaction, with a USD value when a price exists.
You allow
What someone else may take later: allowances, Permit2 permits, operator approvals, 7702 delegations. Amount and expiry ("forever" if none).
Who gets it
Each spender, recipient or delegate: contract or wallet, verified on Sourcify or "no source code we can read", known label, creation time when we have it.

SOBER READ AGAIN DON'T SIGN

Inputs

One text box takes all of these. Detection order is fixed: tx hash → address → EIP-712 typed data → 7702 transaction → 7702 authorization → tx JSON → calldata with to. Max 64 KB. An eth_sendTransaction params array ([tx]), an escaped JSON string and hex without 0x also work.

1 · Transaction JSON kind: tx

Anything with to plus data, input or value. from is optional (we use a demo address with a borrowed balance). A chainId other than 4663 is decoded but not simulated. Example 1, an unlimited USDG approval to an unverified contract born 30 Oct:

{"from": "0x000000000000000000000000000000000000dEaD", "to": "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168", "data": "0x095ea7b3000000000000000000000000019e3a373650fa8ff495c6c550ce085575656df5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}

Example 4, a normal Uniswap swap (0.001 ETH → USDG through SwapRouter02):

{"from": "0x000000000000000000000000000000000000dEaD", "to": "0xCaf681a66D020601342297493863E78C959E5cb2", "value": "0x38D7EA4C68000", "data": "0x04e45aaf0000000000000000000000000bd7d308f8e1639fab988df18a8011f41eacad730000000000000000000000005fc5360d0400a0fd4f2af552add042d716f1d16800000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000000000000000000000000000000000000000dead00000000000000000000000000000000000000000000000000038d7ea4c6800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

2 · Calldata + to kind: calldata

Bare hex calldata. The page shows a small to field when it sees it; in the API, send "to" next to "input".

{"input": "0x095ea7b3000000000000000000000000019e3a373650fa8ff495c6c550ce085575656df5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "to": "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168"}

3 · EIP-712 typed data kind: typedData

JSON with types, domain and message. ERC-2612 Permit and Permit2 PermitSingle, PermitBatch, PermitTransferFrom, PermitBatchTransferFrom are read field by field; anything else is listed as fields. Example 3, a Permit2 signature for a stock token:

{"types": {"EIP712Domain": [{"name": "name", "type": "string"}, {"name": "chainId", "type": "uint256"}, {"name": "verifyingContract", "type": "address"}], "PermitDetails": [{"name": "token", "type": "address"}, {"name": "amount", "type": "uint160"}, {"name": "expiration", "type": "uint48"}, {"name": "nonce", "type": "uint48"}], "PermitSingle": [{"name": "details", "type": "PermitDetails"}, {"name": "spender", "type": "address"}, {"name": "sigDeadline", "type": "uint256"}]}, "primaryType": "PermitSingle", "domain": {"name": "Permit2", "chainId": 4663, "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3"}, "message": {"details": {"token": "0x322F0929c4625eD5bAd873c95208D54E1c003b2d", "amount": "1461501637330902918203684832716283019655932542975", "expiration": "1796000000", "nonce": "0"}, "spender": "0x8876789976decbfcbbbe364623c63652db8c0904", "sigDeadline": "1793500000"}}

4 · 7702 authorization kind: authorization7702 / tx7702

{chainId, address, nonce} (with or without yParity/r/s), or a transaction with authorizationList / type 4. Example 2, a delegation to unverified code:

{"chainId": 4663, "address": "0x019e3a373650Fa8FF495c6C550CE085575656DF5", "nonce": 0}

5 · Transaction hash kind: txhash

0x + 64 hex. If the transaction already landed, we read its real receipt logs ("what you already signed"), not a re-simulation. Our node only keeps recent data, so older hashes may return tx_not_found.

0xbb81fff2c4952da8d8e45319bbb1428e20bdff533668faf21e5bef89ff2d668c

6 · Contract address kind: address

0x + 40 hex. You get who it is: contract or wallet, code size, Sourcify status, label.

0x019e3a373650Fa8FF495c6C550CE085575656DF5

Verdict rules

The verdict is set by fixed rules on the server before any words are written. The AI writer cannot change it. Rules are checked top to bottom; the first match wins. The code of the rule that matched (for example R3:unlimited_to_unverified) is shown under "facts" and returned in reasons.

#WhenVerdict
R1A 7702 delegation to code that has no source on Sourcify, or no label, or with chainId 0 (valid on every chain).DON'T SIGN
R2Assets leave your address to someone without a label who is a wallet or has no readable source, and it isn't a swap that sends tokens back to you.DON'T SIGN
R3An unlimited allowance (or "all your NFTs") to an unlabeled address that has no readable source, is a plain wallet, or was created less than 7 days ago.DON'T SIGN
R4A Permit or Permit2 signature whose spender is a plain wallet, not a contract.DON'T SIGN
R5A Permit2 permitTransferFrom (a transfer by signature) to an unlabeled address.DON'T SIGN
R6An unlimited allowance or "all assets" approval to a labeled or verified contract.READ AGAIN
R7A limited allowance to an unlabeled address.READ AGAIN
R8A swap that sends the output to someone else, or you lose tokens and get nothing back, or the transaction would revert.READ AGAIN
R9A call we can't decode that moves nothing and allows nothing, to a contract with no readable source.READ AGAIN
R10Typed data that isn't a Permit (NFT orders, sign-in messages, anything else). Fields are listed as they are.READ AGAIN
R11Just an address: READ AGAIN if it has no readable source, SOBER if it is verified or labeled.READ AGAIN / SOBER
R12Everything else: what you lose is only what a swap gives back, and any allowance is limited and goes to a labeled party.SOBER

Unlimited means ≥ 2255 for ERC-20 / ERC-2612, and 2160−1 for Permit2. SOBER is not "safe": it means we found nothing that takes or allows your assets in this one transaction.

Simulation

Transactions (tx JSON, calldata, tx hashes that have not landed) run through eth_simulateV1 with traceTransfers on the latest block of Robinhood Chain (chain 4663). One call, nothing is broadcast. Every ERC-20, ERC-721, ERC-1155 and ETH transfer in the logs becomes "you lose" (from you) or "you get" (to you), netted per token.

If you don't connect, or your address doesn't hold enough, we simulate with a borrowed balance: the sender's ETH balance is overridden to 1 ETH for the simulation only. The card says "simulated with a borrowed balance" when that happens.

What a simulation cannot see:

  • Other transactions in the same block, before or after yours.
  • State changes between now and when your transaction actually lands (prices, allowances, upgradeable contracts, paused tokens).
  • Contracts that behave differently for the real sender, for example when tx.origin or the block differs.

If it would revert, you see "This would fail right now:" with the reason, and the verdict is READ AGAIN.

EIP-7702

Robinhood Chain does not execute EIP-7702 delegations today. We checked on 30 Oct 2026, 17:40 UTC: eth_simulateV1 ignores authorizationList, and delegated code (0xef01…) fails with "invalid opcode: opcode 0xef not defined". So 7702 inputs are explained, not simulated.

An authorization is still dangerous to sign: it lets the delegate's code act as your wallet, for every asset, until you revoke it. One with chainId 0 is valid on every chain, and chains can upgrade. To revoke, sign a new authorization that delegates to 0x0000000000000000000000000000000000000000.

Prices

  • USDG = $1.
  • ETH / WETH from the Uniswap V3 WETH/USDG 0.05% pool on Robinhood Chain.
  • Other tokens: the Uniswap V3 pool against USDG with the most liquidity (0.05%, 0.3% or 1%).
  • No pool, no price: the card says "no USD price".

This is a Uniswap V3 pool price on Robinhood Chain, not an oracle. Prices are cached for 60 seconds.

Sources & labels

Source check = Sourcify. "Verified on Sourcify" means the published source matches the deployed code. "No source code we can read" means Sourcify has none. That does not mean malicious: busy, legitimate contracts on Robinhood Chain have no Sourcify entry. If Sourcify is down, the card says "source check unavailable" and the rules treat it like no source.

Explorer links go to Blockscout (robinhoodchain.blockscout.com) for you to check by hand. Our server cannot read Blockscout's API right now, so contract age is usually unknown.

Labels come from a short fixed list:

LabelAddress
Uniswap Permit20x000000000022D473030F116dDEE9F6B43aC78BA3
USDG (Global Dollar)0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168
WETH0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73
Uniswap V3 SwapRouter020xCaf681a66D020601342297493863E78C959E5cb2
Uniswap Universal Router0x8876789976decbfcbbbe364623c63652db8c0904
Uniswap router (alt)0x755A17798BFa5D2Fcbaf504D70aefA2295e27214
Uniswap V3 Factory0x1f7d7550B1b028f7571E69A784071F0205FD2EfA
Uniswap V3 pool WETH/USDG 0.05%0x69BfaF19C9f377BB306a89aEd9F6B07e2c1a8d9a
Uniswap v4 PoolManager0x8366a39CC670B4001A1121B8F6A443A643e40951
Uniswap v4 PositionManager0x58daec3116aae6D93017bAAea7749052E8a04fA7
Tesla Robinhood Token0x322F0929c4625eD5bAd873c95208D54E1c003b2d
Apple Robinhood Token0xaF3D76f1834A1d425780943C99Ea8A608f8a93f9
Nvidia Robinhood Token0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC
SPY Robinhood Token0x117cc2133c37B721F49dE2A7a74833232B3B4C0C
Alphabet Robinhood Token0x2e0847E8910a9732eB3fb1bb4b70a580ADAD4FE3
Uniswap V3 pool TSLA/USDG 0.05%0xc4f0172D6ac8DD294Dd1137D047d5E1893760236
Uniswap V3 pool TSLA/USDG 0.3%0xf4ACdAEEB7022862A763C9B1B885e11191c889E3
Pons launchpad0x7eD598BcEf8bd9Edd8C97A195C6d13f40801EC7e
Pons launchpad (MemeHook)0xE5e702641Ea86F4ae6cC3cDaeD2B886f976Be044
system (ArbOS)0x…0a4b05 (precompile; shown as "system", never as a spender)

A label says who we think an address is. It is not an endorsement.

API

Agents holding wallets ask before they sign. JSON, no key, CORS open. Types: /shared/api.d.ts.

EndpointReturns
POST /api/explainExplainResponse: verdict, reasons, text {lose, allow, who, why}, facts, curl. Body: {"input": "…"}, optional to, from, holder, or example: 1–4.
GET /api/explain?input=…Same, for one-line curl (input up to 2 KB).
GET /api/examplesThe four examples, ready to paste.
GET /api/statsCounters from our database: explained, explained24h, byVerdict.
GET /api/healthRPC, Sourcify and AI writer status.

Explain anything

curl -s https://signsober.xyz/api/explain -H 'content-type: application/json' -d '{"input":"<paste>"}'

Who is this address?

curl -s "https://signsober.xyz/api/explain?input=0x019e3a373650Fa8FF495c6C550CE085575656DF5"

Response (shape)

{
  "ok": true,
  "id": "…",
  "verdict": "DON'T SIGN",
  "reasons": ["R3:unlimited_to_unverified"],
  "text": { "lose": "…", "allow": "…", "who": "…", "why": "…" },
  "source": "llm",
  "facts": {
    "kind": "tx", "chainId": 4663, "from": "0x…", "to": "0x…",
    "intents": ["approve"],
    "lose": [], "gain": [], "allow": [ { "unlimited": true, "spender": "0x…", … } ],
    "who": [ { "address": "0x…", "sourcify": null, "label": null, … } ],
    "simulated": true, "balanceWasOverridden": true, "block": 101911802, "revert": null, "notes": []
  },
  "ms": 1200,
  "disclaimer": "…",
  "curl": "…"
}

Errors: {"ok": false, "error": "cannot_parse" | "bad_address" | "too_large" | "quota" | "rpc_unavailable" | "rate_limited" | "tx_not_found", "message": "…"} with HTTP 400 / 404 / 429 / 503. source is "template" when the AI writer is unavailable or its text used a number that was not in the facts; the verdict is the same either way.

Limits

  • 20 explanations a day per IP, reset at 00:00 UTC. The four examples are not counted.
  • After launch, sending holder with an address that holds ≥ 1,000,000 of the token raises that to 500 a day.
  • We check the address, not a signature. We don't ask you to sign to prove holding. Yes, that means you can borrow a holder's address. It's a rate limit, not a vault.
  • Also 30 requests a minute per IP on /api/explain.

Privacy

We don't store what you paste. For the counter we keep one row per explanation: time, a hash of the input, the input kind, the verdict, whether the words came from the AI writer or the template, how long it took, and a salted hash of your IP for the daily limit. Server logs don't contain your input. "Connect" only reads your address; we never ask your wallet to sign anything or send a transaction.

Token

After launch, holding ≥ 1,000,000 tokens raises the limit from 20 to 500 a day. Enforced by our server, not by a contract.

The token launches on Pons on 31 Oct 2026 at 18:00 UTC. The contract address appears on the home page and on x.com/signsober at launch.

FAQ

Does SOBER mean safe?
No. It means we found nothing that takes or allows your assets in this one transaction.
Can it be fooled?
Yes: contracts can behave differently when the real tx lands, and 'no source code' does not mean malicious.
Why no 7702 simulation?
The chain does not run it yet.
Do you store what I paste?
No.
Why Sourcify and not Blockscout?
Our server cannot read Blockscout's API right now; links still go there for you.
Would this have stopped the Binance hack?
We don't know and won't claim it. It reads one signature at a time.