Lets say I'm trying to write some kind of exchange or escrow smart contract that handles transferring tokens for users.

I see that ERC20 tokens implement the approve function something like below:

    function approve(address delegate, uint256 numTokens) public override returns (bool) {

        allowed[msg.sender][delegate] = numTokens;

        emit Approval(msg.sender, delegate, numTokens);

        return true;


With the main point that approved account is msg.sender NOT tx.origin. So if I am writing a separate smart contract that tries to call the approve function of this ERC20 token:

function handleApproval(IERC20 token, uint256 numTokens) public override returns(bool){
    IERC20.approve(address(this), numTokens);

This would not work as intended since it would only be doing allowed[CONTRACT_ADDRESS][CONTRACT_ADDRESS] = numTokens, since the sender of the message is my smart contract.

My question is what is the proper pattern for exchanges/escrows to get users to approve the smart contract for handling transfers? Are users supposed to have to call the approve() function of the ERC20 contract directly themselves?


2 Answers 2


Yes, the users have to call the approve function "themselves". (Otherwise, you would just be able to approve anything you want :) )

But they don't have to do that manually - usually how it works is that your front end website will issue for the user two transactions to sign - one for approving the ERC20, and one for executing your smart contract function.

  • thanks for confirming this. how come i havent noticed this before as an end-user? for example if im a user of uniswap at what point do they make me call the approve() function? And is it customary to set the approval amount to max? (ie 2^256-1)
    – tsuigeo
    Commented Oct 25, 2021 at 12:54
  • You're welcome. For example at Uniswap, when you do a swap, you should be asked to sign 2 MetaMask transactions - one for approval and one for executing the swap. Also, if I recall correctly, when you add liquidity you will be asked to sign 3 transactions - approve one token, approve the other, and then add them to the LP. I think from now you'll start noticing it whenever you interact with contracts :) No, setting the approval to max is not customary from my experience and it's bad practice, because then the app could just "steal" all the user's tokens. Commented Oct 26, 2021 at 6:14

To answer your question in your comment, the most common pattern is to first check the user's allowance and ask the user to approve the token if it is below a certain threshold. You will always, always be required to approve a token that a contract is trying to spend for you. I'm not sure what the exact numbers that are used are, and I'm sure they vary, but it would look like something very similar to this in Web3:

if (allowance <= 2**50) { // 2**50 or any other amount you think is low enough!
    await token.methods
                (1e50).toLocaleString("fullwide", { useGrouping: false }) // 1e50 or whatever allowance you want to set
        .send({ from: accounts[0] })

To answer your second question, yes, it is very common to set the user's token allowance to the max it can possibly be. You can see this for yourself if you dive into your PancakeSwap allowance or any other dApp.

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.