이더넛 레벨1 풀기
01. Fallback
목표
1. 컨트랙트의 소유권을 가져온다. (owner 변경)
2. 컨트랙트의 잔고를 0으로 만든다.
Full code
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import '@openzeppelin/contracts/math/SafeMath.sol';
contract Fallback {
using SafeMath for uint256;
mapping(address => uint) public contributions;
address payable public owner;
constructor() public {
owner = msg.sender;
contributions[msg.sender] = 1000 * (1 ether);
}
modifier onlyOwner {
require(
msg.sender == owner,
"caller is not the owner"
);
_;
}
function contribute() public payable {
require(msg.value < 0.001 ether);
contributions[msg.sender] += msg.value;
if(contributions[msg.sender] > contributions[owner]) {
owner = msg.sender;
}
}
function getContribution() public view returns (uint) {
return contributions[msg.sender];
}
function withdraw() public onlyOwner {
owner.transfer(address(this).balance);
}
receive() external payable {
require(msg.value > 0 && contributions[msg.sender] > 0);
owner = msg.sender;
}
}
전략
function withdraw() public onlyOwner {
owner.transfer(address(this).balance);
}
최종 목표의 출금을 하려면
modfier onlyOwner 조건을 만족해야합니다.
modifier onlyOwner {
require(
msg.sender == owner,
"caller is not the owner"
);
_;
}
modifier onlyOwner는
함수 호출자의 주소가 owner에 대입된 주소인지 확인합니다.
- owner는 누구?
constructor() public {
owner = msg.sender;
contributions[msg.sender] = 1000 * (1 ether);
}
constructor에서
owner는 스마트컨트랙트 배포자의 주소임을 알 수 있습니다.
- owner가 되어보자.
function contribute() public payable {
require(msg.value < 0.001 ether);
contributions[msg.sender] += msg.value;
if(contributions[msg.sender] > contributions[owner]) {
owner = msg.sender;
}
}
receive() external payable {
require(msg.value > 0 && contributions[msg.sender] > 0);
owner = msg.sender;
}
}
owner에 대입한 주소를 바꾸는 방법은 위 두가지 입니다.
첫번째에 contribute 함수에서 owner가 되기 위해서는
contributions 값이 1000 ether가 되야 합니다.
contribute 함수를 호출하기 위해서는
msg.value (보내는 ether)이 0.001 ether 미만이 되야 합니다.
contributions 값을 1000 ether가 넘게 만드려면
백만번넘게 contribute 함수를 호출해야 합니다.
이 방법은 어려워 보입니다.
두번째는 전송하는 ether가 0 보다 크면서
contribute 함수를 통해 보낸 ether가 0 보다 크면
owner가 될 수 있습니다.
두번째 방법으로 owner가 되보겠습니다.
두번째 방법으로 시도
컨트랙트 배포시 컨스트럭터에 의해
owner에는 0x9cB~ 주소가 대입되어 있습니다.
await contract.contribute.sendTransaction({value: toWei("0.00001")})
함수 contribute는 payable이기 때문에 이더를 보낼 수 있습니다.
contribute의 require 조건을 통과하기 위해
0.001 ether보다 낮게 설정해서
contribute를 호출하여 0.00001 ether를 컨트랙트로 보냈습니다.
이제
contributions[msg.sender]는 0.00001 ether가 되고 0보다 커졌습니다.
receive() external payable {
require(msg.value > 0 && contributions[msg.sender] > 0);
owner = msg.sender;
}
}
이제 receive를 통해 보내는 이더가 0보다 크면
owner 주소를 내 주소로 바꿀 수 있습니다.
await contract.sendTransaction({value: toWei("0.00001")})
위 코드를 실행하면 스마트컨트랙트의
receive를 통해 이더를 전송할 수 있습니다.
위 코드가 실행하고 나서
owner를 확인하니 owner가 내 주소로 변경 되었습니다.
await contract.withdraw()
이제 즐거운 인출시간.
함수 withdraw를 호출하면
이제 owner가 msg.sender 주소(=내 주소)로
변경되었기 때문에 정상적으로 인출이 성공합니다.
인출후에 스마트컨트랙트 잔고를 확인하면
0이 되었음을 알 수 있습니다.
정답을 제출하면 레벨1 완료~!
'블록체인' 카테고리의 다른 글
[이더넛] 레벨3 'Coin Flip' 풀기 (0) | 2021.08.10 |
---|---|
이더넛 레벨2 풀기 (0) | 2021.08.10 |
이더넛 시작 & 레벨 0 (0) | 2021.08.10 |
이더스캔 만들기 (0) | 2021.08.06 |
블록체인에 절대 지울 수 없는 메시지 남기기. (0) | 2021.08.05 |