problem · erc20 approval risks

ERC-20 approval risks

The approval problem.

ERC-20 LSP·7 LSP·6

approve and transferFrom split intent. Wallets can't explain what they're authorizing.

ERC-20 approve(spender, amount)
unbounded phishable split-intent
LSP·7 authorizeOperator(op, amount, data)
scoped revocable LSP6 gated
LUKSO route

If you're dealing with ERC-20 approval risks, the LUKSO route is LSP7 + LSP6. LSP7 operators are still amount-scoped — that's honest, not magic. The shift is that on a Universal Profile, the controller calling authorizeOperator is itself bound by LSP6 permissions. Allowances stop being a forever-promise to a token contract and become a revocable, narrow grant on the account.

Why this breaks

ERC-20 approve sets an allowance. The spender later calls transferFrom whenever it likes, for any amount up to the allowance. The user signs intent once and never sees the executions, so wallets cannot meaningfully explain what they’re authorizing.

Most dapps request max-uint approvals to skip future prompts. That turns every approved spender into a standing risk: if the spender contract is upgraded, exploited, or misconfigured, the allowance is already there.

What people try

Revoke flows

revoke.cash, wallet UIs that list active allowances. Reactive, requires user effort, allowance has already lived on-chain.

EIP-2612 permit

Moves approval from a transaction to a signature. Still blanket authority, still trusts the spender contract not to drain. Cheaper to give, not safer to hold.

Permit2

Signature-based, per-transaction allowances, scoped to a single contract. Helps materially — but only when both sides integrate it.

Approve-and-call wrappers

Adds a custom router contract. Fragments UX across token + router, doesn’t fix the underlying ERC-20 model.

How LSP solves it

LSP7’s authorizeOperator is still amount-scoped — that part is honest. It is not magic protection against every approval risk. The shift is where the policy lives.

On a Universal Profile, the controller calling authorizeOperator is itself bound by LSP6 Key Manager permissions: allowed calls, allowed standards, allowed ERC-725Y data keys, value limits, and revocable per controller. So instead of asking the token contract to police every future transferFrom, the account decides what each app controller may invoke and when.

A session controller can be granted (one tx) and revoked (one tx) without ever touching token-level allowances. That is the meaningful change.

continue at the source