> For the complete documentation index, see [llms.txt](https://whs3-doge5k.gitbook.io/smartcontract-security-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://whs3-doge5k.gitbook.io/smartcontract-security-docs/basics/2./undefined-2/fallback-receive.md).

# fallback / receive 함수

### Fallback

fallback 함수는 "**예상하지 못한 호출에 대응하기 위한 특수 함수**"이다. 주로 정의되지 않은 함수 호출을 처리하거나, 외부 호출에 대한 예외 상황을 안전하게 대응하기 위해 작성된다. Solidity 0.5.0 버전 이전에는 fallback 함수의 형태는 function()과 같았고, 0.6.0 이후 버전부터 현재와 같은 fallback 함수의 형태가 만들어졌다.

```solidity
// solidity < 0.5.0
function() external payable {}

// solidity >= 0.6.0
fallback() external payable {}
```

0.6.0 이전 solidity 버전의 fallback 함수는 **정의되지 않은 함수 호출**과 **ETH 수신** 두 가지를 모두 처리해야했기 때문에, 하나의 명령어가 두 역할을 하는 상황이 존재하였다. 따라서 0.6.0 버전에서는 **ETH 수신** 기능을 분리한 receive 함수가 도입되었다. fallback 함수의 역할은 기존과 동일하지만, receive 함수가 존재할 경우에는 역할이 "정의되지 않은 함수 호출"을 처리하는 것으로 축소된다.

fallback 함수는 msg.data가 존재하지만 이와 일치하는 함수가 존재하지 않을 경우 실행된다.

* msg.data : 함수 호출 전체에 대한 바이트 데이터(함수  selector + 인자들)

#### **예시**

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Example {
    address owner;
    constructor() {
        owner = msg.sender;
    }
    
    function audit() public pure returns (string) {
        return "hello";
    }
    
    fallback() external payable {
        if (msg.sender != owner) {
            revert("unsupported");
        }
        // code
    }
}
```

외부 지갑이나 컨트랙트가 Example 컨트랙트의 함수를 호출할 때 "audit()"를 호출하지 않고 다른 함수명을 호출할 경우 fallback 함수가 동작하게 된다.

위의 코드에서는 컨트랙트 호출 주소가 owner가 아닐 경우 revert 되는 핸들링이 추가된 형태이다.

***

### Receive

solidity 0.6.0 버전 이후 fallback 함수 기능 중 **ETH 수신 기능**을 처리하기 위해 도입되었다. msg.data가 존재하지 않지만, ETH가 수신되었을 경우에 receive 함수가 호출된다.

#### **예시**

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Example {
   function getBalance() public view returns (uint) {
        return address(this).balance;
    }

    receive() external payable {
        // 이더를 수신
    }
}

```

외부에서 함수를 호출할 때, 함수 정보를 전달하지 않고 ETH만 송신하였을 경우에 receive 함수가 실행되고 컨트랙트는 ETH를 전송받을 수 있다.

### **정리**

<figure><img src="https://2462457462-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLf9vwRuaws92ULgGvzTi%2Fuploads%2FbPDr3pFgEr58jNPHmszM%2Fimage.png?alt=media&amp;token=a1b55805-392c-4ea0-9135-91bcd3693bcb" alt=""><figcaption></figcaption></figure>

<table><thead><tr><th width="135.8359375">함수 종류</th><th width="241.46875">트리거 조건</th><th>특징</th></tr></thead><tbody><tr><td><code>receive()</code></td><td><strong>이더만 전송</strong>되고 <code>data</code>가 <strong>없을 때</strong></td><td><code>payable</code>이어야 함. 간단한 이더 수신용</td></tr><tr><td><code>fallback()</code></td><td>이더와 함께 <strong>데이터가 있거나</strong>, 함수 이름이 잘못됐을 때</td><td><code>payable</code> 또는 <code>non-payable</code> 가능. 함수 시그니처가 없거나 잘못된 경우 실행됨</td></tr></tbody></table>

{% hint style="info" %}
Q. fallback을 사용하여 핸들링을 하지 않고 그냥 revert 시켜도 되지 않나요?

간단한 컨트랙트라면 fallback 함수를 굳이 구현하지 않아도 대부분의 경우 문제가 되지 않습니다. 하지만 실제 서비스나 복잡한 컨트랙트를 개발할 때는 다음과 같은 이유로 fallback을 활용하는 것이 안전합니다.

* 예기치 않은 함수 호출 - 보안, 디버깅
* 보안적인 고려 - 의도하지 않은 접근 제어
* Proxy(업그레이드) - 코드 변경 없이 새로운 기능 업데이트
  {% endhint %}
