diff --git a/.github/workflows/pr_test_build.yml b/.github/workflows/pr_test_build.yml
index 03c44755c..b4ddcfefe 100644
--- a/.github/workflows/pr_test_build.yml
+++ b/.github/workflows/pr_test_build.yml
@@ -151,6 +151,7 @@ jobs:
           echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
           echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
           echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
+          echo "const quantexExchangeMarkup = '${{ secrets.QUANTEX_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
           echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
           echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
 
diff --git a/assets/images/quantex.png b/assets/images/quantex.png
new file mode 100644
index 000000000..cfa32b382
Binary files /dev/null and b/assets/images/quantex.png differ
diff --git a/assets/text/Monerocom_Release_Notes.txt b/assets/text/Monerocom_Release_Notes.txt
index d5297ebe1..faad67777 100644
--- a/assets/text/Monerocom_Release_Notes.txt
+++ b/assets/text/Monerocom_Release_Notes.txt
@@ -1 +1 @@
-Generic bug fixes and enhancements
\ No newline at end of file
+Bug fixes and generic enhancements
\ No newline at end of file
diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt
index f9b05cea2..faad67777 100644
--- a/assets/text/Release_Notes.txt
+++ b/assets/text/Release_Notes.txt
@@ -1,3 +1 @@
-Hardware wallets support for Bitcoin, Ethereum and Polygon
-Security enhancements
 Bug fixes and generic enhancements
\ No newline at end of file
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 0cc57e075..c4ee98c37 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -307,7 +307,7 @@ SPEC CHECKSUMS:
   Toast: ec33c32b8688982cecc6348adeae667c1b9938da
   uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
   UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
-  url_launcher_ios: 6116280ddcfe98ab8820085d8d76ae7449447586
+  url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
   wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
   workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
 
diff --git a/lib/exchange/exchange_provider_description.dart b/lib/exchange/exchange_provider_description.dart
index 4d9691035..c28de5b72 100644
--- a/lib/exchange/exchange_provider_description.dart
+++ b/lib/exchange/exchange_provider_description.dart
@@ -22,10 +22,11 @@ class ExchangeProviderDescription extends EnumerableItem<int> with Serializable<
       ExchangeProviderDescription(title: 'Trocador', raw: 5, image: 'assets/images/trocador.png');
   static const exolix =
       ExchangeProviderDescription(title: 'Exolix', raw: 6, image: 'assets/images/exolix.png');
-  static const thorChain =
-  ExchangeProviderDescription(title: 'ThorChain' , raw: 8, image: 'assets/images/thorchain.png');
-
   static const all = ExchangeProviderDescription(title: 'All trades', raw: 7, image: '');
