fallback과 receive 함수
지금까지는 deposit 같은 이름 있는 payable 함수를 호출해 Ether 를 보냈습니다. 그런데
이더리움에서는 함수를 전혀 지정하지 않고 컨트랙트 주소로 Ether 만 덜렁 보내는 경우도 있습니다.
예를 들어 사용자가 지갑에서 컨트랙트 주소로 그냥 송금하는 상황입니다. 이때 자동으로 실행되는 두
가지 특수 함수가 receive 와 fallback 입니다. 둘은 직접 호출하는 것이 아니라,
특정 조건이 충족되면 EVM 이 알아서 불러 주는 일종의 "기본 대응 함수"입니다.
receive 함수
receive 는 순수하게 Ether 만 전송되고 calldata(함께 보내는 데이터)가 비어 있을 때 실행됩니다.
반드시 external payable 이어야 하며, 다른 함수와 달리 function 키워드 없이 이름 뒤에 괄호만
옵니다. 또한 인자도 반환값도 가질 수 없습니다.
fallback 함수
fallback 은 두 가지 상황에서 실행됩니다. (1) 호출한 데이터에 일치하는 함수가 없을 때, 또는
(2) Ether 가 들어왔는데 receive 함수가 정의되어 있지 않을 때입니다. fallback 역시 function
키워드 없이 선언하며, Ether 를 받으려면 payable 을 붙여야 합니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Receiver {
event Received(address sender, uint256 amount);
event FallbackCalled(address sender, uint256 amount);
// Ether 만 보내고 데이터가 없을 때 실행
receive() external payable {
emit Received(msg.sender, msg.value);
}
// 일치하는 함수가 없거나, receive 가 없을 때 실행
fallback() external payable {
emit FallbackCalled(msg.sender, msg.value);
}
}어떤 것이 실행되는가?
둘 중 무엇이 실행될지는 calldata 가 비어 있는가와 receive 가 존재하는가로 결정됩니다.
| 상황 | 실행되는 함수 |
|---|---|
| calldata 가 비어 있음 + receive 존재 | receive |
| calldata 가 비어 있음 + receive 없음 | fallback |
| calldata 가 있고 일치 함수 없음 | fallback |
receive 가 없으면 빈 calldata 의 Ether 전송도 fallback 으로 넘어갑니다. 둘 다 없으면 그 Ether
전송은 실패(revert)합니다.
receive 와 fallback 은 transfer/send 로 단 2300 gas 한도에서 호출될 수도 있습니다.
따라서 이 두 함수 안에서는 상태 변경이 많은 무거운 로직을 피하고, 이벤트 기록 정도의 가벼운 작업만
두는 것이 안전합니다.
Ether 를 자유롭게 받고 싶다면 receive 를, 예상치 못한 호출까지 대비하려면 fallback 을 함께
정의해 두면 됩니다.