I have a contract that uses the ERC20 token contract for making payments. Now, in the ERC20 token contract we have the following implementation of approve function:

function approve(address _spender, uint256 _value) public returns (bool) {
    allowed[msg.sender][_spender] = _value;
    emit Approval(msg.sender, _spender, _value);
    return true;

The problem is that the msg.sender within the approve() function of ERC20 holds the address of the service contract (the contract that uses the ERC20 contract for making payments and not the address of the user who wants to make the payment). So, how do I let the approve function know the address of the user who wants to make the payment ?

The work-around for this is to call the approve function directly instead of via
another contract. Is this the way to do it ?


If you are using someone else's ERC20 token, then you will not be able to do this. The approve function in a standard ERC20 contract is made to use the msg.sender which, as you have noticed, will take the form of the calling address (like a contract), rather than the root address which initiated a transaction.

This is actually a way to prevent from attacks against the token. Imagine you could build a contract which a user calls, that triggers another ERC20 token and make some sort of change on behalf of the user. You could then use this behavior in a malicious function, where you trick the user to call your contract function, and then you steal all of their coins.

Because the approve function is written the way it is, the only way a user could have their tokens manipulated with, is through explicit action by that user directly to the token contract that they know about.

The approve function is actually made exactly for your kind of scenario, where the user can "approve" your contract address to spend some amount of tokens, and then you can build functions which can call transferFrom() to then interact with those tokens.

Now, you can build your own ERC20 token, which would allow for this exploit by replacing msg.sender with tx.origin which is always the root caller of the transactions (always an EOA), but as I mentioned above, this would leave you vulnerable to other contracts exploiting your choice.

I hope this helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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