creation_sourcecode: pragma solidity ^0.8.9;
  
  // SPDX-License-Identifier: MIT
  
  abstract contract Proxy {
      fallback() external payable {
          _fallback();
      }
  
      receive() external payable {
          _fallback();
      }
  
      function _implementation() internal view virtual returns (address);
  
      function _delegate(address implementation) internal {
          assembly {
              calldatacopy(0, 0, calldatasize())
  
              let result := delegatecall(
                  gas(),
                  implementation,
                  0,
                  calldatasize(),
                  0,
                  0
              )
              // Copy the returned data.
              let retSz := returndatasize()
              returndatacopy(0, 0, retSz)
  
              switch result
              // delegatecall returns 0 on error.
              case 0 {
                  revert(0, retSz)
              }
              default {
                  return(0, retSz)
              }
          }
      }
  
      function _beforeFallback() internal virtual {}
  
      function _fallback() internal {
          _beforeFallback();
          _delegate(_implementation());
      }
  }
  
  library ZOSLibAddress {
      function isContract(address account) internal view returns (bool) {
          uint256 size;
          // solhint-disable-next-line no-inline-assembly
          assembly {
              size := extcodesize(account)
          }
          return size > 0;
      }
  }
  
  contract BaseUpgradeabilityProxy is Proxy {
      event Upgraded(address indexed implementation);
  
      bytes32 internal constant IMPLEMENTATION_SLOT =
          0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
  
      function _implementation() internal view override returns (address impl) {
          bytes32 slot = IMPLEMENTATION_SLOT;
          assembly {
              impl := sload(slot)
          }
      }
  
      function _upgradeTo(address newImplementation) internal {
          _setImplementation(newImplementation);
          emit Upgraded(newImplementation);
      }
  
      function _setImplementation(address newImplementation) internal {
          require(
              ZOSLibAddress.isContract(newImplementation),
              "Cannot set a proxy implementation to a non-contract address"
          );
  
          bytes32 slot = IMPLEMENTATION_SLOT;
  
          assembly {
              sstore(slot, newImplementation)
          }
      }
  }
  
  contract TransparentUpgradeableProxy is BaseUpgradeabilityProxy {
      //ERC-1967 bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)
      bytes32 internal constant ADMIN_SLOT =
          0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
  
      constructor(
          address logic,
          address newAdmin,
          bytes memory data
      ) payable {
          assert(
              IMPLEMENTATION_SLOT ==
                  bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)
          );
          assert(
              ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1)
          );
          _setAdmin(newAdmin);
          _setImplementation(logic);
          if (data.length > 0) {
              (bool success, ) = logic.delegatecall(data);
              require(success);
          }
      }
  
      event AdminChanged(address previousAdmin, address newAdmin);
  
      modifier ifAdmin() {
          if (msg.sender == _admin()) {
              _;
          } else {
              _fallback();
          }
      }
  
      function admin() external ifAdmin returns (address) {
          return _admin();
      }
  
      function implementation() external ifAdmin returns (address) {
          return _implementation();
      }
  
      function changeAdmin(address newAdmin) external ifAdmin {
          require(
              newAdmin != address(0),
              "Cannot change the admin of a proxy to the zero address"
          );
          emit AdminChanged(_admin(), newAdmin);
          _setAdmin(newAdmin);
      }
  
      function upgradeTo(address newImplementation) external ifAdmin {
          _upgradeTo(newImplementation);
      }
  
      function upgradeToAndCall(address newImplementation, bytes calldata data)
          external
          payable
          ifAdmin
      {
          _upgradeTo(newImplementation);
          (bool success, ) = newImplementation.delegatecall(data);
          require(success);
      }
  
      function _admin() internal view returns (address adm) {
          bytes32 slot = ADMIN_SLOT;
          assembly {
              adm := sload(slot)
          }
      }
  
      function _setAdmin(address newAdmin) internal {
          bytes32 slot = ADMIN_SLOT;
  
          assembly {
              sstore(slot, newAdmin)
          }
      }
  
      function _beforeFallback() internal override {
          require(
              msg.sender != _admin(),
              "Cannot call fallback function from the proxy admin"
          );
          super._beforeFallback();
      }
  }