abstract contract TransparentProxyBase is BaseUpgradeabilityProxy, IProxy {
  bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

  constructor(address admin) {
    require(admin != address(0));
    assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
    assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));

    bytes32 slot = ADMIN_SLOT;
    // solhint-disable-next-line no-inline-assembly
    assembly {
      sstore(slot, admin)
    }
  }

  modifier ifAdmin() {
    if (msg.sender == _admin()) {
      _;
    } else {
      _fallback();
    }
  }

  function _admin() internal view returns (address impl) {
    bytes32 slot = ADMIN_SLOT;
    // solhint-disable-next-line no-inline-assembly
    assembly {
      impl := sload(slot)
    }
  }

  /// @return impl The address of the implementation.
  function implementation() external ifAdmin returns (address impl) {
    return _implementation();
  }

  /// @dev Upgrade the backing implementation of the proxy and call a function on it.
  function upgradeToAndCall(address logic, bytes calldata data) external payable override ifAdmin {
    _upgradeTo(logic);
    Address.functionDelegateCall(logic, data);
  }

  /// @dev Only fall back when the sender is not the admin.
  function _willFallback() internal virtual override {
    require(msg.sender != _admin(), 'Cannot call fallback function from the proxy admin');
    super._willFallback();
  }
}
/// @dev This contract is a transparent upgradeability proxy with admin. The admin role is immutable.
function upgradeToAndCall(address logic, bytes calldata data) external payable override ifAdmin {
  _upgradeTo(logic);
  Address.functionDelegateCall(logic, data);
}

/// @dev Upgrade the backing implementation of the proxy and call a function on it.