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);
}
}