Approve and transferFrom in the same tx

Hi,
I’m trying to write a simple function for a contract which is supposed to approve and transferFrom msg.sender some ERC20 tokens in the contract itself, in a single tx.

Ideally (this code is NOT working) I would do:

function testFoo(address _token, uint256 _amount) public {
  // get a handle for the ERC20 contract
  IERC20 underlying = IERC20(_token);
  // approve the transfer to this contract
  underlying.approve(address(this), _amount);
  // transfer to this contract
  underlying.transferFrom(msg.sender, address(this), _amount);

  // do other stuff
}

but the first approve is obviously called with msg.sender equal to the contract address.
What’s the correct way to approve and transferFrom in a single tx? Should I use delegateCall on the first approve? Other ideas?

Thank you

2 Likes

Probably delegateCall is not the correct answer given that it would modify MY contract storage rather than the ERC20 token’s one.

2 Likes

The fungible token needs an approve and call mechanism to support doing this in a single transaction. Otherwise users will require two transactions.

If you are developing the fungible token then I suggest having a look at ERC777 to see if this meets your needs. (I haven’t used ERC777 in anger yet, I have only deployed to a testnet). I have previously used other approve and call mechanisms and believe it is essential for a good user experience.

As part of OpenZeppelin 2.3 there is an implementation of ERC777, though as per the release notes for RC3 it has not been audited yet.

ERC777

The long awaited sequel to ERC20 is here. The EIP is almost finalized, and OpenZeppelin has an implementation of it. Please note that this code has not been audited yet . An audit will be performed soon, but for now we need you all to look at it and review it from top to bottom . The main source file is here at ERC777.sol :new::sparkles:. Anything you see, drop us a line in the forum or via email at security@openzeppelin.org. Letting us know that you’ve looked at it and found nothing is also valuable!

3 Likes

Thank you @abcoathup , unfortunately I’m interacting with a third party token and have no control over it, so I suppose there is no way to do it, right?

2 Likes

@bugduino Not that I am aware of unfortunately.

I would check to see if the third party token has implemented any mechanism for approve and call that you can use.

Otherwise you are asking users to approve (ideally to cover multiple actions on your contract) and then call in two separate transactions.

3 Likes

You’re correct that delegateCall wouldn’t work.

The only way I can think of to approve and transferFrom in a single transaction is if the token holder is a contract itself. Then it can have a function that first approves and then calls a function on another contract that triggers transferFrom.

@bugduino Can you tell us why you want to do this in a single transaction? Perhaps we can find another solution to the same problem. Is it to have better UX, to spend less gas, or something else?

3 Likes

Token holders are actually EOA in the use case that I have in mind.
It’s definetly to have a better UX and to not require users to create 2 different txs.

I asked the same question on a popular Discord server for solidity devs and and some folks pointed me to a trick recently used by EXEDAO. Basically a user creates a tx which would then create my contract, execute stuff and then the contract is selfdestructed at the end of the constructor, how does it sounds?

3 Likes

I assume this is the EXEdao that you were talking about?

I wonder what the gas cost is like for this sort of mechanism.

It would be great if you could introduce yourself and tell the community a bit more about your project:

3 Likes

Yes this is what I was referring for EXEDAO.

Sure I’ll do it!

3 Likes

Regarding the EXEDAO mechanism I still need to dig a little bit deeper, have no idea about the gas used, but at the end the contract would be destroyed so one should also get the gas refund I suppose.

3 Likes

I am not sure how creating a contract, executing and then destroying the contracts allows for getting around the two transaction requirement for using ERC20 in a contract but look forward to hearing what you find out.

It would be great if you can update the community with what you find. :smiley:

2 Likes

What I understood is that for interacting with the dapp the user would create a single tx which will create a contract (so msg.sender is the user) and in the constructor he can approve, transfer, do other stuff and selfdestruct at the end.

2 Likes

You can run arbitrary EVM code in the init code of a contract deploy. Unfortunately, since calls originating from that contract would have a different msg.sender than the EOA and ERC20 contracts check msg.sender as opposed to tx.origin, you would need to do a one time approval of some address. This could be the address of some proxy contract, or a deploy address predefined by CREATE2. I might have some more ideas after I have coffee.

3 Likes

Thank you @charles-cooper

that’s true, you are right

2 Likes

Moved to #support category

Hi @bugduino have you found a resolution to this?

1 Like

Unfortunately no, I mean the only way seems to have an approveAndCall or similar on the token side

1 Like

@bugduino That is what I thought.

You may need to handle explaining to the user on the UX side that two transactions are required rather than being able to deal with it on the smart contract side.

1 Like