payable(msg.sender).transfer(address(this).balance)
msg.sender
는 address
의 type이다. 앞에 payable을 추가하는 것은 이전에 int와 uint로 했던 것처럼 형변환하는 것이다. this
는 전체계약인 FundMe.sol을 의미한다. 코스트가 2300gas로 제한되고 더 많은 코스트가 필요하면 에러를 반환한다.
bool sendSuccess= payable(msg.sender).send(address(this).balance);
require(sendSuccess, "Couldn't send the funds");
마찬가지로 2300gas로 제한되지만 오류 대신 bool을 반환. 자체적으로 반환하지 않기 때문에 위와같이 작성.
(bool callSuccess, bytes memory dataReturned)= payable(msg.sender).call{value: address(this).balance}("");
.balance
뒤의 괄호는 비어 있다. 일반적으로 계약에서 함수를 호출할 때 함수 정보나 호출하려는 함수에 대한 정보를 넣는다. 실제로 함수를 호출하고 싶지 않으므로 이 함수를 비워둔다. 비워 둔다는 것을 알리기 위해 ("")
을 이용한다.
call.{value: address(this).balance}
은 Remix에 지불하려는 금액을 입력하는 Value
부분이 있다. 이와 같이 작동하기 위해 this
계약의 주소에 금액을 입력.
2개의 변수를 반환한다. 반환되는 첫 번째 변수는 bool callSuccess이고 두 번째 변수는 dataReturned 바이트이다. 그러나 call메서드로 어떤 함수도 호출하지 않기 때문에 이 두 번째 변수는 필요하지 않다.
(bool callSuccess,)= payable(msg.sender).call{value: address(this).balance}("");
require(callSuccess, "Call failed");
계약을 배포한 사람만 자금을 인출할 수 있도록 하기 위해 constructor
를 사용한다.
constructor(){
owner= msg.sender;
}
owner
주소 변수를 만들고 constructor
에 msg.sender
를 설정한다.
modifier onlyOwner{
require(msg.sender == owner, "You are not the owner!");
_;
}
function withdraw() public onlyOwner {
...
}
사용할 함수의 상태변수 뒤에 modifier
를 입력해준다.
_;
은 조건후에 modifier
가 첨부된 함수의 나머지 코드를 실행하겠다는 의미.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import "./PriceConverter.sol";
contract FundMe{
using PriceConverter for uint256;
uint256 public minimumUsd = 50 * 1e18;
address[] public funders;
mapping(address => uint256) public addressToAmountFunded;
address public owner;
constructor(){
owner = msg.sender;
}
function fund() public payable{
require(msg.value.getConversionRate() >= minimumUsd, "Didn't send enough!"); // 1e18 == 1 * 10 ** 18
funders.push(msg.sender);
addressToAmountFunded[msg.sender] = msg.value;
}
function withdraw() public onlyOwner {
for(uint256 funderIndex = 0; funderIndex < funders.length; funderIndex++){
address funder = funders[funderIndex];
addressToAmountFunded[funder] = 0;
}
funders = new address[](0);
(bool callSuccess,)= payable(msg.sender).call{value: address(this).balance}("");
require(callSuccess, "Call failed");
}
modifier onlyOwner {
require(msg.sender == owner, "Sender is not owner!");
_;
}
}
완성된 코드
컴파일 후 ENVIRONMENT를 injected Provider - Metamask로 바꿔주고 CONTRACT가 FundMe로 맞춰진것을 확인 후 deploy를 눌러주자. 메타마스크에서 확인을 눌러준다.
eth-converter
50USD를 1ETH/USD인 1300으로 나눠준다. 0.0384...이 나오는데 계산하기 쉽게 0.04를 하겠다.
변환기에서 Wei값을 가져와서
Value에 입력후 fund를 해주면 성공적으로 전송된것을 확인할 수 있다.
시도 할때마다 Transaction이 쌓인다.
인출 확인을 위해 계정2로 바꾸어주고
인출을 누르면 성공적으로 오류 메세지를 반환한다. send Transaction을 눌러도 가스를 소비하고 실패할 것이다. 주소를 다시 바꿔주고 인출을 하면 성공이다.
이 시리즈는 freeCodeCamp.org의 강의를 들으면서 공부한 내용을 정리하기 위해 작성했습니다.