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.
| # | When | Verdict |
|---|---|---|
| R1 | A 7702 delegation to code that has no source on Sourcify, or no label, or with chainId 0 (valid on every chain). | DON'T SIGN |
| R2 | Assets 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 |
| R3 | An 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 |
| R4 | A Permit or Permit2 signature whose spender is a plain wallet, not a contract. | DON'T SIGN |
| R5 | A Permit2 permitTransferFrom (a transfer by signature) to an unlabeled address. | DON'T SIGN |
| R6 | An unlimited allowance or "all assets" approval to a labeled or verified contract. | READ AGAIN |
| R7 | A limited allowance to an unlabeled address. | READ AGAIN |
| R8 | A swap that sends the output to someone else, or you lose tokens and get nothing back, or the transaction would revert. | READ AGAIN |
| R9 | A call we can't decode that moves nothing and allows nothing, to a contract with no readable source. | READ AGAIN |
| R10 | Typed data that isn't a Permit (NFT orders, sign-in messages, anything else). Fields are listed as they are. | READ AGAIN |
| R11 | Just an address: READ AGAIN if it has no readable source, SOBER if it is verified or labeled. | READ AGAIN / SOBER |
| R12 | Everything 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.originor 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:
| Label | Address |
|---|---|
| Uniswap Permit2 | 0x000000000022D473030F116dDEE9F6B43aC78BA3 |
| USDG (Global Dollar) | 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 |
| WETH | 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73 |
| Uniswap V3 SwapRouter02 | 0xCaf681a66D020601342297493863E78C959E5cb2 |
| Uniswap Universal Router | 0x8876789976decbfcbbbe364623c63652db8c0904 |
| Uniswap router (alt) | 0x755A17798BFa5D2Fcbaf504D70aefA2295e27214 |
| Uniswap V3 Factory | 0x1f7d7550B1b028f7571E69A784071F0205FD2EfA |
| Uniswap V3 pool WETH/USDG 0.05% | 0x69BfaF19C9f377BB306a89aEd9F6B07e2c1a8d9a |
| Uniswap v4 PoolManager | 0x8366a39CC670B4001A1121B8F6A443A643e40951 |
| Uniswap v4 PositionManager | 0x58daec3116aae6D93017bAAea7749052E8a04fA7 |
| Tesla Robinhood Token | 0x322F0929c4625eD5bAd873c95208D54E1c003b2d |
| Apple Robinhood Token | 0xaF3D76f1834A1d425780943C99Ea8A608f8a93f9 |
| Nvidia Robinhood Token | 0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC |
| SPY Robinhood Token | 0x117cc2133c37B721F49dE2A7a74833232B3B4C0C |
| Alphabet Robinhood Token | 0x2e0847E8910a9732eB3fb1bb4b70a580ADAD4FE3 |
| Uniswap V3 pool TSLA/USDG 0.05% | 0xc4f0172D6ac8DD294Dd1137D047d5E1893760236 |
| Uniswap V3 pool TSLA/USDG 0.3% | 0xf4ACdAEEB7022862A763C9B1B885e11191c889E3 |
| Pons launchpad | 0x7eD598BcEf8bd9Edd8C97A195C6d13f40801EC7e |
| 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.
| Endpoint | Returns |
|---|---|
POST /api/explain | ExplainResponse: 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/examples | The four examples, ready to paste. |
GET /api/stats | Counters from our database: explained, explained24h, byVerdict. |
GET /api/health | RPC, 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
holderwith 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.