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.
Best Answer
It's common for dApps that interact with tokens to specify the maximum
uint256
value as allowance (2^256 - 1 or0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
), in which case you only need to run it once basically. The advantage is that the user won't have to constantly send two transactions, but the disadvantage is that there could be some kind of vulnerability in your contract, allowing someone to transfer all user's tokens. It's a trade-off between user exprience and security.