0

I was wondering whether the "insufficient gas griefing attack" is possible in cases when the external call is a typed call rather than an inline call with lower level utility functions (i.e. call).

For example, will the gas griefing attack be possible in the following example?

function transferAndRedeem(
      ...
    ) internal returns (uint256) {
        (
            uint256 shares
        ) = getShares(depositTransfers, false);

        require(
            shares <= maxShares
            "Redeem: shares is greater than maxRootsIn"
        );
        ...

        // Default mode is EXTERNAL
        address burnAddress = msg.sender;
        // Transfer token from beanstalk internal to this contract and burn
        if (mode == From.INTERNAL) {
            burnAddress = address(this);
            
            ITokenTreasury(tokenTreasury).transferInternalTokenFrom(
                this,
                msg.sender,
                burnAddress,
                shares,
                To.EXTERNAL
            );
        }
        _burn(burnAddress, shares);
        emit Redeem(...);
        return shares;
    }

Will this line be silently skipped if the gas is insufficient for the execution or will it throw an error?

 ITokenTreasury(tokenTreasury).transferInternalTokenFrom(
                    this,
                    msg.sender,
                    burnAddress,
                    shares,
                    To.EXTERNAL
                );

Or is the gas griefing attack only applicable to low-level external contract calls (e.g., target.call(calldata))?

P.S. I'm particularly interested in this vulnerability in context of Solidity >=0.8.12

1 Answer 1

1

Gas griefing is applicable to all forms of external calls.

Your question isn't that simple. Following the 63/64 rule of EIP-150, if by the time you reach your ITokenTreasury(tokenTreasury).transferInternalTokenFrom you've not consumed more than 63/64ths of your maximum gas, the call will go through and even if it runs Out Of Gas inside, the transaction won't revert.

So it would be a matter of calculating the running cost of your function's external calls. This is probably not feasible if an external call is dynamic.

Hence, you could just "internalize" the possibility of "revert vs griefing" by simply checking for a success condition, after your external call returns:

(bool success, ) = ITokenTreasury(tokenTreasury).transferInternalTokenFrom();
require(success, "External tomfoolery failed");
1
  • Thank you so much for the great explanation!!!
    – Mila A
    Commented Nov 5, 2023 at 15:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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