프록시 컨트랙트의 내부에는 어드민의 관리를 위해 만든 함수가 있다.
이 함수명이 로직 컨트랙트의 함수명과 동일하다면 프록시의 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);
}
}
슬롯 값인 상수 역시 private 으로 바꾸어준다.
bytes32 private constant IMPLEMENTATION_SLOT = bytes32(
uint(keccak256("implementation")) - 1
);
bytes32 private constant ADMIN_SLOT = bytes32(
uint(keccak256("admin")) - 1
);
modifier checkAdmin 을 만들어준다.
함수를 호출한 주소가 어드민이라면, 그대로 함수 호출.
=> 프록시 컨트랙트의 함수를 호출
그 외의 주소가 호출했다면, _fallback 함수 호출.
=> 로직 컨트랙트로 delegate call.
modifier checkAdmin() {
if(msg.sender == _getAdmin()){
_;
} else {
_fallback();
}
}
위의 modifier 내부 로직으로 fallback 함수를 그대로 호출할 수 없으므로 _fallback 함수를 정의하고 수정한다.
function _fallback() private {
_delegate(_getImplementation());
}
fallback() external payable {
_fallback();
}
receive() external payable {
_fallback();
}
require 문으로 어드민임을 확인했던 upgradeTo 함수는 modifier 를 사용함으로 필요가 없다. 삭제해준다.
function upgradeTo(address _implementation) external checkAdmin {
_setImplementation(_implementation);
}
두 함수에 modifier 를 넣어줌으로 호출하는 주소가 admin 인지, user 인지에 따라 반환하는 값이 바뀔 것이다.
function admin() external checkAdmin returns(address) {
return _getAdmin();
}
function implementation() external checkAdmin returns(address) {
return _getImplementation();
}
프록시 컨트랙트 내부에 있는 함수를 호출하고 값을 반환.
로직 컨트랙트를 delegate call 한 값을 반환.
modifier 를 사용하여 어드민, 유저의 인터페이스를 구현했다.
어드민은 프록시 내부의 함수를 호출하여 프록시의 관리에 필요한 값을 반환받을 수 있다.
유저는 로직의 함수를 delegate call 하여 dApp 사용에 필요한 값을 반환받을 수 있다.