[Solidity] Proxy contract part 2 - Separate interface

임형석·2023년 10월 31일
0

Solidity


interface

프록시 컨트랙트의 내부에는 어드민의 관리를 위해 만든 함수가 있다.

이 함수명이 로직 컨트랙트의 함수명과 동일하다면 프록시의 admin 함수를 호출하게 된다.

예를 들어, 아래와 같이 두 컨트랙트 코드를 작성했다면 로직 컨트랙트의 함수를 호출. address(1), address(2) 값을 반환하는 것이 개발자의 의도이다.

- 로직 컨트랙트
    function admin() external view returns(address) {
        return address(1);
    }

    function implementation() external view returns(address) {
        return address(2);
    }

- 프록시 컨트랙트
    function admin() external view returns(address) {
        return _getAdmin();
    }

    function implementation() external view returns(address) {
        return _getImplementation();
    }

하지만 의도한 것과 다르게 프록시 컨트랙트의 함수를 호출, 주소 값을 반환했다.

따라서, 유저가 함수를 호출할 때와 어드민이 함수를 호출할 때의 결과를 다르게 만들어주기 위해 코드를 수정한다.


코드 수정

외부에서 호출할 수 있는 모든 함수를 수정해준다. (external, public).

로직 컨트랙트

CounterV1 의 admin, implemetation 함수를 만들어준다.

이 함수를 호출한다면 1, 2 의 주소를 반환할 것이다.

contract CounterV1 {
    uint public count;

    function increase() public {
        count += 1;
    }

    function admin() external view returns(address) {
        return address(1);
    }

    function implementation() external view returns(address) {
        return address(2);
    }
}

프록시 컨트랙트

  • SLOT 상수

슬롯 값인 상수 역시 private 으로 바꾸어준다.

    bytes32 private constant IMPLEMENTATION_SLOT = bytes32(
        uint(keccak256("implementation")) - 1
    );
    
    bytes32 private constant ADMIN_SLOT = bytes32(
        uint(keccak256("admin")) - 1
    );

  • modifier

modifier checkAdmin 을 만들어준다.

함수를 호출한 주소가 어드민이라면, 그대로 함수 호출.
=> 프록시 컨트랙트의 함수를 호출

그 외의 주소가 호출했다면, _fallback 함수 호출.
=> 로직 컨트랙트로 delegate call.

    modifier checkAdmin() {
        if(msg.sender == _getAdmin()){
            _;
        } else {
            _fallback();
        }
    }

  • fallback

위의 modifier 내부 로직으로 fallback 함수를 그대로 호출할 수 없으므로 _fallback 함수를 정의하고 수정한다.

    function _fallback() private {
        _delegate(_getImplementation());
    }

    fallback() external payable {
        _fallback();
    }

    receive() external payable {
        _fallback();
    }

  • upgradeTo

require 문으로 어드민임을 확인했던 upgradeTo 함수는 modifier 를 사용함으로 필요가 없다. 삭제해준다.

    function upgradeTo(address _implementation) external checkAdmin {
        _setImplementation(_implementation);
    }

  • admin & implementation

두 함수에 modifier 를 넣어줌으로 호출하는 주소가 admin 인지, user 인지에 따라 반환하는 값이 바뀔 것이다.

function admin() external checkAdmin returns(address) {
        return _getAdmin();
    }

    function implementation() external checkAdmin returns(address)  {
        return _getImplementation();
    }

테스트

  • admin

프록시 컨트랙트 내부에 있는 함수를 호출하고 값을 반환.


  • user

로직 컨트랙트를 delegate call 한 값을 반환.


modifier 를 사용하여 어드민, 유저의 인터페이스를 구현했다.

어드민은 프록시 내부의 함수를 호출하여 프록시의 관리에 필요한 값을 반환받을 수 있다.

유저는 로직의 함수를 delegate call 하여 dApp 사용에 필요한 값을 반환받을 수 있다.


0개의 댓글