
call()은 address 데이터 타입 내에 존재하는 메서드로 다른 컨트랙트와 상호작용하는 저수준(low lever) 함수다.call()를 이용해 송금을 하거나 다른 스마트 컨트랙트의 함수를 호출할 수 있다.send() 와 trasfer()의 경우 2,300 gas를 발생시킨다.call() 사용을 권장한다.send() 와 trasfer()이 소비하는 2,300 gas 로는 다른 스마트 컨트랙트을 작동하기에는 부족할 수 있기 때문이다.call() 은 다양한 형태로 사용된다.
function myFunction(uint _x, address _addr) public returns(uint, uint) {
// do something
return (a, b);
}
// function signature string should not have any spaces
(bool success, bytes memory result) = addr.call(abi.encodeWithSignature("myFunction(uint,address)", 10, msg.sender));
다른 컨트랙트의 함수를 호출할 때 사용되는 형태이다.
반환값은 함수 호출의 성공, 실패를 반환하는 bool과 호출한 함수의 반환값을 담는 bytes이며, abi.decode()로 변환하여 사용 가능하다.
(bool success, ) = addr.call(abi.encodeWithSignature("myFunction(uint,address)", 10, msg.sender));
호출한 함수의 반환값이 존재하지 않는다면 위와 같이 bytes를 생략해도 된다.
(bool success, bytes memory result) = addr.call("");
call에 전달된 함수가 존재하지 않으면 해당 스마트 컨트랙트의 fallback 함수가 호출된다.
만약, fallback 함수가 구현되지 않았다면, call()는 false를 반환한다.
(bool success, bytes memory result) = addr.call{gas: 1000000}(abi.encodeWithSignature("myFunction(uint,address)", 10, msg.sender));
위와 같이 호출할 함수에서 사용될 가스비를 지정해 줄 수도 있지만, 가스비를 하드코딩하는 것은 권장되지 않는다.
만약 사용할 가스비를 지정하지 않는다면, call() 함수전에 남아 있는 모든 가스가 호출할 함수로 공급된다.
function myFunction(uint _x, address _addr) public payable returns(uint, uint) {
// do something
return (a, b);
}
(bool success, bytes memory result) = addr.call{value: msg.value}(abi.encodeWithSignature("myFunction(uint,address)", 10, msg.sender));
value를 통해 이더를 호출할 수 있다.
(bool success, bytes memory result) = addr.call{value: msg.sender}("");
call에 전달된 함수가 존재하지 않으면 해당 스마트 컨트랙트의 receive 함수가 호출된다.
만약, receive 함수가 구현되지 않았다면 fallback 함수가 호출되고, fallback 함수가 구현되지 않았다면 call()는 false를 반환한다.
(bool success, bytes memory result) = addr.call{value: msg.value, gas: 1000000}(abi.encodeWithSignature("myFunction(uint,address)", 10, msg.sender));
마찬가지로 권장되지 않지만 가스비를 하드코딩하는 것도 가능하다.
아래 컨트랙트를 call()을 이용해 호출하는 예제들이다.
contract callee {
event JustFallback(string _str);
event JustReceive(string _str);
function addNumber(uint256 _num1, uint256 _num2) public pure returns (uint256) {
return _num1 + _num2;
}
fallback() external {
emit JustFallback("JustFallback is called");
}
received() external {
emit JustReceive("JustReceive is called");
}
}
contract callSend {
function transferEther(address payable _to) public payable {
(bool success, ) = _to.call{value: msg.value}("");
require(sucess, "failed to transfer ether");
}
}
contract callFunction {
event calledFunction(bool _success, bytes _data);
function callMethod(address _contractAddress, uint256 _num1, uint256 _num2) public {
(bool success, btyes memory data) = _contractAddress.call(
abi.encodeWithSignature("addNumber(uint256, uint256)", _num1, _num2);
);
require(success, "failed to call outer function");
emit calledFunction(success, data);
}
}