Query regarding multicall() fucntion in MulticallUpgradeable.sol

In the below function in MulticallUpgradeable.sol I just wanted to verify if a function call which requires the use of msg.value can be called via multicall as multicall itself is non payable.

    function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            results[i] = _functionDelegateCall(address(this), data[i]);
        return results;

TLDR: No, it wont work as the EVM wont let you pass a value to a non-payable function (multicall here).

Details: From what I understand multicall is used to call several function in a single function call on a contract by calling this function which will delegate the calls to itself. This has the advantage of providing the multiple function calls with atomicity.

Given that the base multicall is not payable, you wouldn't be able to call it and pass a msg.value. You can't override it and make it payable either, because from the solidity docs:

The mutability may be changed to a more strict one following the order: nonpayable can be overridden by view and pure . view can be overridden by pure . payable is an exception and cannot be changed to any other mutability.

If you wonder why the base multicall itself isn't payable, imagine that you had a defi pool which allowed you to deposit ether collateral by calling deposit(uint256 amount). Now imagine this contract inherits Multicall. If you call multicall on this pool with a msg.value of 1 ether to deposit 1 ether several times, the logic of depositing would be executed several times but the contract would only have received 1 ether.

I tested it with Foundry on my side:

  • I can't call the multicall function with a msg.value
  • I can't override the multicall function with a payable modifier
  • If I redefine a function multicall2 to be payable, then it sorta works but it doesn't make much sense, allowing me to call payable functions multiple times without giving the ether multiple times

I see, yes this makes a lot of sense, this is a great explanation, personally I never even thought of the possibility that this could be overridden, the fact that it cant be is certainly something I wasn't aware of, thanks for such a detailed explanation.