# Fallback Function
이름 그대로 대비책 함수이다.
- 특징
- 무기명 함수, 이름이 없는 함수이다.
- External 필수
- Payable
- 왜 쓰는가?
- 스마트 컨트랙이 이더를 받을 수 있게 한다.
- 이더를 받고 난 후 어떠한 행동을 취할수 있다.
- Call함수로 없는 함수가 불려질 때, 어떠한 행동을 취하게 할수 있다.
! 이전의 call은 이더를 보내기 위한 용도로 사용했지만 외부 스마트 컨트랙의 함수를 부를때 사용할 수도 있다.
// ~0.6 version
function() external payable{
}
// 0.6~ version
Fallback은 receive와 fallback 두가지 형태로 나뉘게 되었다.
- Receive
순수하게 이더만 받을때 작동한다.
receive() external payable{
}
- Fallback
함수를 실행하면서 이더를 보낼때
fallback() external payable{
}
불려진 함수가 없을 때 작동한다.
fallback() external{
}
0.7버전 이하
// SPDX-License-Identifier:GPL-30
pragma solidity >=0.5.0 <0.9.0;
contract Bank{
event JustFallbackwithfunds(address _from, uint256 _value,string message);
// account -> customer(smart contract) -> bank(smart contract)
function() external payable{
emit JustFallbackwithfunds(msg.sender,msg.value,"Justfallback is called");
}
}
contract customer{
event deposit_event(address payable _to, uint256 value);
function Depositwithsend(address payable _to) public payable{
bool success = _to.send(msg.value);
emit deposit_event(_to,_to.balance);
require(success,"Failed");
}
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");
//0.7~
//(bool sent, ) = _to.call{value:msg.value}("");
//require(sent,"Failed");
}
// 이더를 보내는 것이 아니라 함수를 실행시키려고 한다.
function Justgivemesage(address _to) public{
// ~0.7
(bool sent, ) = _to.call("HI");// Hi 함수가 없으므로 Fallback에 걸린다.
require(sent,"Failed to call function");
//0.7~
//(bool sent, ) = _to.call("Hi");
//require(sent,"Failed to call function");
}
// 이더도 보내고 함수도 같이 실행시키려고한다.
function JustgivemesagewithFund(address payable _to) public payable{
//~0.7
(bool sent, ) = _to.call.value(msg.value)("HI");
require(sent,"Failed to call function");
//0.7~
//(bool sent, ) = _to.call{value:msg.value}("HI");
//require(sent,"Failed to call function");
}
}
Customer의 msg.sender는 account이고 bank의 msg.sender는 customer address가 된다.
이후 버전에서 send와 transfer은 오류가 생김
= String 지우면 돌아간다. But 버전 따라 다르다. 갈수록 오르는 추세
즉, 2300gas로 부족함을 알 수 있다. -> Call로 해야함
// SPDX-License-Identifier:GPL-30
pragma solidity >=0.5.0 <0.9.0;
contract Bank{
event Justfallback(address _from, string message);
event ReceiveFallback(address _From,uint256 _value,string message);
event JustFallbackwithfunds(address _from, uint256 _value,string message);
// account -> customer(smart contract) -> bank(smart contract)
fallback() external {
emit Justfallback(msg.sender,"Justfallback is called");
}
receive() external payable{
emit ReceiveFallback(msg.sender,msg.value,"ReceiveFallback");
}
}
contract customer{
event deposit_event(address payable _to, uint256 value);
function Depositwithsend(address payable _to) public payable{
bool success = _to.send(msg.value);
emit deposit_event(_to,_to.balance);
require(success,"Failed");
}
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");
//0.7~
(bool sent, ) = _to.call{value:msg.value}("");
require(sent,"Failed");
}
// 이더를 보내는 것이 아니라 함수를 실행시키려고 한다.
function Justgivemesage(address _to) public{
//(bool sent, ) = _to.call("HI");// Hi 함수가 없으므로 Fallback에 걸린다.
//require(sent,"Failed to call function");
//0.7~
(bool sent, ) = _to.call("Hi");
require(sent,"Failed to call function");
}
// 이더도 보내고 함수도 같이 실행시키려고한다.
function JustgivemesagewithFund(address payable _to) public payable{
//~0.7
//(bool sent, ) = _to.call.value(msg.value)("HI");
//require(sent,"Failed to call function");
//0.7~
(bool sent, ) = _to.call{value:msg.value}("HI");
require(sent,"Failed to call function");
}
}
! Remix low level interaction으로 account -> smart contract 송금 가능
! 자신의 잔액 조회 = address(this).balance
# Call
: Low level 함수
- 특징
- 송금하기
- 외부 스마트 컨트랙트 함수 부르기
// SPDX-License-Identifier:GPL-30
pragma solidity >=0.5.0 <0.9.0;
contract add{
event JustFallback(string _str);
event JustRecevie(string _str);
function addNumber(uint256 _num1, uint256 _num2) public pure returns(uint256){
return _num1+_num2;
}
fallback() external {
emit Justfallback("Just Fallback");
}
receive() external payable{
emit JustRecevie("Justreceive is called");
}
}
contract caller{
event calledFunction(bool _success, bytes _output);
function transferEther(address payable _to) public payable{
(bool success, ) = _to.call{value:msg.value}("");
require(success,"Failed to transfer ether");
}
function callMethod(address _contractaddr, uint256 _num1, uint256 _num2) public{
(bool success, bytes memory outputFromCalledFunction) = _contractaddr.call(
abi.encodeWithSignature("addNumber(uint256,uint256)",_num1,_num2)
);
require(success,"failed to transfer ether");
emit calledFunction(success,outputFromCalledFunction);
// return 값이 바이트 화 되어서 받아진다. 기존 call에서는 받을 이유없어서 비워둠
}
}
! Abi는 이더리움 환경안에서 스마트 컨트랙트를 상호작용시키는 표준 방법이다.
주로 encodeWithSignature 메소드를 활용하여 function을 부른다.
- 가변적인 gas
- 아스탄불 하드포크, 2019년 12월 이후, gas 가격 상승에 따른 call 사용 권장
- Re-entrancy(재진입)공격 위험 있기에, Checks_effects_Interactions_pattern 사용
# Call vs Delegate Call
- Delegate Call
- Msg.sender가 본래의 스마트 컨트랙트 사용자를 나타낸다.
- Delegate call이 정의된 스마트 컨트랙트(= caller)가 외부 컨트랙트의 함수들을 자신의 것 처럼 사용(= 실질적인 값도 caller에 저장)
조건 : 외부 스마트 컨트랙트와 caller스마트 컨트랙트는 같은 변수를 갖고 있어야 한다.
- Delegate call 전개
Caller calla() -> 스마트 컨트랙 A -> callb() 스마트 컨트랙 B
주소 : 1 주소 : 2 주소 : 3
msg.sender = 1 msg.sender = 1(call일때는 2이다)
value =1-> 2 call일땐 b의 value가 변경됨
기능을 A에서 실행시킨 것으로 보면 된다.
- Delegate call 사용 이유
배포된 스마트 컨트랙의 특정 default값과 같은 것을 업데이트나 수정 하고 싶을 때 다시 배포하는 것 이외에는 수정할 수가 없다.
다시 배포한다고 하면 그동안 사용했던 정보들이 저장되어 있다.
또한 재배포한 스마트컨트랙의 주소를 다시 고객에서 배포해야한다.
이를 막기 위해 a -> b와의 관계에서 b를 모듈처럼 a에 연결시키듯이 주소를 setaddr를 하고 b를 업데이트 해야하면 새로운 c를 만들어서 setaddr한다.
# Enum
// SPDX-License-Identifier:GPL-30
pragma solidity >=0.5.0 <0.9.0;
contract enu{
enum Carstatus{
Turnoff,
Turnon,
Driving,
Stop
}
CarStatus public carStatus;
constructor(){
carStatus = CarStatus.Turnoff;
}
event carCurrentStatus(CarStatus _carStatus, uint256 _carstatusInint);
function turnoncar() public{
require(carStatus== CarStatus.Turnoff,"To turn on, your car must be turned off");
carStatus = CarStatus.Turnon;
emit carCurrentStatus(carStatus,uint256(carStatus));
}
}
# Interface
스마트컨트랙트 내에서 필요에 의해 정의되어야 할 것
- 함수는 external로 표시
- Enum, structs 가능
- 변수, 생성자 불가능
// SPDX-License-Identifier:GPL-30
pragma solidity >=0.5.0 <0.9.0;
interface Iteminfo{
struct item{
string name;
uint256 price;
}
function addItemInfo(string memory _name,uint256 _price) external;
function getItemInfo(uint256 _index) external view returns(item memory)
}
contract lec is Iteminfo{
item[] public itemlist;
uint256[] public a;
//인터페이스에 있는 함수 빠지지 않고 다 써줘야 하며 override해야함 . but interface에는 virtual안적음
function addItemInfo(string memory _name,uint256 _price) override public{
itemlist.push(item(_name,_price));
}
function getItemInfo(uint256 _index) override public view returns(item memory){
return itemlist[_index];
}
}
# Library
기존에 만들던 스마트 컨트랙과 다른 종류의 스마트 컨트랙이다.
라이브러리를 사용함으로써 몇가지 이점과 제한사항이 있다.
- 이점
- 재사용 : 블록체인에 라이브러리가 배포되면, 다른 스마트 컨트랙트들에 적용 가능
- 가스 절약 : 공통으로 라이브러리를 빼서 배포하면 전반적인 가스 소비를 줄일 수 있다.
- 데이터 타입 적용 : 라이브러리의 기능들은 데이터 타입에 적용할 수 있기 때문에 좀 더 쉽게 사용할 수 있다.
- 제한 사항
- Fallback 함수 불가 : Fallback함수를 라이브러리 안에 정의 못 하기에 이더를 갖고 있을 수 없다.
- 상속 불가
- Payable함수 정의 불가
// SPDX-License-Identifier:GPL-30
pragma solidity >=0.5.0 <0.9.0;
// 0.8 이전 버전에는 overflow허용됨
// 이후에는 막아준다.
library SafeMath{
function add(uint8 a, uint8 b) internal pure returns (uint8){
require(a+b>=a, "SafeMath: addition overflow");
return a+b;
}
}
contract lib{
using SafeMath for uint8;
uint8 public a;
function becomeOverflow(uint8 _num1, uint8 _num2) public {
//a = _num1.add(_num2);
a = SafeMath.add(_num1,_num2);
}
}
# Import
// SPDX-License-Identifier:GPL-30
pragma solidity >=0.5.0 <0.9.0;
library SafeMath{
function add(uint8 a, uint8 b) internal pure returns (uint8){
require(a+b>=a, "SafeMath: addition overflow");
return a+b;
}
}
contract HiSolidity{
event Hi(string _str);
function hi() public{
emit Hi("Hello solidity");
}
}
// SPDX-License-Identifier:GPL-30
pragma solidity >=0.5.0 <0.9.0;
import "./hi.sol";
// import "../hi.sol";
contract HiSolidity2 is HiSolidity{
using SafeMath for uint8;
uint8 public a;
function becomeOverflow(uint8 _num1,uint8 _num2) public {
a = _num1.add(_num2);
}
}
외부 소스파일에서 import
Import "https://github.com/OpenZeppelin/~";
'BlockChain' 카테고리의 다른 글
Solidity 취약점 카테고리화 (0) | 2022.01.11 |
---|---|
Solidity #5 (0) | 2022.01.10 |
Solidity #4 (0) | 2022.01.07 |
Solidity #2 (0) | 2022.01.05 |
Solidity #1 (0) | 2022.01.04 |