Proxy Pattern - UUSP

_Block·2022년 5월 28일
0

SmartContract

목록 보기
3/5
post-thumbnail

이번에는 유명한 Proxy Pattern중 하나인 UUSP에 대해서 알아 보겠습니다.

실제로 프로젝트에서도 활용을 해볼 패턴이고 이러한 제안은 EIP-1822 라고도 합니다.

Proxy는 간단하게 설명을 하면 대체자를 통해서 다른 컨트랙트를 호출 하는 방법을 말합니다.

앞서 말했듯이 이러한 방법을 활용하면 따로 저장공간을 두고 활용이 가능합니다.

기본적인 구조는 이와 같습니다.

Proxy를 통해서 Logic - 1을 실행 시키고 이후 해당 로직에 대한 데이터를 다른 공간에 저장을 해두 어서 관리를 하는 것 입니다.

이러한 관점에서 보면 저희는 LogicContract를 변경하여 활용이 가능합니다.

  • 왜냐하면 어차피 다른 저장공간을 활용하고 있기 때문에 해당 공간에 있는 데이터를 활용하면 됩니다.

오늘은 실제 테스트를 통해서 알아보도록 하겠습니다.

🐾 Youtube

🐾 SourceCode

//SPDX-License-Identifier: MIT

pragma solidity 0.8.1;

contract Proxy {
    // Storage = "0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7"
    constructor(bytes memory constructData, address contractLogic) {
        // save the code address
        assembly { // solium-disable-line
            sstore(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7, contractLogic)
        }
        (bool success, bytes memory result ) = contractLogic.delegatecall(constructData); // solium-disable-line
        require(success, "Construction failed");
    }

    fallback() external payable {
        assembly { // solium-disable-line
            let contractLogic := sload(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7)
            calldatacopy(0x0, 0x0, calldatasize())
            let success := delegatecall(sub(gas(), 10000), contractLogic, 0x0, calldatasize(), 0, 0)
            let retSz := returndatasize()
            returndatacopy(0, 0, retSz)
            switch success
            case 0 {
                revert(0, retSz)
            }
            default {
                return(0, retSz)
            }
        }
    }
}

contract Proxiable {
    //  keccak256("PROXIABLE") = "0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7"

    function updateCodeAddress(address newAddress) internal {
        require(
            bytes32(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7) == Proxiable(newAddress).proxiableUUID(),
            "Not compatible"
        );
        assembly { // solium-disable-line
            sstore(0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7, newAddress)
        }
    }

    function proxiableUUID() public pure returns (bytes32) {
        return 0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7;
    }
} 

contract MyContract {

    address public owner;
    uint256 public secondUint;

    function constructor1() public {
        require(owner == address(0), "Already initalized");
        owner = msg.sender;
    }

    function increment2() public {
        //require(msg.sender == owner, "Only the owner can increment"); //someone forget to uncomment this
        secondUint += 3;
    }
}

contract MyFinalContract is MyContract, Proxiable {

    function updateCode(address newCode) onlyOwner public {
        updateCodeAddress(newCode);
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner is allowed to perform this action");
        _;
    }
}
profile
Block_Chain 개발자 입니다. 해당 블로그는 네트워크에 관한 내용을 다루고 있습니다.

0개의 댓글