안녕하세요. 스마트 컨트렉트 개발자 개발이 체질의 최원혁입니다.
요즘 앱개발 프로젝트 계약을 하게 돼서, 블로그 작성할 시간이 많이 없네요. 하루에 한두 시간씩 공부하면서 정리노트에 정리 중이니, 시간 내서 작성해 보도록 하겠습니다.
오늘은 Solidity의 Payable(), Fallback(), Receive() 함수에 대해 알아보겠습니다.
Smart Contract가 이더리움에 베포가된다면, 이더리움 네트워크의 네이티브 코인(Native Coin)인 이더(Ether)는 Smart Contract를 통해 사용자 또는 컨트렉트에 전송할 수 있습니다. 해당 기능을 위해 Solidity에서 기능을 구현해야 합니다. 그 역할을 하는 게 Payable(), Fallback(), Receive() 함수입니다.
지금부터 각 함수가 Smart Contract에서 세부적으로 어떻게 사용되는지 알아보겠습니다.
Payable()
Solidity에서 payable() 함수는 주소(address) 또는 함수(function)에 명시되어, 이더가 수신하고 처리되는 의미를 부여합니다.
// 주소에 명시하는 경우
payable(address);
address payable public owner;
// 함수에 명시하는 경우
function deposit() external payable {
...logic...
}
payable()는 위와 같이 Solidity 문법에서 사용이 가능합니다. payable() 함수가 명시된 부분이 네트워크에서 실행 될 경우, 이더가 처리되는 EVM Opcode가 실행됩니다. 즉, 어떤 사용자가 payable()가 명시된 함수나 로직을 실행할 경우, 사용자의 지갑주소에 명시된 이더의 잔액(Balance)을 조회하고, 로직에 따라 전송하는 기능들이 EVM의 Opcode에 의해 실행됩니다.
다른 트랜잭션과 다르게, payable() 함수가 포함된 트랜잭션은 트랜잭션에 보내는 메세지 중, Value를 조회하는 진입점이 됩니다. 그리고 EVM 내에서 런타임 되는 동안 Value에 명시된 이더의 값을 기록하여 함수를 실행합니다.
Fallback() VS Receive()
Fallback()
Fallback() 함수는 Smart Contract의 주소로 발생한 트랜잭션 메세지가 컨트렉트 내부에 어떠한 기능과 일치하지 않는 경우 자동으로 호출되는 함수입니다. 어떤 함수(function)실행 없이 컨트렉트에 이더를 직접적으로 보내는 방법을 구현할 때 사용됩니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract FallbackExample {
fallback() external payable {
// 컨트렉트에 포함되지 않은 기능이 호출될 경우
// 전부 revert()
revert();
}
}
Fallback() 함수는 function에 함수 명 없이 fallback를 명시하기에, 익명(Anonymous)의 함수라고도 불립니다.
위와 같이 fallback에 payable를 명시할 경우, 트랜잭션 메세지의 Value가 포함된 외부 호출을 수신할 경우, 내부 코드가 실행됩니다. 위 예시로 봤을 때, 컨트렉트에 포함되지 않은 기능을 호출하는 트랜잭션은 전부 revert()하도록 되어 있습니다.
Reveive()
Reveive() 함수는 Fallback() 함수와 기능적으로 같지만, 실행되는 조건이 다릅니다. 마찬가지로 컨트렉트 내부에 어떠한 기능과 일치하지 않는 경우 자동으로 호출됩니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract ReceiveExample {
receive() external payable {
revert();
}
}
Solidity 문법으로 위와 같이 receive() 함수를 사용할 수 있습니다.
Reveive VS Fallback 차이
Reveive()와 Fallback()은 같은 기능을 갖고 있지만, 실행 조건이 다릅니다.
트랜잭션 메세지에는 calldata 부분이 있습니다. 이는 트랜잭션에 메시지를 담아 보낼 수 있고, Solidity 내부에서 msg.data로 해당 값을 조회할 수 있습니다.
만약 트랜잭션 메세지에는 calldata가 비어있을 경우(empty) Reveive()이 실행되고, 어떤 데이터가 존재할 경우(exists) Fallback()가 실행됩니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract Fallback {
event Log(string func, uint gas);
// msg.data 존재하는 경우
fallback() external payable {
// send / transfer (forwards 2300 gas to this fallback function)
emit Log("fallback", gasleft());
}
// msg.data 비어있는 경우
receive() external payable {
emit Log("receive", gasleft());
}
// 실행 결과를 확인하기 위한 잔액조회 기능
function getBalance() public view returns (uint) {
return address(this).balance;
}
}
contract SendToFallback {
function transferToFallback(address payable _to) public payable {
// calldata 없이 트랜잭션 보내는 경우
_to.transfer(msg.value);
}
function callFallback(address payable _to) public payable {
// calldata를 담아서 보내는 경우
(bool sent, ) = _to.call{value: msg.value}("data msg");
require(sent, "Failed to send Ether");
}
}
위 코드를 예시로, contract Fallback에 calldata를 담아서 보내거나, 빈 상태로 보내서 Reveive()와 Fallback() 중 어떤 함수가 실행되는지 확인할 수 있습니다.
function callFallback() 실행 : calldata를 담아서 보냈을 경우 :
function transferToFallback() 실행 : calldata를 빈 상태로 보냈을 경우 :
calldata를 담아서 보내거나, 빈 상태로 보냈을 때 Reveive()와 Fallback() 중 어떤 함수가 실행되는지 확인 할 수 있었습니다.
예외 : Smart Contract에 fallback()함수만 있는 경우??
위 예시를 통해 트랜잭션 메세지의 calldata의 존재 유무에 따라 Reveive()와 Fallback() 중 어떤 함수가 실행되는지 확인을 했습니다.
하지만 예외의 경우가 있는데, 바로 컨트랙트 코드 내에 fallback()만 있는 경우입니다.
이때는 msg.data가 비어 있어도 fallback() 함수가 자동으로 실행됩니다.
최종정리 :
- payable() 함수는 주소(address) 또는 함수(function)에 명시되어, 이더가 수신하고 처리되는 의미를 부여한다.
- 호출된 트랜잭션이 컨트렉트 내부에 어떠한 기능과 일치하지 않는 경우 조건에 따라 fallback()과 receive() 함수가 실행된다.
- 트랜잭션 메시지의 Calldata가 비어있는 경우, receive() 함수가 실행된다.
- 트랜잭션 메세지의 Calldata가 존재하는 경우, fallback() 함수가 실행된다.
- 만약 컨트랙트 코드 내부에 fallback()만 존재할 경우, 트랜잭션 메세지의 Calldata가 비어있어도 fallback() 실행된다.
지금까지 Solidity의 Payable(), Fallback(), Receive() 함수에 대해 알아봤습니다.
감사합니다~!
📌 Github Solidity Code :
https://github.com/imelon2/My-Solidity-Playground/blob/main/Solidity/Fallback.sol
https://github.com/imelon2/My-Solidity-Playground/blob/main/Solidity/FallbackReceive.sol
댓글