ERC-8009: Proxy Clear Signing

The new standards proposal aims to solve the vulnerability of blind signing for a large fraction of use cases, when a user must sign a transaction sent to a smart contract unknown to their hardware wallet. The hardware wallet will be able to display a list of constraints consisting of ETH and ERC-20 token balances or balance changes after the execution of the transaction, with a guarantee that if these constraints are not met, the transaction will revert, only imposing a gas cost on the user.

Abstract

Introduce a singleton, stateless contract that proxies arbitrary smart‑contract calls and enforces user‑supplied outcome constraints. The proxy supports absolute post‑balance thresholds and balance‑difference (delta) checks over native ETH and ERC‑20 balances. Calls that violate the declared constraints MUST revert.

Motivation

Current hardware wallets struggle to present meaningful transaction information when interacting with unknown or newly deployed smart contracts. Without prior knowledge of a contract’s ABI or address, these devices can only display raw hexadecimal calldata - an unreadable and unsafe experience for most users. This practice, known as blind signing, leaves users vulnerable to unintentionally approving malicious or incorrect transactions. This vulnerability has already been exploited in high-value attacks.

Instead of parsing transaction calldata, the proposed approach focuses on verifying expected balance differences after execution. This proposal introduces an alternative path to clear signing - defined here as the ability for users to verify the outcome of a transaction before signing, without requiring ABI knowledge. By routing calls through a singleton proxy contract that enforces these expectations on-chain, hardware wallets can reliably display the “balance after transaction” values to the user, taken from the smart-contract parameters. This enables a permissionless, scalable, and understandable transaction confirmation experience, even for unknown contracts.

5 Likes

The PR containing the ERC is here. An ERC number is yet to be assigned.

1 Like

Yes, blind signing is bad, and we should address it.

Yes, “balance after transaction” check is a good solution, but it’s still blind signing, because the function args require comprehensive display from wallets, especially with hard wallets.

I believe this contract should be callled “router” instead of “proxy”. Because it holds token approval and spent them the same way DeFi peripheral router contracts do. The exactly same idea is proposed, implemented and audited 3 years ago: ERC-6120: Universal Token Router.

But to completely remove the blind signing UX, we need something like this: ERC-TBD: Intent-Based State Transition.

After reviewing ERC-6120, we came to the conclusion that it is not the exact same thing. In particular, our proposal does not require the deployment of a routing contract for each smart contract, but only one proxy contract. Also, it has been designed with hardware wallets in mind to be able to display constraints in a user readable fashion. In fact, supporting firmware development for several hardware wallets is in progress.

Same, there’s only 1 single ERC-6120 contract is deployed for all applications.

It’s a long shot to even think that some hardware wallets will make changes to “parse a part of calldata to display something” (with an ABI or a common pattern). If that’s posible, 6120 already have that, wallets can just parse the calldata to display the balance outputs.

Meanwhile, the Intent-based State Transition can display readable intents in clear text on hardware wallets using ̀eth_sigǹ (or 712) that already being standard for every wallets.

The ERC-6120 contract has several issues that make it unusable for the balance-based clear signing on the hardware wallets.

The first issue is that ERC-6120 only allows to check for positive changes in balances. So, if I want to make a constraint saying “I should not lose more than 1 eth as the result of this transaction”, we cannot use ERC-6120 for that, neither can we use it for a constraint saying “my balance after the transaction should be X USDC”

Yes, ERC-6120 is one for all applications. But the applications have to either implement “NotToken” marker, or 0x61206120 ERC-165 marker.

If they don’t, one would need to write a custom helper contract like the one you showed in your proposal (uniswap v2/v3)

Another thing to mention is that ERC-6120 requires Cancun, so it is not that scalable (not all EVM networks will be supported).

The ERC-8009 however, is less generic, but that’s also a bonus as it will be more gas-efficient and has potential for even better gas-efficiency than the reference implementation.

Do users need to approve their tokens to the Proxy contract?

They don’t need, it is optional. They can.

Here’s a critical vulnerability for you:

When the user approve tokens to the Proxy, anyone can steal all the tokens by sending transactions like this:

proxy.proxyCall(
  [...],
  [...],
  tokenAddress,
  abi.encodeFunction("transferFrom", ...),
  [...]
)
1 Like

Thank you, I see. I will make edits to the contract

Whatever balance you don’t check is the one that will be drained.

We expect hardware wallets to display the balance constraint parameters on their screens. So if a certain token balance delta / value is not displayed on the screen, the person holding the hardware wallet is expected to discard the transaction.

For comparison, there was once a smart contract that only made sure that its weth balance increased at the end of a transaction and was otherwise permissionless. But this didn’t check approvals and so it was drained.

So if a certain token balance delta / value is not displayed on the screen, the person holding the hardware wallet is expected to discard the transaction.

The simulation might show some expected behaviors, but the transaction might behave much differently during execution. For example I once had a honeypot that would behave differently according to COINBASE to take advantage of some defaults that were in use by some frontrunning bots, though many environmental parameters can be used for this purpose. So the user would still approve the transaction, and it would pass the checks, but it can take additional actions that are not checked, for example stealing unrelated NFTs or approving someone to steal your tokens.

I don’t think this problem can be solved in the general case because it reduces to the halting problem.

How do these things happen? Is it because the arbitrary call from the generalized “Proxy” contract?

They happen because balance checks are insufficient to verify safe execution, and because faith in those checks creates a false sense of security.