BlockChain

Solidity #3

부산대보금자리 2022. 1. 6. 16:56

# Fallback Function

이름 그대로 대비책 함수이다.

 

  • 특징
  1. 무기명 함수, 이름이 없는 함수이다.
  2. External 필수
  3. Payable

 

  • 쓰는가?
  1. 스마트 컨트랙이 이더를 받을 있게 한다.
  2. 이더를 받고 어떠한 행동을 취할수 있다.
  3. 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 함수

 

  • 특징
  1. 송금하기
  2. 외부 스마트 컨트랙트 함수 부르기

 

// 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을 부른다.

 

 

  1. 가변적인 gas
  2. 아스탄불 하드포크, 2019 12 이후, gas 가 상승에 따른 call 사용 권장
  3. Re-entrancy(재진입)공격 위험 있기에, Checks_effects_Interactions_pattern 사용

 

 

# Call vs Delegate Call

 

  • Delegate Call
  1. Msg.sender 본래의 스마트 컨트랙트 사용자를 나타낸다.
  2. 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

스마트컨트랙트 내에서 필요에 의해 정의되어야

 

  1. 함수는 external 표시
  2. Enum, structs 가능
  3. 변수, 생성자 불가능

 

// 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

기존에 만들던 스마트 컨트랙과 다른 종류의 스마트 컨트랙이다.

라이브러리를 사용함으로써 몇가지 이점과 제한사항이 있다.

 

  • 이점
  1. 재사용 : 블록체인에 라이브러리가 배포되면, 다른 스마트 컨트랙트들에 적용 가능
  2. 가스 절약 : 공통으로 라이브러리를 빼서 배포하면 전반적인 가스 소비를 줄일 있다.
  3. 데이터 타입 적용 : 라이브러리의 기능들은 데이터 타입에 적용할 있기 때문에 쉽게 사용할 있다.

 

 

  • 제한 사항
  1. Fallback 함 불가 : Fallback함수를 라이브러리 안에 정의 하기에 이더를 갖고 있을 없다.
  2. 상속 불가
  3. 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