🔑 코인 투자 추천 링크 🔑
[NEW] 누구나 쉽게 따라하는 솔리디티 강의(솔리디티 버전 0.8.13)
5. 배열, 열거형(enum), 구조체(calldata,memory)
8. 이벤트(events), 생성자(constructor), 상속
10. 인터페이스(interface), payable, 이더전송,받기 관련
11. Fallback, Call, Delegate(솔리디티 업그레이드 기법)
12. 함수 선택자(function selector), 다른 컨트랙트 사용 및 생성기법
13. Try Catch, Import(임포트), Library(라이브러리)
14. ABI 디코드, hash 함수, 서명검증, 가스최적화
* 블록체인 전문가들도 놓치기 쉬운 비트코인, 이더리움의 핵심가치 강의
1. Fallback
- fallback은 함수이며, 어떤 arguments(전달인자)나 return값을 가지지 않는다.
- 존재하지 않는 함수를 호출하거나(계약 내에 존재하지 않는 함수명을 사용하는 경우 폴백 함수 자동으로 호출)
- 쉽게 설명해서, 호출된 함수와 이름이 일치하는 함수가 없을 때 폴백 함수가 호출됨
- 이더가 컨트랙트로 바로 보내질때 호출됨 - receive() 함수가 없거나, msg.data가 없어야 함
- fallback은 transfer, send가 호출될때 2,300 gas 제한이 있음
예제)
- Fallback 함수는 external로 선언되어야 함.
- fallback 함수에서 send,transfer는 2,300 gas 제한이 있음.
- call의 경우 모든 가스를 사용하게 됨
-
- transfer()와 call()을 사용하여 이더 전송.
전체소스
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract Fallback {
event Log(uint gas);
// Fallback function must be declared as external.
fallback() external payable {
// send / transfer (forwards 2300 gas to this fallback function)
// call (forwards all of the gas)
emit Log(gasleft());
}
// Helper function to check the balance of this contract
function getBalance() public view returns (uint) {
return address(this).balance;
}
}
contract SendToFallback {
function transferToFallback(address payable _to) public payable {
_to.transfer(msg.value);
}
function callFallback(address payable _to) public payable {
(bool sent, ) = _to.call{value: msg.value}("");
require(sent, "Failed to send Ether");
}
}
2. Call
- call은 다른 컨트랙트와 상호작용하는 저수준(low lever) 함수다.
- fallback 함수 호출을 통해서 이더를 보낼경우에 이러한 방법을 추천한다.
- 그러나 존재하는 함수를 호출하는 방법으로는 추천하지 않는다.
예제) Receiver 컨트랙트에 fallback() 선언 후 foo()함수 정의
- Caller 컨트랙트는 call을 사용하여 Receiver 컨트랙트의 함수를 호출.
소스파일
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract Receiver {
event Received(address caller, uint amount, string message);
fallback() external payable {
emit Received(msg.sender, msg.value, "Fallback was called");
}
function foo(string memory _message, uint _x) public payable returns (uint) {
emit Received(msg.sender, msg.value, _message);
return _x + 1;
}
}
contract Caller {
event Response(bool success, bytes data);
// Let's imagine that contract B does not have the source code for
// contract A, but we do know the address of A and the function to call.
function testCallFoo(address payable _addr) public payable {
// You can send ether and specify a custom gas amount
(bool success, bytes memory data) = _addr.call{value: msg.value, gas: 5000}(
abi.encodeWithSignature("foo(string,uint256)", "call foo", 123)
);
emit Response(success, data);
}
// Calling a function that does not exist triggers the fallback function.
function testCallDoesNotExist(address _addr) public {
(bool success, bytes memory data) = _addr.call(
abi.encodeWithSignature("doesNotExist()")
);
emit Response(success, data);
}
}
3. DelegateCall
- DelegateCall은 call과 유사한 저수준(low lever) 함수다.
- 컨트랙트 A가 delegatecall을 실행하여 컨트랙트 B를 실행할 수 있다.
- 컨트랙트 B의 코드가 컨트랙트 A의 스토리지(storage), msg.sender, msg.value를 통해서 실행됨
- 아래 예제에서 B를 먼저 실행후 A에서 delegatecall을 사용한다.
- B의 코드를 실행하지만, A의 컨트랙트에 데이터가 저장된다.
소스파일
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
// NOTE: Deploy this contract first
contract B {
// NOTE: storage layout must be the same as contract A
uint public num;
address public sender;
uint public value;
function setVars(uint _num) public payable {
num = _num;
sender = msg.sender;
value = msg.value;
}
}
contract A {
uint public num;
address public sender;
uint public value;
function setVars(address _contract, uint _num) public payable {
// A's storage is set, B is not modified.
(bool success, bytes memory data) = _contract.delegatecall(
abi.encodeWithSignature("setVars(uint256)", _num)
);
}
}
* DelegateCall
- 호출된 컨트래트의 코드가 호출한 컨트랙트의 Context에서 수행됨
- msg.sender와 msg.value가 변하지 않음
- 컨트랙트가 런타임에 서로 다른 주소의 컨트랙트를 호출 할 수 있음
- 스토리지, 주소, 잔액은 여전히 호출 컨트랙트 참조
- 코드만 호출 주소에서 가져옴
- 라이브러리
- 업그레이드 가능한 스마트컨트랙트의 기본개념임!!
소스출처 : https://solidity-by-example.org/
블록체인 교육 문의는 아래 링크 참고 바랍니다.
댓글