Solidity 문법 - (24) fallback

2023. 6. 4. 17:38BlockChain/Solidity 깨부수기 ( 유투브 강의 )

목차
1. fallback
2. fallback 예제코드

 

1. fallback

 

 

솔리디티에는 fallback 이라는 함수가 존재한다.

 

fallback은 아래의 뜻을 가지고 있다.


fallback[ˈfɔːlbæk]명사

  • 1.후퇴(retreat)
  • 2.의지(가 되는 것), 여축(餘蓄), 예비물[금]; [컴퓨터] (고장시의) 대체 시스템

우리가 사용할 때는 대체 시스템이라는 뜻으로 사용을 하게된다.

 

fallback의 특징

 

  1. 익명 함수이기에 함수의 이름을 짓지 않아도 된다.
  2. 외부에서 사용하기 때문에 external을 붙여야한다.
  3. 이더를 받을 수 있기 때문에 payable을 붙여야한다.

 

fallback의 용도

 

  1. 스마트 컨트랙트가 이더를 받을 수 있게 한다.
  2. 이더를 받고난 후에 어떤 동작을 실행할지 정의할 수 있다.
  3. call 함수로 없는 함수가 불려질 때 어떤 행동을 취하게 할 수 있다.

(※ call은 외부 스마트 컨트랙트의 함수를 사용할 수 있다.)

 

 

fallback의 문법

 

0.6 버전 이전과 이후로 나뉘게 된다.

 

0.6버전 이전에는 아래와 같이 익명함수 하나로 정의되어있다.

// 0.6 이전
function() external payable {}

 

 

0.6버전 이후에는 receive와 fallback 두 가지로 나뉘게 되었다.

 

receive는 순수하게 이더만 받을 경우에 사용하고,

fallback은 함수를 실행하면서 이더를 보낼 경우 혹은 불러진 함수가 존재하지 않을 경우에 사용한다.

// 이더와 상호작용 하지않고 행동을 취할 경우
fallback () external {}

// 이더와 상호작용할 경우
fallback () external payable {}

// 이더만 받을 경우
receive () external payable {}

 

 

2. fallback 예제코드

 

아래의 코드는 You 컨트랙트에서 Bank의 CA에 이더를 보낼경우 혹은 Bank 컨트랙트에 없는 함수를 부를경우 fallback이 발동된다.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;

contract Bank {
    event JustFallbackWIthFunds(address _from, uint256 _value, string message);

    //~0.6
    function() external payable {
        emit JustFallbackWIthFunds(
            msg.sender,
            msg.value,
            "JustFallbackWIthFunds is called"
        );
    }
}

contract You {
    //receve()
    function DepositWithSend(address payable _to) public payable {
        bool success = _to.send(msg.value);
        require(success, "Failled");
    }

    function DepositWithTransfer(address payable _to) public payable {
        _to.transfer(msg.value);
    }

    function DepositWithCall(address payable _to) public payable {
        // ~ 0.7
        (bool sent, ) = _to.call.value(msg.value)("");
        require(sent, "Failed to send either");

        //0.7 ~
        // (bool sent, ) = _to.call{value: msg.value}("");
        // require(sent, "Failled" );
    }

    //fallback()
    function JustGiveMessage(address _to) public {
        // ~ 0.7
        (bool sent, ) = _to.call("HI");
        require(sent, "Failed to send either");

        //0.7 ~
        // (bool success, ) = _to.call("HI");
        // require(success, "Failled" );
    }

    //To the fallback() with Funds
    function JustGiveMessageWithFunds(address payable _to) public payable {
        // ~ 0.7
        (bool sent, ) = _to.call.value(msg.value)("HI");
        require(sent, "Failed to send either");

        //0.7 ~
        // (bool success,) = _to.call{value:msg.value}("HI");
        // require(success, "Failled" );
    }
}

 

0.6 버전 이후에는 fallback을 fallback과 receive로 나누어서 사용한다.

 

receive가 받는 것은 오로지 이더를 CA에 보냈을 경우에 발동하고,

fallback은 컨트랙트에 없는 함수를 실행할 경우와 이더를 보내면서 함수를 실행할 경우에 발동한다.

 

// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 <0.9.0;

contract Bank {
    event JustFallback(address _from, string message);
    event RecevieFallback(address _from, uint256 _value, string message);
    event JustFallbackWIthFunds(address _from, uint256 _value, string message);

    //0.6~
    fallback() external {
        emit JustFallback(msg.sender, "JustFallback is called");
    }

    receive() external payable {
        emit RecevieFallback(
            msg.sender,
            msg.value,
            "RecevieFallback is called"
        );
    }

    //
    // fallback() external payable {
    //     emit JustFallbackWIthFunds(
    //         msg.sender,
    //         msg.value,
    //         "JustFallbackWIthFunds is called"
    //     );
    // }
}

contract You {
    //receve()
    function DepositWithSend(address payable _to) public payable {
        bool success = _to.send(msg.value);
        require(success, "Failled");
    }

    function DepositWithTransfer(address payable _to) public payable {
        _to.transfer(msg.value);
    }

    function DepositWithCall(address payable _to) public payable {
        // ~ 0.7
        // (bool sent, ) = _to.call.value(msg.value)("");
        // require(sent,"Failed to send either");

        //0.7 ~
        (bool sent, ) = _to.call{value: msg.value}("");
        require(sent, "Failled");
    }

    //fallback()
    function JustGiveMessage(address _to) public {
        // ~ 0.7
        // (bool sent, ) = _to.call("HI");
        // require(sent,"Failed to send either");

        //0.7 ~
        (bool success, ) = _to.call("HI");
        require(success, "Failled");
    }

    //To the fallback() with Funds
    function JustGiveMessageWithFunds(address payable _to) public payable {
        // ~ 0.7
        // (bool sent, ) = _to.call.value(msg.value)("HI");
        // require(sent,"Failed to send either");

        //0.7 ~
        (bool success, ) = _to.call{value: msg.value}("HI");
        require(success, "Failled");
    }
}

 

(실행하는 과정은 추후에 추가 하도록 하겠습니다...)