To transfer a token from a wallet to my contract I need to do both:

  1. token.connect(signer).approve(contract.address, amount) (frontend)
  2. IERC20(token).transferFrom(msg.sender, address(this), amount) (backend)

Both prompt Metamask to ask the user to "accept".

From a user experience perspective, it's annoying to have to click "accept" twice.

But if I skip the first step, there is an error.

ERC20: insufficient allowance

Am I missing something that would allow only asking the user to click "accept" once?

1 Answer 1


Yes, it is annoying, but every major app working with ERC-20 has the exact same UI. Why?

Because of fundamental limitations in ERC-20 design, contracts must pull the ERC-20, otherwise they cannot know who sent the ERC-20, and therefore cannot credit you with them.

However, they need to be approved before they can be allowed to pull.

The options to get around this are:

  1. Use ERC-777 and utilize hooks
  2. Approve an infinite amount once at the start
  3. Use ETH instead of ERC-20, as ETH can trigger the fallback/receive function (which ERC-20 cannot)

It's probably the single biggest point of friction for the ERC-20 token spec. The next biggest is sending tokens directly (pushing tokens to a contract, instead of letting them pull tokens). If you do that, you've basically burned the tokens.

So, assuming we're working with USDC, to pick a random ERC-20:

what you have to do:

  1. USER tells USDC contract that your contract is approved to withdraw x tokens.
  2. USER tells your contract to go withdraw the USDC from USER account.
  3. All good, because your contract has permission.

And what you're trying to do:

  1. USER tells your contract to go withdraw the USDC from USER account.
  2. USDC contract rejects, because your contract doesn't have permission to touch USER funds.

If USDC validated by checking tx.origin instead of msg.sender, this would work! It would also be a huge security flaw, and many tokens have been lost by people trying to take that shortcut.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.