+  static const thorChain =
+      ExchangeProviderDescription(title: 'ThorChain', raw: 8, image: 'assets/images/thorchain.png');
+  static const quantex =
+      ExchangeProviderDescription(title: 'Quantex', raw: 9, image: 'assets/images/quantex.png');
 
   static ExchangeProviderDescription deserialize({required int raw}) {
     switch (raw) {
@@ -43,10 +44,12 @@ class ExchangeProviderDescription extends EnumerableItem<int> with Serializable<
         return trocador;
       case 6:
         return exolix;
-      case 8:
-        return thorChain;
       case 7:
         return all;
+      case 8:
+        return thorChain;
+      case 9:
+        return quantex;
       default:
         throw Exception('Unexpected token: $raw for ExchangeProviderDescription deserialize');
     }
diff --git a/lib/exchange/provider/quantex_exchange_provider.dart b/lib/exchange/provider/quantex_exchange_provider.dart
new file mode 100644
index 000000000..9ab7fbb55
--- /dev/null
+++ b/lib/exchange/provider/quantex_exchange_provider.dart
@@ -0,0 +1,252 @@
+import 'dart:convert';
+
+import 'package:cake_wallet/.secrets.g.dart' as secrets;
+import 'package:cake_wallet/exchange/exchange_provider_description.dart';
+import 'package:cake_wallet/exchange/limits.dart';
+import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
+import 'package:cake_wallet/exchange/trade.dart';
+import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
+import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
+import 'package:cake_wallet/exchange/trade_request.dart';
+import 'package:cake_wallet/exchange/trade_state.dart';
+import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
+import 'package:cw_core/crypto_currency.dart';
+import 'package:http/http.dart';
+
+class QuantexExchangeProvider extends ExchangeProvider {
+  QuantexExchangeProvider() : super(pairList: supportedPairs(_notSupported));
+
+  static final List<CryptoCurrency> _notSupported = [
+    ...(CryptoCurrency.all
+        .where((element) => ![
+              CryptoCurrency.btc,
+              CryptoCurrency.sol,
+              CryptoCurrency.eth,
+              CryptoCurrency.ltc,
+              CryptoCurrency.ada,
+              CryptoCurrency.bch,
+              CryptoCurrency.usdt,
+              CryptoCurrency.bnb,
+              CryptoCurrency.xmr,
+            ].contains(element))
+        .toList())
+  ];
+
+  static final markup = secrets.quantexExchangeMarkup;
+
+  static const apiAuthority = 'api.myquantex.com';
+  static const getRate = '/api/swap/get-rate';
+  static const getCoins = '/api/swap/get-coins';
+  static const createOrder = '/api/swap/create-order';
+
+  @override
+  String get title => 'Quantex';
+
+  @override
+  bool get isAvailable => true;
+
+  @override
+  bool get isEnabled => true;
+
+  @override
+  bool get supportsFixedRate => false;
+
+  @override
+  ExchangeProviderDescription get description => ExchangeProviderDescription.quantex;
+
+  @override
+  Future<bool> checkIsAvailable() async => true;
+
+  @override
+  Future<Limits> fetchLimits({
+    required CryptoCurrency from,
+    required CryptoCurrency to,
+    required bool isFixedRateMode,
+  }) async {
+    try {
+      final uri = Uri.https(apiAuthority, getCoins);
+      final response = await get(uri);
+
+      final responseJSON = json.decode(response.body) as Map<String, dynamic>;
+
+      if (response.statusCode != 200)
+        throw Exception('Unexpected http status: ${response.statusCode}');
+
+      final coinsInfo = responseJSON['data'] as List<dynamic>;
+
+      for (var coin in coinsInfo) {
+        if (coin['id'].toString().toUpperCase() == _normalizeCurrency(from)) {
+          return Limits(
+            min: double.parse(coin['min'].toString()),
+            max: double.parse(coin['max'].toString()),
+          );
+        }
+      }
+
+      // coin not found:
+      return Limits(min: 0, max: 0);
+    } catch (e) {
+      print(e.toString());
+      return Limits(min: 0, max: 0);
+    }
+  }
+
+  @override
+  Future<double> fetchRate({
+    required CryptoCurrency from,
+    required CryptoCurrency to,
+    required double amount,
+    required bool isFixedRateMode,
+    required bool isReceiveAmount,
+  }) async {
+    try {
+      if (amount == 0) return 0.0;
+
+      final headers = <String, String>{};
+      final params = <String, dynamic>{};
+      final body = <String, String>{
+        'coin_send': _normalizeCurrency(from),
+        'coin_receive': _normalizeCurrency(to),
+        'ref': 'cake',
+      };
+
+      final uri = Uri.https(apiAuthority, getRate, params);
+      final response = await post(uri, body: body, headers: headers);
+      final responseBody = json.decode(response.body) as Map<String, dynamic>;
+
+      if (response.statusCode != 200)
+        throw Exception('Unexpected http status: ${response.statusCode}');
+
+      final data = responseBody['data'] as Map<String, dynamic>;
+      double rate = double.parse(data['price'].toString());
+      return rate;
+    } catch (e) {
+      print("error fetching rate: ${e.toString()}");
+      return 0.0;
+    }
+  }
+
+  @override
+  Future<Trade> createTrade({
+    required TradeRequest request,
+    required bool isFixedRateMode,
+    required bool isSendAll,
+  }) async {
+    try {
+      final headers = <String, String>{};
+      final params = <String, dynamic>{};
+      var body = <String, dynamic>{
+        'coin_send': _normalizeCurrency(request.fromCurrency),
+        'coin_receive': _normalizeCurrency(request.toCurrency),
+        'amount_send': request.fromAmount,
+        'recipient': request.toAddress,
+        'ref': 'cake',
+        'markup': markup,
+      };
+
+      String? fromNetwork = _networkFor(request.fromCurrency);
+      String? toNetwork = _networkFor(request.toCurrency);
+      if (fromNetwork != null) body['coin_send_network'] = fromNetwork;
+      if (toNetwork != null) body['coin_receive_network'] = toNetwork;
+
+      final uri = Uri.https(apiAuthority, createOrder, params);
+      final response = await post(uri, body: body, headers: headers);
+      final responseBody = json.decode(response.body) as Map<String, dynamic>;
+
+      if (response.statusCode == 400 || responseBody["success"] == false) {
+        final error = responseBody['errors'][0]['msg'] as String;
+        throw TradeNotCreatedException(description, description: error);
+      }
+
+      if (response.statusCode != 200)
+        throw Exception('Unexpected http status: ${response.statusCode}');
+
+      final responseData = responseBody['data'] as Map<String, dynamic>;
+
+      return Trade(
+        id: responseData["order_id"] as String,
+        inputAddress: responseData["server_address"] as String,
+        amount: request.fromAmount,
+        from: request.fromCurrency,
+        to: request.toCurrency,
+        provider: description,
+        createdAt: DateTime.now(),
+        state: TradeState.created,
+        payoutAddress: request.toAddress,
+        isSendAll: isSendAll,
+      );
+    } catch (e) {
+      print("error creating trade: ${e.toString()}");
+      throw TradeNotCreatedException(description, description: e.toString());
+    }
+  }
+
+  @override
+  Future<Trade> findTradeById({required String id}) async {
+    try {
+      final headers = <String, String>{};
+      final params = <String, dynamic>{};
+      var body = <String, dynamic>{
+        'order_id': id,
+      };
+
+      final uri = Uri.https(apiAuthority, createOrder, params);
+      final response = await post(uri, body: body, headers: headers);
+      final responseBody = json.decode(response.body) as Map<String, dynamic>;
+
+      if (response.statusCode == 400 || responseBody["success"] == false) {
+        final error = responseBody['errors'][0]['msg'] as String;
+        throw TradeNotCreatedException(description, description: error);
+      }
+
+      if (response.statusCode != 200)
+        throw Exception('Unexpected http status: ${response.statusCode}');
+
+      final responseData = responseBody['data'] as Map<String, dynamic>;
+      final fromCurrency = responseData['coin_send'] as String;
+      final from = CryptoCurrency.fromString(fromCurrency);
+      final toCurrency = responseData['coin_receive'] as String;
+      final to = CryptoCurrency.fromString(toCurrency);
+      final inputAddress = responseData['server_address'] as String;
+      final status = responseData['status'] as String;
+      final state = TradeState.deserialize(raw: status);
+      final response_id = responseData['order_id'] as String;
+      final expectedSendAmount = responseData['amount_send'] as String;
+
+      return Trade(
+        id: response_id,
+        from: from,
+        to: to,
+        provider: description,
+        inputAddress: inputAddress,
+        amount: expectedSendAmount,
+        state: state,
+      );
+    } catch (e) {
+      print("error getting trade: ${e.toString()}");
+      throw TradeNotFoundException(
+        id,
+        provider: description,
+        description: e.toString(),
+      );
+    }
+  }
+
+  String _normalizeCurrency(CryptoCurrency currency) {
+    switch (currency) {
+      default:
+        return currency.title.toUpperCase();
+    }
+  }
+
+  String? _networkFor(CryptoCurrency currency) {
+    switch (currency) {
+      case CryptoCurrency.usdt:
+        return "USDT_ERC20";
+      case CryptoCurrency.bnb:
+        return "BNB_BSC";
+      default:
+        return null;
+    }
+  }
+}
diff --git a/lib/exchange/trade.dart b/lib/exchange/trade.dart
index 6cc3fddbe..aeb544ece 100644
--- a/lib/exchange/trade.dart
+++ b/lib/exchange/trade.dart
@@ -5,9 +5,6 @@ import 'package:cw_core/format_amount.dart';
 import 'package:cw_core/hive_type_ids.dart';
 import 'package:hive/hive.dart';
 
-part 'trade.g.dart';
-
-@HiveType(typeId: Trade.typeId)
 class Trade extends HiveObject {
   Trade({
     required this.id,
@@ -32,6 +29,7 @@ class Trade extends HiveObject {
     this.txId,
     this.isRefund,
     this.isSendAll,
+    this.router,
   }) {
     if (provider != null) providerRaw = provider.raw;
 
@@ -121,21 +119,26 @@ class Trade extends HiveObject {
   @HiveField(21)
   bool? isSendAll;
 
+  @HiveField(22)
+  String? router;
+
   static Trade fromMap(Map<String, Object?> map) {
     return Trade(
-        id: map['id'] as String,
-        provider: ExchangeProviderDescription.deserialize(raw: map['provider'] as int),
-        from: CryptoCurrency.deserialize(raw: map['input'] as int),
-        to: CryptoCurrency.deserialize(raw: map['output'] as int),
-        createdAt:
-            map['date'] != null ? DateTime.fromMillisecondsSinceEpoch(map['date'] as int) : null,
-        amount: map['amount'] as String,
-        walletId: map['wallet_id'] as String,
-        fromWalletAddress: map['from_wallet_address'] as String?,
-        memo: map['memo'] as String?,
-        txId: map['tx_id'] as String?,
-        isRefund: map['isRefund'] as bool?,
-        isSendAll: map['isSendAll'] as bool?);
+      id: map['id'] as String,
+      provider: ExchangeProviderDescription.deserialize(raw: map['provider'] as int),
+      from: CryptoCurrency.deserialize(raw: map['input'] as int),
+      to: CryptoCurrency.deserialize(raw: map['output'] as int),
+      createdAt:
+          map['date'] != null ? DateTime.fromMillisecondsSinceEpoch(map['date'] as int) : null,
+      amount: map['amount'] as String,
+      walletId: map['wallet_id'] as String,
+      fromWalletAddress: map['from_wallet_address'] as String?,
+      memo: map['memo'] as String?,
+      txId: map['tx_id'] as String?,
+      isRefund: map['isRefund'] as bool?,
+      isSendAll: map['isSendAll'] as bool?,
+      router: map['router'] as String?,
+    );
   }
 
   Map<String, dynamic> toMap() {
@@ -152,8 +155,111 @@ class Trade extends HiveObject {
       'tx_id': txId,
       'isRefund': isRefund,
       'isSendAll': isSendAll,
+      'router': router,
     };
   }
 
   String amountFormatted() => formatAmount(amount);
 }
+
+class TradeAdapter extends TypeAdapter<Trade> {
+  @override
+  final int typeId = Trade.typeId;
+
+  @override
+  Trade read(BinaryReader reader) {
+    final numOfFields = reader.readByte();
+    final fields = <int, dynamic>{};
+    for (int i = 0; i < numOfFields; i++) {
+      try {
+        fields[reader.readByte()] = reader.read();
+      } catch (_) {}
+    }
+
+    return Trade(
+      id: fields[0] == null ? '' : fields[0] as String,
+      amount: fields[7] == null ? '' : fields[7] as String,
+      createdAt: fields[5] as DateTime?,
+      expiredAt: fields[6] as DateTime?,
+      inputAddress: fields[8] as String?,
+      extraId: fields[9] as String?,
+      outputTransaction: fields[10] as String?,
+      refundAddress: fields[11] as String?,
+      walletId: fields[12] as String?,
+      payoutAddress: fields[13] as String?,
+      password: fields[14] as String?,
+      providerId: fields[15] as String?,
+      providerName: fields[16] as String?,
+      fromWalletAddress: fields[17] as String?,
+      memo: fields[18] as String?,
+      txId: fields[19] as String?,
+      isRefund: fields[20] as bool?,
+      isSendAll: fields[21] as bool?,
+      router: fields[22] as String?,
+    )
+      ..providerRaw = fields[1] == null ? 0 : fields[1] as int
+      ..fromRaw = fields[2] == null ? 0 : fields[2] as int
+      ..toRaw = fields[3] == null ? 0 : fields[3] as int
+      ..stateRaw = fields[4] == null ? '' : fields[4] as String;
+  }
+
+  @override
+  void write(BinaryWriter writer, Trade obj) {
+    writer
+      ..writeByte(23)
+      ..writeByte(0)
+      ..write(obj.id)
+      ..writeByte(1)
+      ..write(obj.providerRaw)
+      ..writeByte(2)
+      ..write(obj.fromRaw)
+      ..writeByte(3)
+      ..write(obj.toRaw)
+      ..writeByte(4)
+      ..write(obj.stateRaw)
+      ..writeByte(5)
+      ..write(obj.createdAt)
+      ..writeByte(6)
+      ..write(obj.expiredAt)
+      ..writeByte(7)
+      ..write(obj.amount)
+      ..writeByte(8)
+      ..write(obj.inputAddress)
+      ..writeByte(9)
+      ..write(obj.extraId)
+      ..writeByte(10)
+      ..write(obj.outputTransaction)
+      ..writeByte(11)
+      ..write(obj.refundAddress)
+      ..writeByte(12)
+      ..write(obj.walletId)
+      ..writeByte(13)
+      ..write(obj.payoutAddress)
+      ..writeByte(14)
+      ..write(obj.password)
+      ..writeByte(15)
+      ..write(obj.providerId)
+      ..writeByte(16)
+      ..write(obj.providerName)
+      ..writeByte(17)
+      ..write(obj.fromWalletAddress)
+      ..writeByte(18)
+      ..write(obj.memo)
+      ..writeByte(19)
+      ..write(obj.txId)
+      ..writeByte(20)
+      ..write(obj.isRefund)
+      ..writeByte(21)
+      ..write(obj.isSendAll)
+      ..writeByte(22)
+      ..write(obj.router);
+  }
+
+  @override
+  int get hashCode => typeId.hashCode;
+
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      other is TradeAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
+}
diff --git a/lib/exchange/trade_state.dart b/lib/exchange/trade_state.dart
index 2c58a96f4..0a196835e 100644
--- a/lib/exchange/trade_state.dart
+++ b/lib/exchange/trade_state.dart
@@ -28,6 +28,7 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
       TradeState(raw: 'waitingAuthorization', title: 'Waiting authorization');
   static const failed = TradeState(raw: 'failed', title: 'Failed');
   static const completed = TradeState(raw: 'completed', title: 'Completed');
+  static const expired = TradeState(raw: 'expired', title: 'Expired');
   static const settling = TradeState(raw: 'settling', title: 'Settlement in progress');
   static const settled = TradeState(raw: 'settled', title: 'Settlement completed');
   static const wait = TradeState(raw: 'wait', title: 'Waiting');
@@ -39,7 +40,33 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
   static const exchanging = TradeState(raw: 'exchanging', title: 'Exchanging');
   static const sending = TradeState(raw: 'sending', title: 'Sending');
   static const success = TradeState(raw: 'success', title: 'Success');
+  
   static TradeState deserialize({required String raw}) {
+
+    switch (raw) {
+      case '1':
+        return unpaid;
+      case '2':
+        return paidUnconfirmed;
+      case '3':
+        return sending;
+      case '4':
+        return confirmed;
+      case '5':
+      case '6':
+        return exchanging;
+      case '7':
+        return sending;
+      case '8':
+        return complete;
+      case '9':
+        return expired;
+      case '10':
+        return underpaid;
+      case '11':
+        return failed;
+    }
+
     switch (raw) {
       case 'NOT_FOUND':
         return notFound;
diff --git a/lib/main.dart b/lib/main.dart
index fa71da31d..eeee4fbc3 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -5,7 +5,6 @@ import 'package:cake_wallet/core/secure_storage.dart';
 import 'package:cake_wallet/entities/language_service.dart';
 import 'package:cake_wallet/buy/order.dart';
 import 'package:cake_wallet/locales/locale.dart';
-import 'package:cake_wallet/store/yat/yat_store.dart';
 import 'package:cake_wallet/utils/device_info.dart';
 import 'package:cake_wallet/utils/exception_handler.dart';
 import 'package:cake_wallet/view_model/link_view_model.dart';
@@ -38,7 +37,6 @@ import 'package:cake_wallet/entities/template.dart';
 import 'package:cake_wallet/exchange/trade.dart';
 import 'package:cake_wallet/exchange/exchange_template.dart';
 import 'package:cake_wallet/src/screens/root/root.dart';
-import 'package:uni_links/uni_links.dart';
 import 'package:cw_core/unspent_coins_info.dart';
 import 'package:cake_wallet/monero/monero.dart';
 import 'package:cw_core/cake_hive.dart';
@@ -46,9 +44,10 @@ import 'package:cw_core/window_size.dart';
 
 final navigatorKey = GlobalKey<NavigatorState>();
 final rootKey = GlobalKey<RootState>();
-final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
+final RouteObserver<PageRoute<dynamic>> routeObserver = RouteObserver<PageRoute<dynamic>>();
 
 Future<void> main() async {
+  bool isAppRunning = false;
   await runZonedGuarded(() async {
     WidgetsFlutterBinding.ensureInitialized();
 
@@ -63,13 +62,42 @@ Future<void> main() async {
     };
 
     await setDefaultMinimumWindowSize();
-    
+
     await CakeHive.close();
 
     await initializeAppConfigs();
 
     runApp(App());
+
+    isAppRunning = true;
   }, (error, stackTrace) async {
+    if (!isAppRunning) {
+      runApp(
+        MaterialApp(
+          debugShowCheckedModeBanner: false,
+          home: Scaffold(
+            body: SingleChildScrollView(
+              child: Container(
+                margin: EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20),
+                child: Column(
+                  children: [
+                    Text(
+                      'Error:\n${error.toString()}',
+                      style: TextStyle(fontSize: 22),
+                    ),
+                    Text(
+                      'Stack trace:\n${stackTrace.toString()}',
+                      style: TextStyle(fontSize: 16),
+                    ),
+                  ],
+                ),
+              ),
+            ),
+          ),
+        ),
+      );
+    }
+
     ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
   });
 }
@@ -229,61 +257,6 @@ class App extends StatefulWidget {
 }
 
 class AppState extends State<App> with SingleTickerProviderStateMixin {
-  AppState() : yatStore = getIt.get<YatStore>();
-
-  YatStore yatStore;
-  StreamSubscription? stream;
-
-  @override
-  void initState() {
-    super.initState();
-    //_handleIncomingLinks();
-    //_handleInitialUri();
-  }
-
-  Future<void> _handleInitialUri() async {
-    try {
-      final uri = await getInitialUri();
-      print('uri: $uri');
-      if (uri == null) {
-        return;
-      }
-      if (!mounted) return;
-      //_fetchEmojiFromUri(uri);
-    } catch (e) {
-      if (!mounted) return;
-      print(e.toString());
-    }
-  }
-
-  void _handleIncomingLinks() {
-    if (!kIsWeb) {
-      stream = getUriLinksStream().listen((Uri? uri) {
-        print('uri: $uri');
-        if (!mounted) return;
-        //_fetchEmojiFromUri(uri);
-      }, onError: (Object error) {
-        if (!mounted) return;
-        print('Error: $error');
-      });
-    }
-  }
-
-  void _fetchEmojiFromUri(Uri uri) {
-    //final queryParameters = uri.queryParameters;
-    //if (queryParameters?.isEmpty ?? true) {
-    //  return;
-    //}
-    //final emoji = queryParameters['eid'];
-    //final refreshToken = queryParameters['refresh_token'];
-    //if ((emoji?.isEmpty ?? true)||(refreshToken?.isEmpty ?? true)) {
-    //  return;
-    //}
-    //yatStore.emoji = emoji;
-    //yatStore.refreshToken = refreshToken;
-    //yatStore.emojiIncommingSC.add(emoji);
-  }
-
   @override
   Widget build(BuildContext context) {
     return Observer(builder: (BuildContext context) {
diff --git a/lib/src/screens/restore/restore_options_page.dart b/lib/src/screens/restore/restore_options_page.dart
index 454d124da..a703c9f9e 100644
--- a/lib/src/screens/restore/restore_options_page.dart
+++ b/lib/src/screens/restore/restore_options_page.dart
@@ -1,3 +1,5 @@
+import 'dart:io';
+
 import 'package:cake_wallet/core/execution_state.dart';
 import 'package:cake_wallet/di.dart';
 import 'package:cake_wallet/generated/i18n.dart';
@@ -13,6 +15,9 @@ import 'package:cake_wallet/utils/responsive_layout_util.dart';
 import 'package:cake_wallet/utils/show_pop_up.dart';
 import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
 import 'package:cake_wallet/view_model/restore/wallet_restore_from_qr_code.dart';
+import 'package:cake_wallet/wallet_type_utils.dart';
+import 'package:cw_core/hardware/device_connection_type.dart';
+import 'package:cw_core/wallet_type.dart';
 import 'package:flutter/material.dart';
 import 'package:permission_handler/permission_handler.dart';
 
@@ -24,6 +29,19 @@ class RestoreOptionsPage extends BasePage {
 
   final bool isNewInstall;
 
+  bool get _doesSupportHardwareWallets {
+    if (!DeviceInfo.instance.isMobile) {
+      return false;
+    }
+
+    if (isMoneroOnly) {
+      return DeviceConnectionType.supportedConnectionTypes(WalletType.monero, Platform.isIOS)
+          .isNotEmpty;
+    }
+
+    return true;
+  }
+
   @override
   Widget body(BuildContext context) {
     final imageColor = Theme.of(context).extension<OptionTileTheme>()!.titleColor;
@@ -57,7 +75,7 @@ class RestoreOptionsPage extends BasePage {
                       description: S.of(context).restore_description_from_backup,
                     ),
                   ),
-                if (DeviceInfo.instance.isMobile)
+                if (_doesSupportHardwareWallets)
                   Padding(
                     padding: EdgeInsets.only(top: 24),
                     child: OptionTile(
diff --git a/lib/src/screens/root/root.dart b/lib/src/screens/root/root.dart
index afdd14865..b6406dfbd 100644
--- a/lib/src/screens/root/root.dart
+++ b/lib/src/screens/root/root.dart
@@ -1,10 +1,7 @@
 import 'dart:async';
 import 'package:cake_wallet/core/auth_service.dart';
 import 'package:cake_wallet/core/totp_request_details.dart';
-import 'package:cake_wallet/generated/i18n.dart';
-import 'package:cake_wallet/reactions/wallet_connect.dart';
 import 'package:cake_wallet/utils/device_info.dart';
-import 'package:cake_wallet/utils/payment_request.dart';
 import 'package:cake_wallet/view_model/link_view_model.dart';
 import 'package:cw_core/wallet_base.dart';
 import 'package:flutter/material.dart';
@@ -13,7 +10,6 @@ import 'package:cake_wallet/src/screens/auth/auth_page.dart';
 import 'package:cake_wallet/store/app_store.dart';
 import 'package:cake_wallet/store/authentication_store.dart';
 import 'package:cake_wallet/entities/qr_scanner.dart';
-import 'package:fluttertoast/fluttertoast.dart';
 import 'package:mobx/mobx.dart';
 import 'package:uni_links/uni_links.dart';
 import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
diff --git a/lib/view_model/exchange/exchange_trade_view_model.dart b/lib/view_model/exchange/exchange_trade_view_model.dart
index 94fec2fa2..c5ce7a591 100644
--- a/lib/view_model/exchange/exchange_trade_view_model.dart
+++ b/lib/view_model/exchange/exchange_trade_view_model.dart
@@ -4,6 +4,7 @@ import 'package:cake_wallet/exchange/exchange_provider_description.dart';
 import 'package:cake_wallet/exchange/provider/changenow_exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/exolix_exchange_provider.dart';
+import 'package:cake_wallet/exchange/provider/quantex_exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/sideshift_exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/simpleswap_exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
@@ -48,6 +49,9 @@ abstract class ExchangeTradeViewModelBase with Store {
       case ExchangeProviderDescription.exolix:
         _provider = ExolixExchangeProvider();
         break;
+      case ExchangeProviderDescription.quantex:
+        _provider = QuantexExchangeProvider();
+        break;
       case ExchangeProviderDescription.thorChain:
         _provider = ThorChainExchangeProvider(tradesStore: trades);
         break;
diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart
index e5533f48a..1560a4be0 100644
--- a/lib/view_model/exchange/exchange_view_model.dart
+++ b/lib/view_model/exchange/exchange_view_model.dart
@@ -30,6 +30,7 @@ import 'package:cake_wallet/exchange/limits_state.dart';
 import 'package:cake_wallet/exchange/provider/changenow_exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/exolix_exchange_provider.dart';
+import 'package:cake_wallet/exchange/provider/quantex_exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/sideshift_exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/simpleswap_exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
@@ -157,6 +158,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
             useTorOnly: _useTorOnly, providerStates: _settingsStore.trocadorProviderStates),
         ThorChainExchangeProvider(tradesStore: trades),
         if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(),
+        QuantexExchangeProvider(),
       ];
 
   @observable
diff --git a/lib/view_model/hardware_wallet/ledger_view_model.dart b/lib/view_model/hardware_wallet/ledger_view_model.dart
index 06ddaf275..f05b1c805 100644
--- a/lib/view_model/hardware_wallet/ledger_view_model.dart
+++ b/lib/view_model/hardware_wallet/ledger_view_model.dart
@@ -1,8 +1,12 @@
+import 'dart:io';
+
 import 'package:cake_wallet/bitcoin/bitcoin.dart';
 import 'package:cake_wallet/ethereum/ethereum.dart';
 import 'package:cake_wallet/generated/i18n.dart';
 import 'package:cake_wallet/polygon/polygon.dart';
 import 'package:cake_wallet/utils/device_info.dart';
+import 'package:cake_wallet/wallet_type_utils.dart';
+import 'package:cw_core/hardware/device_connection_type.dart';
 import 'package:cw_core/wallet_base.dart';
 import 'package:cw_core/wallet_type.dart';
 import 'package:ledger_flutter/ledger_flutter.dart';
@@ -11,8 +15,21 @@ import 'package:permission_handler/permission_handler.dart';
 class LedgerViewModel {
   late final Ledger ledger;
 
+  bool get _doesSupportHardwareWallets {
+    if (!DeviceInfo.instance.isMobile) {
+      return false;
+    }
+
+    if (isMoneroOnly) {
+      return DeviceConnectionType.supportedConnectionTypes(WalletType.monero, Platform.isIOS)
+          .isNotEmpty;
+    }
+
+    return true;
+  }
+
   LedgerViewModel() {
-    if (DeviceInfo.instance.isMobile) {
+    if (_doesSupportHardwareWallets) {
       ledger = Ledger(
         options: LedgerOptions(
           scanMode: ScanMode.balanced,
diff --git a/lib/view_model/trade_details_view_model.dart b/lib/view_model/trade_details_view_model.dart
index 1da322778..c88008982 100644
--- a/lib/view_model/trade_details_view_model.dart
+++ b/lib/view_model/trade_details_view_model.dart
@@ -4,6 +4,7 @@ import 'package:cake_wallet/exchange/exchange_provider_description.dart';
 import 'package:cake_wallet/exchange/provider/changenow_exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/exolix_exchange_provider.dart';
+import 'package:cake_wallet/exchange/provider/quantex_exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/sideshift_exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/simpleswap_exchange_provider.dart';
 import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
@@ -56,6 +57,9 @@ abstract class TradeDetailsViewModelBase with Store {
       case ExchangeProviderDescription.thorChain:
         _provider = ThorChainExchangeProvider(tradesStore: trades);
         break;
+      case ExchangeProviderDescription.quantex:
+        _provider = QuantexExchangeProvider();
+        break;
     }
 
     _updateItems();
@@ -80,6 +84,8 @@ abstract class TradeDetailsViewModelBase with Store {
         return 'https://exolix.com/transaction/${trade.id}';
       case ExchangeProviderDescription.thorChain:
         return 'https://track.ninerealms.com/${trade.id}';
+      case ExchangeProviderDescription.quantex:
+        return 'https://myquantex.com/send/${trade.id}';
     }
     return null;
   }
diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh
index c671a013f..b520a3179 100644
--- a/scripts/android/app_env.sh
+++ b/scripts/android/app_env.sh
@@ -15,15 +15,15 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
 APP_ANDROID_TYPE=$1
 
 MONERO_COM_NAME="Monero.com"
-MONERO_COM_VERSION="1.13.0"
-MONERO_COM_BUILD_NUMBER=86
+MONERO_COM_VERSION="1.13.2"
+MONERO_COM_BUILD_NUMBER=88
 MONERO_COM_BUNDLE_ID="com.monero.app"
 MONERO_COM_PACKAGE="com.monero.app"
 MONERO_COM_SCHEME="monero.com"
 
 CAKEWALLET_NAME="Cake Wallet"
-CAKEWALLET_VERSION="4.16.0"
-CAKEWALLET_BUILD_NUMBER=210
+CAKEWALLET_VERSION="4.16.2"
+CAKEWALLET_BUILD_NUMBER=212
 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
 CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
 CAKEWALLET_SCHEME="cakewallet"
diff --git a/scripts/ios/app_env.sh b/scripts/ios/app_env.sh
index f7887e4bf..f70963745 100644
--- a/scripts/ios/app_env.sh
+++ b/scripts/ios/app_env.sh
@@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
 APP_IOS_TYPE=$1
 
 MONERO_COM_NAME="Monero.com"
-MONERO_COM_VERSION="1.13.0"
-MONERO_COM_BUILD_NUMBER=84
+MONERO_COM_VERSION="1.13.2"
+MONERO_COM_BUILD_NUMBER=86
 MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
 
 CAKEWALLET_NAME="Cake Wallet"
-CAKEWALLET_VERSION="4.16.0"
-CAKEWALLET_BUILD_NUMBER=236
+CAKEWALLET_VERSION="4.16.2"
+CAKEWALLET_BUILD_NUMBER=240
 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
 
 HAVEN_NAME="Haven"
diff --git a/scripts/macos/app_env.sh b/scripts/macos/app_env.sh
index e16df1e61..afdac3e6c 100755
--- a/scripts/macos/app_env.sh
+++ b/scripts/macos/app_env.sh
@@ -16,13 +16,13 @@ if [ -n "$1" ]; then
 fi
 
 MONERO_COM_NAME="Monero.com"
-MONERO_COM_VERSION="1.3.0"
-MONERO_COM_BUILD_NUMBER=17
+MONERO_COM_VERSION="1.3.2"
+MONERO_COM_BUILD_NUMBER=19
 MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
 
 CAKEWALLET_NAME="Cake Wallet"
-CAKEWALLET_VERSION="1.9.0"
-CAKEWALLET_BUILD_NUMBER=71
+CAKEWALLET_VERSION="1.9.2"
+CAKEWALLET_BUILD_NUMBER=73
 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
 
 if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then
diff --git a/tool/utils/secret_key.dart b/tool/utils/secret_key.dart
index 89e4de12d..9559e83b3 100644
--- a/tool/utils/secret_key.dart
+++ b/tool/utils/secret_key.dart
@@ -38,6 +38,7 @@ class SecretKey {
     SecretKey('walletConnectProjectId', () => ''),
     SecretKey('moralisApiKey', () => ''),
     SecretKey('ankrApiKey', () => ''),
+    SecretKey('quantexExchangeMarkup', () => ''),
   ];
 
   static final evmChainsSecrets = [