이번 포스트에서는 계약을 조금 더 전문적으로 만들기이다. 비용을 더 효율적으로 쓰기 위함이다.
uint256 public minimumUsd= 50 * 1e18;
은 계약이 배포 되면 고정되고 변하지 않는다. constant
키워드를 통해 이 변수를 조금 더 효율적으로 만든다.
uint256 public constant MINIMUM_USD= 50 * 1e18;
키워드를 추가하면 변수는 저장공간을 차지하지 않고 읽기 쉬워진다. 규칙이 있는데 대문자와 _
으로 작성한다.
address public immutable i_owner;
상태변수는 immutable
로 표시할수 있는데 읽기 전용이 되지만 constructor
에서 할당할 수 있다. i_
로 시작해야한다.
0.8.4버전 이상부터 사용가능하다. 계약외부에 error를 정의해준다.
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./PriceConverter.sol";
error NotOwner();
contract FundMe{
...
...
modifier onlyOwner{
// require(msg.sender == i_owner, "You are not the owner!");
if(msg.sender != i_owner){ revert NotOwner(); }
_;
}
계약에 fund
함수를 이용하지 않고 돈을 보낸다면 누가 얼마나 보냈는지 추적할 수 없다.
FallbackExample.sol
을 만들어준다.
receive() external payable{
result= 1;
}
receive
함수는 이더를 받을 때 디폴트 함수로 실행된다.
컴파일후 배포하게 되면 아래쪽에
입력필드가 있는 CALLDATA
과 Transact
버튼이 있는 Low level interactions
을 볼 수 있다. value에 금액을 넣고 트랜잭션을 누르면 result값이 0에서 1로 바뀐다.
CALLDATA
을 공백으로 나두지 않으면 어떻게 될까?
데이터를 보냈을때 Receive
를 이용하지 않아 알아서 함수를 찾아 준다. 0x00과 일치하지 않아 fallback함수를 찾는다. 아직 정의 해주지 않아서 오류를 반환.
fallback() external payable{
result= 2;
}
이제 오류 대신 성공적으로 전달된다.
유효한 함수 없이 계약이 호출됐지만 solidity에서 이것을 알아차리고 fallback
함수를 실행시키고 결과를 반환한다.
...
modifier onlyOwner{
// require(msg.sender == i_owner, "You are not the owner!");
if(msg.sender != i_owner){ revert NotOwner(); }
_;
}
fallback() external payable {
fund();
}
receive() external payable {
fund();
}
fallback()
과 receive()
를 계약에 추가한다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import "./PriceConverter.sol";
error NotOwner();
contract FundMe{
using PriceConverter for uint256;
uint256 public constant MINIMUM_USD = 50 * 1e18;
address[] public funders;
mapping(address => uint256) public addressToAmountFunded;
address public immutable i_owner;
constructor(){
i_owner = msg.sender;
}
function fund() public payable{
require(msg.value.getConversionRate() >= MINIMUM_USD, "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 == i_owner, "Sender is not owner!");
if(msg.sender != i_owner) { revert NotOwner();}
_;
}
receive() external payable{
fund();
}
fallback() external payable{
fund();
}
}
여기까지 기초적인 solidity문법을 이용해 FundMe 스마트 컨트렉트를 만들어 보았습니다.
이 시리즈는 freeCodeCamp.org의 강의를 들으면서 공부한 내용을 정리하기 위해 작성했습니다.