[TIL] Part4 - DAY74 Project - delegatecall, interface, abstract, library, npm에 배포

박동우·2023년 7월 10일

블록체인 스쿨 3기

목록 보기
70/72

[TIL] 2023-07-10 DAY74


Project

GIT 주소
https://github.com/dowoo303/SOLIDITY
https://github.com/dowoo303/hardhat


오늘 배운것들

  1. delegatecall과 call의 차이
  2. interface abstract, library
  3. npm에 배포하는법

각종 팁

회고




💻 Solidity 코딩

✅ delegatecall

다른 컨트랙트의 함수를 빌려서 자신 내 컨트랙트의 상태를 변경시킴(이 경우 다른 컨트랙트의 함수를 실행시킨다고 해서 그 컨트랙트의 값을 변경시키지는 않음)
-> 즉, 남이 만들어놓은 함수를 내 컨트랙트로 가져와서 사용하는 것과 같다.

사용조건 : 스토리지 슬롯이 동일해야함(갯수가 완전 동일하지는 않아도 되지만 순서는 완벽히 같아야한다)

서로 통신 : fallback


🟥 코드

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

// delegatecall과 call의 차이
// 스토리지 슬롯에 동일하게 작성되어야한다
contract A {
    uint public num;
    address public sender;

    function setNum(uint _num) public {
        num = _num;
        sender = msg.sender;
    }

    function add(uint _a, uint _b) public {
        // num = _a+_b;
        // sender = msg.sender;
        addUpgrade(_a, _b);
    }

    function addUpgrade(uint _a, uint _b) public {
        num = _a+_a+_b;
        sender = msg.sender;
    }
}

// A의 함수를 이용해서 B의 상태변수 변경
contract B {
    uint public num;
    address public sender;

    function setNum(address _contract, uint _a, uint _b) public {
        (bool success, bytes memory data) = _contract.delegatecall(abi.encodeWithSignature("add(uint256,uint256)",_a,_b));
        require(success, "did not work");
    }

    address iAmWatching;

    function watching(address _contract) public {
        iAmWatching = _contract;
    }

    function setNumber(uint _a, uint _b) public {
        (bool success, bytes memory data) = iAmWatching.delegatecall(abi.encodeWithSignature("add(uint256,uint256)", _a, _b));
        require(success, "did not work");
    }
}

contract B2 {
    uint public num;
    address public sender;
    address iAmWatching;

    string public str;


    function setNum(address _contract, uint _a, uint _b) public {
        (bool success, bytes memory data) = _contract.delegatecall(abi.encodeWithSignature("add(uint256,uint256)",_a,_b));
        require(success, "did not work");
    }


    function watching(address _contract) public {
        iAmWatching = _contract;
    }

    function setNumber(uint _a, uint _b) public {
        (bool success, bytes memory data) = iAmWatching.delegatecall(abi.encodeWithSignature("add(uint256,uint256)", _a, _b));
        require(success, "did not work");
    }
}

// B와 다르게 C의 상태변수가 변한 것이 아니라 A의 상태변수만 변경
contract C  {
    uint public num;
    address public sender;

    function setNum(address _contract, uint _num) public {
        (bool success, bytes memory data) = _contract.call(abi.encodeWithSignature("setNum(uint256)", _num));
        require(success, "did not work");
    }
}


✅ interface

사용이유: 필수적인 코드들을 알려주는 역할(기초공사에 반드시 필요한 함수 모음) -> 코드를 빠르게 재활용 가능

타컨트랙트형(주소) 대신 interface(주소)로 이용

관리 효율 증가 및 가스비 효율 개선

3가지 차이점

  1. interface : 껍데기

  2. abstract : 껍데기+약간의 변화
    (interface에서 특정 함수는 다른식으로 구성하고 싶을때)

  3. library : 갖다 쓰기


🟥 코드

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

interface ICalculator {
    function count() external view returns(uint);       // 상태변수
    function increment() external;
    function decrement() external;
    function mul() external;
}

contract myContract {
    function increment(address _Calculator) public {
        ICalculator(_Calculator).increment();
    }

    function decrement(address _Calculator) public {
        ICalculator(_Calculator).decrement();
    }

    function count(address _Calculator) public view returns(uint) {
        return ICalculator(_Calculator).count();
    }
}



✅ npm에 배포해보기

사이트: https://www.npmjs.com/

  1. 배포할 sol 파일 준비
  2. npm login으로 로그인
  3. npm publish 명령어로 배포(만약 npm에 같은 이름이 있을경우 package.json에서 이름변경해주기)
  4. npm i 이름 으로 복사 가능
  5. 리믹스에서 import이용해서 라이브러리 사용가능

🟥 코드

profile
HELLO!

0개의 댓글