Lvl 13 (Gatekeeper One) Question

This is re ‘Gatekeeper One’ challenge on Ethernaut: https://ethernaut.openzeppelin.com/level/0x9b261b23cE149422DE75907C6ac0C30cEc4e652A

The enter function has a modifier that requires gasleft to be a multiple of 8191 at that point:

  modifier gateTwo() {
    require(gasleft().mod(8191) == 0);
    _;
  }

The sample solution loops through a range of likely gas values and uses those as an argument to call.gas:

    bytes memory encodedParams = abi.encodeWithSignature(("enter(bytes8)"),
      key
    );

    // gas offset usually comes in around 210, give a buffer of 60 on each side
    for (uint256 i = 0; i < 120; i++) {
      (bool result, bytes memory data) = address(GatekeeperOneContractAddress).call.gas(
          i + 150 + 8191 * 3
        )(
          encodedParams
        );
      if(result)
        {
        break;
      }
    }
  }

Now, that works. But if I try to call enter using a different syntax:

GatekeeperOne gatekeeper = GatekeeperOne(GatekeeperOneContractAddress);

for (uint256 i = 0; i < 120; i++) {
      bool result = gatekeeper.enter{gas:i + 150 + 8191 * 3}(key);
      if(result)
        {
        break;
      }
    }

It fails. Meaning the execution is reverted because (I suppose) one of the requirements is not passed. How is this way of calling different? I am specifying the same amount of gas, am I not?

1 Like

Nvm, figured it out. It’s because the raw call does not propagate the reverts that occur on any iteration that does not pass the required gas value. (Actually that’s what the comment in the proposed solution says. I was just not paying attention to it.)

1 Like

Hi @sialisalderfly,

Glad you were able to resolve.

FYI, OpenZeppelin are hiring security researchers: https://openzeppelin.com/jobs/opening/?gh_jid=4254142003