Skip to main content

This site is for educational purposes only. Nothing here constitutes financial advice.

Lesson 3 of 8
~22 minOn-Chain Research

Lesson 3 — Approvals and signatures revisited: decoding what you're about to sign

Most wallet drains are signed willingly. Today: how to decode the four signature types so you know exactly what you're authorising, before you authorise it.

Intermediate
Evergreen
22 min readUpdated 2026-05-18Block Clarity Hub Editorial Team

We've covered approvals at the security-bootcamp level (what they do) and the scam-defense level (how drainers exploit them). This lesson is the on-chain reading layer: given a signature request, how do you decode it against the contract's verified source to know exactly what you're about to authorise?

**The four signature types your wallet presents.** (1) On-chain transactions — a function call that changes state, sent to the network with gas. (2) Token approvals — a specific kind of transaction that calls `approve(spender, amount)` to grant transfer permission. (3) EIP-712 typed signatures — structured off-chain messages with named fields, used by Permit/Permit2 and other systems. (4) `personal_sign` messages — unstructured off-chain message signing, typically for authentication ('Sign in with Ethereum'). Drainers most heavily exploit categories 2 and 3 because the consequences are misunderstood.

**Decoding an on-chain transaction.** When a contract interaction is presented for signing, MetaMask shows the contract address, the function name (if known), and the decoded arguments. The decoded view depends on the contract being verified on Etherscan — verified means MetaMask can fetch the ABI and parse the calldata into readable fields. Unverified contracts show raw hex calldata; if you don't know what those bytes mean, you're signing blind. The defensive habit: never sign an on-chain transaction to an unverified contract unless you have an out-of-band reason to trust it.

**Decoding a token approval.** When you sign `approve(spender, amount)`, the spender address and amount are the load-bearing fields. The amount can be specific (e.g., 100 USDC) or infinite (`2^256 - 1`, which most wallets display as 'unlimited' or 'maximum'). Wallets that auto-suggest unlimited approvals (because it saves gas on future swaps) are convenient and dangerous — the approved contract can now move any amount of that token from your wallet, at any future time, until you revoke. The defensive habit: approve specific amounts when possible; revoke unused approvals weekly (revoke.cash makes this easy).

**Decoding an EIP-712 signature.** EIP-712 is the standard for typed off-chain signatures. The signed message has named fields (e.g., `Permit { owner, spender, value, nonce, deadline }`), and modern wallets decode the structure for you. Read every field: who is the owner (should be your address), who is the spender (an unknown address is a red flag), what is the value (look for 2^256-1 patterns), what is the deadline (a far-future timestamp grants near-permanent authority). The Permit (EIP-2612) signature is the most-exploited variant because users sign 'a Permit message' without reading the fields and then their tokens are gone.

**Decoding a `personal_sign` message.** These are arbitrary text or hex messages signed by your private key. They cannot directly authorise token transfers, but they can be used by drainers to: (a) authenticate you to a malicious site that then convinces you to sign a different, dangerous request, or (b) sign data that an attacker's smart contract later interprets as authority (a less-common but documented pattern). The defensive habit: only sign `personal_sign` messages whose text you can read and understand. 'Welcome to Site X' is fine; an opaque blob of hex is suspicious.

**Permit2 — the universal-approval pattern.** Permit2 is a Uniswap-built contract (deployed across many chains) that holds approvals from many tokens for many users. Once you've approved Permit2 to spend a token (a one-time on-chain transaction), you can then authorise specific applications via signed off-chain messages instead of on-chain transactions for each app. The convenience is real; the risk surface is concentrated. A drainer can craft a Permit2 signature that, if signed, lets them move any token you've approved to Permit2. Reading the decoded Permit2 signature payload — token, amount, spender, deadline — is the only defense.

**The discipline: read before signing.** Every wallet shows the decoded payload if you expand the signature request. Most users don't expand. The single biggest behavioural change this course can teach is: before clicking Sign on anything, expand the decoded view and read every field. If the decoded view says 'spender: 0xa1b2... (unknown)' or 'value: 115792089237316195423570985008687907853269984665640564039457584007913129639935' (that's 2^256 - 1), that is the moment to cancel.

Example

Walk through a real wallet-drainer signature request that was used in a documented 2024 attack. The site presents what looks like a 'wallet verification' request. The wallet shows: Type: Permit. Owner: <user's address>. Spender: 0x4Fb9...c3D1 (a recently-created contract with no Etherscan label). Value: 115792089237316195423570985008687907853269984665640564039457584007913129639935 (2^256 - 1, i.e., unlimited). Deadline: 4102444800 (year 2100, 75+ years away). Token: USDC. In plain English: 'I authorise the unknown spender to move unlimited USDC from my wallet for the next 75 years.' Signing this would let the spender call `permit()` on the USDC contract immediately and drain every USDC the user holds. The decoded fields told the user exactly what was happening; the user just had to read them.

Common mistakes

  • Signing without expanding the decoded view. The wallet has the data; you just have to look at it.
  • Trusting 'wallet verification' framing. Legitimate sites don't need you to sign Permit messages to 'verify' anything — verification is a read operation, not a signed write.
  • Approving Permit2 to spend a token in a small amount, then thinking that limit will hold forever. Permit2 lets the contract spend any token you've ever approved, via signature — the on-chain approval limit doesn't apply to the off-chain signature flow.
  • Treating personal_sign messages as harmless because they 'can't move tokens.' They can authenticate you to malicious sites that then escalate.
  • Forgetting to revoke approvals. Use revoke.cash weekly on wallets that interact with DeFi; every approval is a permanent attack surface until revoked.

Check your understanding

A site asks you to sign an EIP-712 message. You expand the decoded view and see: Type=Permit, Owner=your address, Spender=an unfamiliar address, Value=2^256-1, Deadline=year 2100, Token=USDC. What is the correct action?

Key terms covered

Sources & further reading

We prioritise primary sources. Where a topic moves quickly (regulation, security incidents), we re-check sources on the cadence shown by the page's "Next review" date.

Go deeper