foundry icon indicating copy to clipboard operation
foundry copied to clipboard

Feat: `mockCall` with actions

Open PraneshASP opened this issue 9 months ago • 2 comments

Component

Forge

Describe the feature you would like

Currently, the mockCall() method can only return values. It would be useful to have a similar method called mockCallWithAction(), which takes in encoded calldata and address as additional parameter. For example, in ERC4626 vault's withdraw() method returns the asset amount as well as performs a transfer call which sends funds to the caller/recipient.

So, instead of just doing:

vm.mockCall(
  address(vault),
  abi.encodeWithSelector(IERC4626.withdraw.selector),
  true
);

We can do something like this:

struct Action {
  address target,
  bytes data
 }
  
bytes memory transferCalldata = abi.encodeWithSelector(IERC20.transfer.selector, receiver, 10e18);

Actions[] memory actions = new Action()[1];

actions.push({target: tokenAddress, data: transferCalldata});

vm.mockCallWithActions(
  address(vault),
  abi.encodeWithSelector(IERC4626.withdraw.selector),
  true,
  actions
);

It would also be nice to include actions the ability to trigger specific cheatcodes like deal(), etc.,

This would be super useful during integration testing. Happy to take this on. Let me know wdyt.

Additional context

No response

PraneshASP avatar May 02 '24 08:05 PraneshASP

bumping this. cc: @mds1 @mattsse

PraneshASP avatar Jun 24 '24 14:06 PraneshASP

For something like this I think you are better off writing a custom mock solidity contract and etching it at the target address. I would be hesitant to implement this feature because it seems there are a wide range of potential side effects and edge cases, and it's not intuitive how everything should behave or work. Some examples:

  • Call parameters: What if I want to send value, or do a delegatecall instead of a call, or specify a gas limit? What if one action reverts? You quickly need to expand that Action struct, and provide lots of overloads if you want good UX
  • What if the mocked call is the same as the action? Revert, or do two separate things on each invocation?
  • If the action calls back into the mocked call, do we still want the mocked value returned? "Yes" isn't representative if the action should have impacted the returned value of the mock, and I'd need to clear mocked calls in between

There are arguments in favor for any answer, but none of them are clearly correct for a vast majority of use cases, meaning the cheatcode behavior will be ambiguous and nonintuitive. Whereas with a custom mock contract you can get the precise behavior you want with no ambiguity :)

mds1 avatar Jun 29 '24 16:06 mds1

Thanks @PraneshASP for the suggestion

Marking as not planned per the comment above

zerosnacks avatar Jul 15 '24 13:07 zerosnacks

Agreed that a custom mock contract is better alternative, thanks for the suggestion @mds1!

PraneshASP avatar Jul 15 '24 13:07 PraneshASP