diff --git a/lib/models/isar/models/blockchain_data/address.dart b/lib/models/isar/models/blockchain_data/address.dart
index da9ac1bae..584636050 100644
--- a/lib/models/isar/models/blockchain_data/address.dart
+++ b/lib/models/isar/models/blockchain_data/address.dart
@@ -174,7 +174,8 @@ enum AddressType {
   tezos,
   frostMS,
   p2tr,
-  solana;
+  solana,
+  cardanoShelley;
 
   String get readableName {
     switch (this) {
@@ -210,6 +211,8 @@ enum AddressType {
         return "Solana";
       case AddressType.p2tr:
         return "P2TR (taproot)";
+      case AddressType.cardanoShelley:
+        return "Cardano Shelley";
     }
   }
 }
diff --git a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart
index 42836e117..275f7ff0e 100644
--- a/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart
+++ b/lib/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart
@@ -12,6 +12,8 @@ import 'dart:async';
 import 'dart:convert';
 
 import 'package:bip39/bip39.dart' as bip39;
+import 'package:blockchain_utils/bip/bip/bip39/bip39_mnemonic.dart';
+import 'package:blockchain_utils/bip/bip/bip39/bip39_mnemonic_generator.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:flutter_svg/flutter_svg.dart';
@@ -560,6 +562,8 @@ class _NewWalletRecoveryPhraseWarningViewState
                                             wordCount = info
                                                 .coin.defaultSeedPhraseLength;
 
+                                            // TODO: Refactor these to generate each coin in their respective classes
+                                            // This code should not be in a random view page file
                                             if (coin is Monero ||
                                                 coin is Wownero) {
                                               // currently a special case due to the
diff --git a/lib/services/price.dart b/lib/services/price.dart
index dc4f3d8d8..5a97e43cb 100644
--- a/lib/services/price.dart
+++ b/lib/services/price.dart
@@ -30,6 +30,7 @@ class PriceAPI {
     BitcoinFrost: "bitcoin",
     Litecoin: "litecoin",
     Bitcoincash: "bitcoin-cash",
+    Cardano: "cardano",
     Dash: "dash",
     Dogecoin: "dogecoin",
     Epiccash: "epic-cash",
diff --git a/lib/utilities/enums/derive_path_type_enum.dart b/lib/utilities/enums/derive_path_type_enum.dart
index 8981cf1c3..3d64fb45a 100644
--- a/lib/utilities/enums/derive_path_type_enum.dart
+++ b/lib/utilities/enums/derive_path_type_enum.dart
@@ -18,7 +18,8 @@ enum DerivePathType {
   eth,
   eCash44,
   solana,
-  bip86;
+  bip86,
+  cardanoShelley;
 
   AddressType getAddressType() {
     switch (this) {
@@ -41,6 +42,9 @@ enum DerivePathType {
 
       case DerivePathType.bip86:
         return AddressType.p2tr;
+
+      case DerivePathType.cardanoShelley:
+        return AddressType.cardanoShelley;
     }
   }
 }
diff --git a/lib/utilities/test_node_connection.dart b/lib/utilities/test_node_connection.dart
index e3365eda8..458e04e4d 100644
--- a/lib/utilities/test_node_connection.dart
+++ b/lib/utilities/test_node_connection.dart
@@ -4,11 +4,15 @@ import 'dart:io';
 
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:on_chain/ada/ada.dart';
+import 'package:on_chain/ada/src/provider/provider/provider.dart';
+import 'package:socks5_proxy/socks.dart';
 
 import '../networking/http.dart';
 import '../pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart';
 import '../providers/global/prefs_provider.dart';
 import '../services/tor_service.dart';
+import '../wallets/api/cardano/blockfrost_http_provider.dart';
 import '../wallets/api/tezos/tezos_rpc_api.dart';
 import '../wallets/crypto_currency/crypto_currency.dart';
 import '../wallets/crypto_currency/interfaces/electrumx_currency_interface.dart';
@@ -107,7 +111,9 @@ Future<bool> testNodeConnection({
 
     case CryptonoteCurrency():
       try {
-        final proxyInfo = ref.read(prefsChangeNotifierProvider).useTor
+        final proxyInfo = ref
+            .read(prefsChangeNotifierProvider)
+            .useTor
             ? ref.read(pTorService).getProxyInfo()
             : null;
 
@@ -180,7 +186,7 @@ Future<bool> testNodeConnection({
     case Stellar():
       try {
         testPassed =
-            await testStellarNodeConnection(formData.host!, formData.port!);
+        await testStellarNodeConnection(formData.host!, formData.port!);
       } catch (_) {}
       break;
 
@@ -196,7 +202,9 @@ Future<bool> testNodeConnection({
               "action": "version",
             },
           ),
-          proxyInfo: ref.read(prefsChangeNotifierProvider).useTor
+          proxyInfo: ref
+              .read(prefsChangeNotifierProvider)
+              .useTor
               ? ref.read(pTorService).getProxyInfo()
               : null,
         );
@@ -233,6 +241,41 @@ Future<bool> testNodeConnection({
         testPassed = false;
       }
       break;
+
+    case Cardano():
+      try {
+        final client = HttpClient();
+        if (ref
+            .read(prefsChangeNotifierProvider)
+            .useTor) {
+          final proxyInfo = TorService.sharedInstance.getProxyInfo();
+          final proxySettings = ProxySettings(
+            proxyInfo.host,
+            proxyInfo.port,
+          );
+          SocksTCPClient.assignToHttpClient(client, [proxySettings]);
+        }
+        final blockfrostProvider = BlockforestProvider(
+          BlockfrostHttpProvider(
+            url: "${formData.host!}:${formData.port!}/api/v0",
+            client: client,
+          ),
+        );
+
+        final health = await blockfrostProvider.request(
+          BlockfrostRequestBackendHealthStatus(),
+        );
+
+        Logging.instance.log(
+          "Cardano testNodeConnection \"health=$health\"",
+          level: LogLevel.Info,
+        );
+
+        return health;
+      } catch (_) {
+        testPassed = false;
+      }
+      break;
   }
 
   return testPassed;
diff --git a/lib/wallets/api/cardano/blockfrost_http_provider.dart b/lib/wallets/api/cardano/blockfrost_http_provider.dart
new file mode 100644
index 000000000..bf00691a9
--- /dev/null
+++ b/lib/wallets/api/cardano/blockfrost_http_provider.dart
@@ -0,0 +1,53 @@
+import 'dart:convert';
+import 'dart:io';
+import 'package:cbor/simple.dart';
+import 'package:on_chain/ada/src/provider/blockfrost/core/core.dart';
+import 'package:on_chain/ada/src/provider/service/service.dart';
+
+import '../../../utilities/logger.dart';
+
+class BlockfrostHttpProvider implements BlockfrostServiceProvider {
+  BlockfrostHttpProvider({
+    required this.url,
+    this.version = "v0",
+    this.projectId,
+    HttpClient? client,
+    this.defaultRequestTimeout = const Duration(seconds: 30),
+  }) : client = client ?? HttpClient();
+  @override
+  final String url;
+  final String version;
+  final String? projectId;
+  final HttpClient client;
+  final Duration defaultRequestTimeout;
+
+  @override
+  Future<dynamic> get(BlockforestRequestDetails params,
+      [Duration? timeout,]) async {
+    final response = await client.getUrl(Uri.parse(params.url(url, "api/$version"))).timeout(timeout ?? defaultRequestTimeout);
+    response.headers.add("Content-Type", "application/json");
+    response.headers.add("Accept", "application/json");
+    if (projectId != null) {
+      response.headers.add("project_id", projectId!);
+    }
+    final responseStream = await response.close();
+    final data = json.decode(await responseStream.transform(utf8.decoder).join());
+    return data;
+  }
+
+  @override
+  Future<dynamic> post(BlockforestRequestDetails params,
+      [Duration? timeout,]) async {
+    final request = await client.postUrl(Uri.parse(params.url(url, "api/$version"))).timeout(timeout ?? defaultRequestTimeout);
+    // Need to change this for other operations than submitting transactions
+    request.headers.add("Content-Type", "application/cbor");
+    request.headers.add("Accept", "application/json");
+    if (projectId != null) {
+      request.headers.add("project_id", projectId!);
+    }
+    request.add(params.body as List<int>);
+    final response = await request.close();
+    final data = json.decode(await response.transform(utf8.decoder).join());
+    return data;
+  }
+}
diff --git a/lib/wallets/crypto_currency/coins/cardano.dart b/lib/wallets/crypto_currency/coins/cardano.dart
new file mode 100644
index 000000000..e9cf17c65
--- /dev/null
+++ b/lib/wallets/crypto_currency/coins/cardano.dart
@@ -0,0 +1,126 @@
+import '../../../models/isar/models/blockchain_data/address.dart';
+import '../../../models/node_model.dart';
+import '../../../utilities/default_nodes.dart';
+import '../../../utilities/enums/derive_path_type_enum.dart';
+import '../crypto_currency.dart';
+import '../intermediate/bip39_currency.dart';
+
+class Cardano extends Bip39Currency {
+  Cardano(super.network) {
+    _idMain = "cardano";
+    _uriScheme = "cardano";
+    switch (network) {
+      case CryptoCurrencyNetwork.main:
+        _id = _idMain;
+        _name = "Cardano";
+        _ticker = "ADA";
+      default:
+        throw Exception("Unsupported network: $network");
+    }
+  }
+
+  late final String _id;
+
+  @override
+  String get identifier => _id;
+
+  late final String _idMain;
+
+  @override
+  String get mainNetId => _idMain;
+
+  late final String _name;
+
+  @override
+  String get prettyName => _name;
+
+  late final String _uriScheme;
+
+  @override
+  String get uriScheme => _uriScheme;
+
+  late final String _ticker;
+
+  @override
+  String get ticker => _ticker;
+
+  @override
+  AddressType get defaultAddressType => AddressType.cardanoShelley;
+
+  @override
+  Uri defaultBlockExplorer(String txid) {
+    switch (network) {
+      case CryptoCurrencyNetwork.main:
+        return Uri.parse(
+            "https://explorer.cardano.org/en/transaction?id=$txid");
+      default:
+        throw Exception(
+          "Unsupported network for defaultBlockExplorer(): $network",
+        );
+    }
+  }
+
+  @override
+  DerivePathType get defaultDerivePathType => DerivePathType.cardanoShelley;
+
+  @override
+  NodeModel get defaultNode {
+    switch (network) {
+      case CryptoCurrencyNetwork.main:
+        return NodeModel(
+          host: "https://cardano.stackwallet.com",
+          port: 443,
+          name: DefaultNodes.defaultName,
+          id: DefaultNodes.buildId(this),
+          useSSL: true,
+          enabled: true,
+          coinName: identifier,
+          isFailover: true,
+          isDown: false,
+        );
+
+      default:
+        throw Exception("Unsupported network: $network");
+    }
+  }
+
+  @override
+  int get defaultSeedPhraseLength => 15;
+
+  @override
+  int get fractionDigits => 6;
+
+  @override
+  String get genesisHash => "f0f7892b5c333cffc4b3c4344de48af4cc63f55e44936196f365a9ef2244134f";
+
+  @override
+  bool get hasBuySupport => false;
+
+  @override
+  bool get hasMnemonicPassphraseSupport => false;
+
+  @override
+  int get minConfirms => 2;
+
+  @override
+  List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength];
+
+  @override
+  BigInt get satsPerCoin => BigInt.from(1000000);
+
+  @override
+  int get targetBlockTimeSeconds => 20;
+
+  @override
+  bool get torSupport => true;
+
+  @override
+  bool validateAddress(String address) {
+    switch (network) {
+      case CryptoCurrencyNetwork.main:
+        return RegExp(r"^addr1[0-9a-zA-Z]{98}$").hasMatch(address);
+      default:
+        throw Exception("Unsupported network: $network");
+    }
+  }
+}
diff --git a/lib/wallets/crypto_currency/crypto_currency.dart b/lib/wallets/crypto_currency/crypto_currency.dart
index 788c87b4f..074536be6 100644
--- a/lib/wallets/crypto_currency/crypto_currency.dart
+++ b/lib/wallets/crypto_currency/crypto_currency.dart
@@ -6,6 +6,7 @@ export 'coins/banano.dart';
 export 'coins/bitcoin.dart';
 export 'coins/bitcoin_frost.dart';
 export 'coins/bitcoincash.dart';
+export 'coins/cardano.dart';
 export 'coins/dash.dart';
 export 'coins/dogecoin.dart';
 export 'coins/ecash.dart';
diff --git a/lib/wallets/wallet/impl/cardano_wallet.dart b/lib/wallets/wallet/impl/cardano_wallet.dart
new file mode 100644
index 000000000..bf3abfd31
--- /dev/null
+++ b/lib/wallets/wallet/impl/cardano_wallet.dart
@@ -0,0 +1,567 @@
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:blockchain_utils/bip/bip/bip44/base/bip44_base.dart';
+import 'package:blockchain_utils/bip/cardano/bip32/cardano_icarus_bip32.dart';
+import 'package:blockchain_utils/bip/cardano/cip1852/cip1852.dart';
+import 'package:blockchain_utils/bip/cardano/cip1852/conf/cip1852_coins.dart';
+import 'package:blockchain_utils/bip/cardano/mnemonic/cardano_icarus_seed_generator.dart';
+import 'package:blockchain_utils/bip/cardano/shelley/cardano_shelley.dart';
+import 'package:on_chain/ada/ada.dart';
+import 'package:socks5_proxy/socks.dart';
+import '../../../models/balance.dart';
+import '../../../models/isar/models/blockchain_data/address.dart';
+import 'package:tuple/tuple.dart';
+import '../../../models/isar/models/blockchain_data/transaction.dart' as isar;
+import '../../../models/paymint/fee_object_model.dart';
+import '../../../networking/http.dart';
+import '../../../services/tor_service.dart';
+import '../../../utilities/amount/amount.dart';
+import 'package:isar/isar.dart';
+import '../../../utilities/logger.dart';
+import '../../../utilities/prefs.dart';
+import '../../api/cardano/blockfrost_http_provider.dart';
+import '../../crypto_currency/crypto_currency.dart';
+import '../../models/tx_data.dart';
+import '../intermediate/bip39_wallet.dart';
+
+class CardanoWallet extends Bip39Wallet<Cardano> {
+  CardanoWallet(CryptoCurrencyNetwork network) : super(Cardano(network));
+
+  // Source: https://cips.cardano.org/cip/CIP-1852
+  static const String _addressDerivationPath = "m/1852'/1815'/0'/0/0";
+  static final HTTP _httpClient = HTTP();
+
+  BlockforestProvider? blockfrostProvider;
+
+  @override
+  FilterOperation? get changeAddressFilterOperation => null;
+
+  @override
+  FilterOperation? get receivingAddressFilterOperation => null;
+
+  Future<Address> _getAddress() async {
+    final mnemonic = await getMnemonic();
+    final seed = CardanoIcarusSeedGenerator(mnemonic).generate();
+    final cip1852 = Cip1852.fromSeed(seed, Cip1852Coins.cardanoIcarus);
+    final derivationAccount = cip1852.purpose.coin.account(0);
+    final shelley = CardanoShelley.fromCip1852Object(derivationAccount)
+        .change(Bip44Changes.chainExt)
+        .addressIndex(0);
+    final paymentPublicKey = shelley.bip44.publicKey.compressed;
+    final stakePublicKey = shelley.bip44Sk.publicKey.compressed;
+    final addressStr = ADABaseAddress.fromPublicKey(
+      basePubkeyBytes: paymentPublicKey,
+      stakePubkeyBytes: stakePublicKey,
+    ).address;
+    return Address(
+      walletId: walletId,
+      value: addressStr,
+      publicKey: paymentPublicKey,
+      derivationIndex: 0,
+      derivationPath: DerivationPath()..value = _addressDerivationPath,
+      type: AddressType.cardanoShelley,
+      subType: AddressSubType.receiving,
+    );
+  }
+
+  @override
+  Future<void> checkSaveInitialReceivingAddress() async {
+    try {
+      final Address? address = await getCurrentReceivingAddress();
+
+      if (address == null) {
+        final address = await _getAddress();
+
+        await mainDB.updateOrPutAddresses([address]);
+      }
+    } catch (e, s) {
+      Logging.instance.log(
+        "$runtimeType  checkSaveInitialReceivingAddress() failed: $e\n$s",
+        level: LogLevel.Error,
+      );
+    }
+  }
+
+  @override
+  Future<bool> pingCheck() async {
+    try {
+      await updateProvider();
+
+      final health = await blockfrostProvider!.request(
+        BlockfrostRequestBackendHealthStatus(),
+      );
+
+      return Future.value(health);
+    } catch (e, s) {
+      Logging.instance.log(
+        "Error ping checking in cardano_wallet.dart: $e\n$s",
+        level: LogLevel.Error,
+      );
+      return Future.value(false);
+    }
+  }
+
+  @override
+  Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
+    await updateProvider();
+
+    if (info.cachedBalance.spendable.raw == BigInt.zero) {
+      return Amount(
+        rawValue: BigInt.zero,
+        fractionDigits: cryptoCurrency.fractionDigits,
+      );
+    }
+
+    final params = await blockfrostProvider!.request(
+      BlockfrostRequestLatestEpochProtocolParameters(),
+    );
+
+    final fee = params.calculateFee(284);
+
+    return Amount(
+      rawValue: fee,
+      fractionDigits: cryptoCurrency.fractionDigits,
+    );
+  }
+
+  @override
+  Future<FeeObject> get fees async {
+    try {
+      await updateProvider();
+
+      final params = await blockfrostProvider!.request(
+        BlockfrostRequestLatestEpochProtocolParameters(),
+      );
+
+      // 284 is the size of a basic transaction with one input and two outputs (change and recipient)
+      final fee = params.calculateFee(284).toInt();
+
+      return FeeObject(
+          numberOfBlocksFast: 2,
+          numberOfBlocksAverage: 2,
+          numberOfBlocksSlow: 2,
+          fast: fee,
+          medium: fee,
+          slow: fee,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "Error getting fees in cardano_wallet.dart: $e\n$s",
+        level: LogLevel.Error,
+      );
+      rethrow;
+    }
+  }
+
+  @override
+  Future<TxData> prepareSend({required TxData txData}) async {
+    try {
+      await updateProvider();
+
+      if (txData.amount!.raw < ADAHelper.toLovelaces("1")) {
+        throw Exception("By network rules, you can send minimum 1 ADA");
+      }
+
+      final utxos = await blockfrostProvider!.request(
+        BlockfrostRequestAddressUTXOsOfAGivenAsset(
+          address: ADAAddress.fromAddress(
+            (await getCurrentReceivingAddress())!.value,
+          ),
+          asset: "lovelace",
+        ),
+      );
+
+      var leftAmountForUtxos = txData.amount!.raw;
+      final listOfUtxosToBeUsed = <ADAAccountUTXOResponse>[];
+      var totalBalance = BigInt.zero;
+
+      for (final utxo in utxos) {
+        if (!(leftAmountForUtxos <= BigInt.parse("0"))) {
+          leftAmountForUtxos -= BigInt.parse(utxo.amount.first.quantity);
+          listOfUtxosToBeUsed.add(utxo);
+        }
+        totalBalance += BigInt.parse(utxo.amount.first.quantity);
+      }
+
+      if (leftAmountForUtxos > BigInt.parse("0") || totalBalance < txData.amount!.raw) {
+        throw Exception("Insufficient balance");
+      }
+
+      final bip32 = CardanoIcarusBip32.fromSeed(CardanoIcarusSeedGenerator(await getMnemonic()).generate());
+      final spend = bip32.derivePath("1852'/1815'/0'/0/0");
+      final privateKey = AdaPrivateKey.fromBytes(spend.privateKey.raw);
+
+      // Calculate fees with example tx
+      final exampleFee = ADAHelper.toLovelaces("0.10");
+      final change = TransactionOutput(address: ADABaseAddress((await getCurrentReceivingAddress())!.value), amount: Value(coin: totalBalance - (txData.amount!.raw)));
+      final body = TransactionBody(
+        inputs: listOfUtxosToBeUsed.map((e) => TransactionInput(transactionId: TransactionHash.fromHex(e.txHash), index: e.outputIndex)).toList(),
+        outputs: [change, TransactionOutput(address: ADABaseAddress(txData.recipients!.first.address), amount: Value(coin: txData.amount!.raw - exampleFee))],
+        fee: exampleFee,
+      );
+      final exampleTx = ADATransaction(
+          body: body,
+          witnessSet: TransactionWitnessSet(vKeys: [
+            privateKey.createSignatureWitness(body.toHash().data),
+          ],)
+        ,);
+      final params = await blockfrostProvider!.request(BlockfrostRequestLatestEpochProtocolParameters());
+      final fee = params.calculateFee(exampleTx.size);
+
+      // Check if we are sending all balance, which means no change and only one output for recipient.
+      if (totalBalance == txData.amount!.raw) {
+        final List<TxRecipient> newRecipients = [(
+        address: txData.recipients!.first.address,
+        amount: Amount(
+          rawValue: txData.amount!.raw - fee,
+          fractionDigits: cryptoCurrency.fractionDigits,
+        ),
+        isChange: txData.recipients!.first.isChange,
+        ),];
+        return txData.copyWith(
+          fee: Amount(
+            rawValue: fee,
+            fractionDigits: cryptoCurrency.fractionDigits,
+          ),
+          recipients: newRecipients,
+        );
+      } else {
+        if (txData.amount!.raw + fee > totalBalance) {
+          throw Exception("Insufficient balance for fee");
+        }
+
+        // Minimum change in Cardano is 1 ADA and we need to have enough balance for that
+        if (totalBalance - (txData.amount!.raw + fee) < ADAHelper.toLovelaces("1")) {
+          throw Exception("Not enough balance for change. By network rules, please either send all balance or leave at least 1 ADA change.");
+        }
+
+        return txData.copyWith(
+          fee: Amount(
+            rawValue: fee,
+            fractionDigits: cryptoCurrency.fractionDigits,
+          ),
+        );
+      }
+    } catch (e, s) {
+      Logging.instance.log(
+        "$runtimeType Cardano prepareSend failed: $e\n$s",
+        level: LogLevel.Error,
+      );
+      rethrow;
+    }
+  }
+
+  @override
+  Future<TxData> confirmSend({required TxData txData}) async {
+    try {
+      await updateProvider();
+
+      final utxos = await blockfrostProvider!.request(
+        BlockfrostRequestAddressUTXOsOfAGivenAsset(
+          address: ADAAddress.fromAddress(
+            (await getCurrentReceivingAddress())!.value,
+          ),
+          asset: "lovelace",
+        ),
+      );
+
+
+      var leftAmountForUtxos = txData.amount!.raw + txData.fee!.raw;
+      final listOfUtxosToBeUsed = <ADAAccountUTXOResponse>[];
+      var totalBalance = BigInt.zero;
+
+      for (final utxo in utxos) {
+        if (!(leftAmountForUtxos <= BigInt.parse("0"))) {
+          leftAmountForUtxos -= BigInt.parse(utxo.amount.first.quantity);
+          listOfUtxosToBeUsed.add(utxo);
+        }
+        totalBalance += BigInt.parse(utxo.amount.first.quantity);
+      }
+
+      var totalUtxoAmount = BigInt.zero;
+
+      for (final utxo in listOfUtxosToBeUsed) {
+        totalUtxoAmount += BigInt.parse(utxo.amount.first.quantity);
+      }
+
+      final bip32 = CardanoIcarusBip32.fromSeed(CardanoIcarusSeedGenerator(await getMnemonic()).generate());
+      final spend = bip32.derivePath("1852'/1815'/0'/0/0");
+      final privateKey = AdaPrivateKey.fromBytes(spend.privateKey.raw);
+
+      final change = TransactionOutput(address: ADABaseAddress((await getCurrentReceivingAddress())!.value), amount: Value(coin: totalUtxoAmount - (txData.amount!.raw + txData.fee!.raw)));
+      List<TransactionOutput> outputs = [];
+      if (totalBalance == (txData.amount!.raw + txData.fee!.raw)) {
+        outputs = [TransactionOutput(address: ADABaseAddress(txData.recipients!.first.address), amount: Value(coin: txData.amount!.raw))];
+      } else {
+        outputs = [change, TransactionOutput(address: ADABaseAddress(txData.recipients!.first.address), amount: Value(coin: txData.amount!.raw))];
+      }
+      final body = TransactionBody(
+        inputs: listOfUtxosToBeUsed.map((e) => TransactionInput(transactionId: TransactionHash.fromHex(e.txHash), index: e.outputIndex)).toList(),
+        outputs: outputs,
+        fee: txData.fee!.raw,
+      );
+      final tx = ADATransaction(
+          body: body,
+          witnessSet: TransactionWitnessSet(vKeys: [
+            privateKey.createSignatureWitness(body.toHash().data),
+          ],)
+        ,);
+
+      final sentTx = await blockfrostProvider!.request(BlockfrostRequestSubmitTransaction(
+          transactionCborBytes: tx.serialize(),),);
+      return txData.copyWith(
+        txid: sentTx,
+      );
+    } catch (e, s) {
+      Logging.instance.log(
+        "$runtimeType Cardano confirmSend failed: $e\n$s",
+        level: LogLevel.Error,
+      );
+      rethrow;
+    }
+  }
+
+  @override
+  Future<void> recover({required bool isRescan}) async {
+    await refreshMutex.protect(() async {
+      final addressStruct = await _getAddress();
+
+      await mainDB.updateOrPutAddresses([addressStruct]);
+
+      if (info.cachedReceivingAddress != addressStruct.value) {
+        await info.updateReceivingAddress(
+          newAddress: addressStruct.value,
+          isar: mainDB.isar,
+        );
+      }
+
+      await Future.wait([
+        updateBalance(),
+        updateChainHeight(),
+        updateTransactions(),
+      ]);
+    });
+  }
+
+  @override
+  Future<void> updateBalance() async {
+    try {
+      await updateProvider();
+
+      final addressUtxos = await blockfrostProvider!.request(
+        BlockfrostRequestAddressUTXOsOfAGivenAsset(
+          address: ADAAddress.fromAddress(
+            (await getCurrentReceivingAddress())!.value,
+          ),
+          asset: "lovelace",
+        ),
+      );
+
+      BigInt totalBalanceInLovelace = BigInt.parse("0");
+      for (final utxo in addressUtxos) {
+        totalBalanceInLovelace += BigInt.parse(utxo.amount.first.quantity);
+      }
+
+      final balance = Balance(
+        total: Amount(
+            rawValue: totalBalanceInLovelace,
+            fractionDigits: cryptoCurrency.fractionDigits,),
+        spendable: Amount(
+            rawValue: totalBalanceInLovelace,
+            fractionDigits: cryptoCurrency.fractionDigits,),
+        blockedTotal: Amount(
+          rawValue: BigInt.zero,
+          fractionDigits: cryptoCurrency.fractionDigits,
+        ),
+        pendingSpendable: Amount(
+          rawValue: BigInt.zero,
+          fractionDigits: cryptoCurrency.fractionDigits,
+        ),
+      );
+
+      await info.updateBalance(newBalance: balance, isar: mainDB.isar);
+    } catch (e, s) {
+      Logging.instance.log(
+        "Error getting balance in cardano_wallet.dart: $e\n$s",
+        level: LogLevel.Error,
+      );
+    }
+  }
+
+  @override
+  Future<void> updateChainHeight() async {
+    try {
+      await updateProvider();
+
+      final latestBlock = await blockfrostProvider!.request(
+        BlockfrostRequestLatestBlock(),
+      );
+
+      await info.updateCachedChainHeight(
+          newHeight: latestBlock.height == null ? 0 : latestBlock.height!,
+          isar: mainDB.isar,);
+    } catch (e, s) {
+      Logging.instance.log(
+        "Error updating transactions in cardano_wallet.dart: $e\n$s",
+        level: LogLevel.Error,
+      );
+    }
+  }
+
+  @override
+  Future<void> updateNode() async {
+    await refresh();
+  }
+
+  @override
+  Future<void> updateTransactions() async {
+    try {
+      await updateProvider();
+
+      final currentAddr = (await getCurrentReceivingAddress())!.value;
+
+      final txsList = await blockfrostProvider!.request(
+        BlockfrostRequestAddressTransactions(
+          ADAAddress.fromAddress(
+            currentAddr,
+          ),
+        ),
+      );
+
+      final parsedTxsList =
+          List<Tuple2<isar.Transaction, Address>>.empty(growable: true);
+
+      for (final tx in txsList) {
+        final txInfo = await blockfrostProvider!.request(
+          BlockfrostRequestSpecificTransaction(tx.txHash),
+        );
+        final utxoInfo = await blockfrostProvider!.request(
+          BlockfrostRequestTransactionUTXOs(tx.txHash),
+        );
+        var txType = isar.TransactionType.unknown;
+
+        for (final input in utxoInfo.inputs) {
+          if (input.address == currentAddr) {
+            txType = isar.TransactionType.outgoing;
+          }
+        }
+
+        if (txType == isar.TransactionType.outgoing) {
+          var isSelfTx = true;
+          for (final output in utxoInfo.outputs) {
+            if (output.address != currentAddr) {
+              isSelfTx = false;
+            }
+          }
+          if (isSelfTx) {
+            txType = isar.TransactionType.sentToSelf;
+          }
+        }
+
+        if (txType == isar.TransactionType.unknown) {
+          for (final output in utxoInfo.outputs) {
+            if (output.address == currentAddr) {
+              txType = isar.TransactionType.incoming;
+            }
+          }
+        }
+
+        var receiverAddr = "Unknown?";
+        var amount = 0;
+
+        if (txType == isar.TransactionType.incoming) {
+          receiverAddr = currentAddr;
+          for (final output in utxoInfo.outputs) {
+            if (output.address == currentAddr && output.amount.first.unit == "lovelace") {
+              amount += int.parse(output.amount.first.quantity);
+            }
+          }
+        } else if (txType == isar.TransactionType.outgoing) {
+          for (final output in utxoInfo.outputs) {
+            if (output.address != currentAddr && output.amount.first.unit == "lovelace") {
+              receiverAddr = output.address;
+              amount += int.parse(output.amount.first.quantity);
+            }
+          }
+        } else if (txType == isar.TransactionType.sentToSelf) {
+          receiverAddr = currentAddr;
+          for (final output in utxoInfo.outputs) {
+            if (output.amount.first.unit == "lovelace") {
+              amount += int.parse(output.amount.first.quantity);
+            }
+          }
+        }
+
+        final transaction = isar.Transaction(
+          walletId: walletId,
+          txid: txInfo.hash,
+          timestamp: tx.blockTime,
+          type: txType,
+          subType: isar.TransactionSubType.none,
+          amount: amount,
+          amountString: Amount(
+            rawValue: BigInt.from(amount),
+            fractionDigits: cryptoCurrency.fractionDigits,
+          ).toJsonString(),
+          fee: int.parse(txInfo.fees),
+          height: txInfo.blockHeight,
+          isCancelled: false,
+          isLelantus: false,
+          slateId: null,
+          otherData: null,
+          inputs: [],
+          outputs: [],
+          nonce: null,
+          numberOfMessages: 0,
+        );
+
+        final txAddress = Address(
+          walletId: walletId,
+          value: receiverAddr,
+          publicKey: List<int>.empty(),
+          derivationIndex: 0,
+          derivationPath: DerivationPath()..value = _addressDerivationPath,
+          type: AddressType.cardanoShelley,
+          subType: txType == isar.TransactionType.outgoing
+              ? AddressSubType.unknown
+              : AddressSubType.receiving,
+        );
+
+        parsedTxsList.add(Tuple2(transaction, txAddress));
+      }
+
+      await mainDB.addNewTransactionData(parsedTxsList, walletId);
+    } catch (e, s) {
+      Logging.instance.log(
+        "Error updating transactions in cardano_wallet.dart: $e\n$s",
+        level: LogLevel.Error,
+      );
+    }
+  }
+
+  @override
+  Future<bool> updateUTXOs() async {
+    // TODO: implement updateUTXOs
+    return false;
+  }
+
+  Future<void> updateProvider() async {
+    final currentNode = getCurrentNode();
+    final client = HttpClient();
+    if (prefs.useTor) {
+      final proxyInfo = TorService.sharedInstance.getProxyInfo();
+      final proxySettings = ProxySettings(
+        proxyInfo.host,
+        proxyInfo.port,
+      );
+      SocksTCPClient.assignToHttpClient(client, [proxySettings]);
+    }
+    blockfrostProvider = BlockforestProvider(
+      BlockfrostHttpProvider(
+        url: "${currentNode.host}:${currentNode.port}/",
+        client: client,
+      ),
+    );
+  }
+}
diff --git a/lib/wallets/wallet/wallet.dart b/lib/wallets/wallet/wallet.dart
index 4837eb8d3..1e711f19d 100644
--- a/lib/wallets/wallet/wallet.dart
+++ b/lib/wallets/wallet/wallet.dart
@@ -28,6 +28,7 @@ import 'impl/banano_wallet.dart';
 import 'impl/bitcoin_frost_wallet.dart';
 import 'impl/bitcoin_wallet.dart';
 import 'impl/bitcoincash_wallet.dart';
+import 'impl/cardano_wallet.dart';
 import 'impl/dash_wallet.dart';
 import 'impl/dogecoin_wallet.dart';
 import 'impl/ecash_wallet.dart';
@@ -324,6 +325,9 @@ abstract class Wallet<T extends CryptoCurrency> {
       case const (Bitcoincash):
         return BitcoincashWallet(net);
 
+      case const (Cardano):
+        return CardanoWallet(net);
+
       case const (Dash):
         return DashWallet(net);
 
diff --git a/pubspec.lock b/pubspec.lock
index 29b88e8a9..ea4a3943e 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -155,6 +155,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.1.0"
+  blockchain_utils:
+    dependency: "direct main"
+    description:
+      name: blockchain_utils
+      sha256: aebc3a32b927b34f638817c4bfdb85f86a97e6ad35f0cd962660b0c6e8d5c56b
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.3.0"
   boolean_selector:
     dependency: transitive
     description:
@@ -527,10 +535,10 @@ packages:
     dependency: "direct main"
     description:
       name: device_info_plus
-      sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074
+      sha256: "77f757b789ff68e4eaf9c56d1752309bd9f7ad557cb105b938a7f8eb89e59110"
       url: "https://pub.dev"
     source: hosted
-    version: "10.1.2"
+    version: "9.1.2"
   device_info_plus_platform_interface:
     dependency: transitive
     description:
@@ -1118,18 +1126,18 @@ packages:
     dependency: transitive
     description:
       name: leak_tracker
-      sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
+      sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
       url: "https://pub.dev"
     source: hosted
-    version: "10.0.5"
+    version: "10.0.4"
   leak_tracker_flutter_testing:
     dependency: transitive
     description:
       name: leak_tracker_flutter_testing
-      sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
+      sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.5"
+    version: "3.0.3"
   leak_tracker_testing:
     dependency: transitive
     description:
@@ -1229,10 +1237,10 @@ packages:
     dependency: transitive
     description:
       name: material_color_utilities
-      sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
+      sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
       url: "https://pub.dev"
     source: hosted
-    version: "0.11.1"
+    version: "0.8.0"
   memoize:
     dependency: transitive
     description:
@@ -1245,10 +1253,10 @@ packages:
     dependency: "direct main"
     description:
       name: meta
-      sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
+      sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
       url: "https://pub.dev"
     source: hosted
-    version: "1.15.0"
+    version: "1.12.0"
   mime:
     dependency: transitive
     description:
@@ -1338,6 +1346,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.0.2"
+  on_chain:
+    dependency: "direct main"
+    description:
+      name: on_chain
+      sha256: "4040c187be82f6f6414110139f6e70fe304f23f63111c3ee60438c539b1a1dce"
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.0.1"
   package_config:
     dependency: transitive
     description:
@@ -1486,18 +1502,18 @@ packages:
     dependency: "direct overridden"
     description:
       name: pinenacl
-      sha256: "57e907beaacbc3c024a098910b6240758e899674de07d6949a67b52fd984cbdf"
+      sha256: e5fb0bce1717b7f136f35ee98b5c02b3e6383211f8a77ca882fa7812232a07b9
       url: "https://pub.dev"
     source: hosted
-    version: "0.6.0"
+    version: "0.3.4"
   platform:
     dependency: transitive
     description:
       name: platform
-      sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
+      sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.5"
+    version: "3.1.4"
   plugin_platform_interface:
     dependency: transitive
     description:
@@ -1854,32 +1870,32 @@ packages:
     dependency: transitive
     description:
       name: test
-      sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e"
+      sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073"
       url: "https://pub.dev"
     source: hosted
-    version: "1.25.7"
+    version: "1.25.2"
   test_api:
     dependency: transitive
     description:
       name: test_api
-      sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
+      sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
       url: "https://pub.dev"
     source: hosted
-    version: "0.7.2"
+    version: "0.7.0"
   test_core:
     dependency: transitive
     description:
       name: test_core
-      sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696"
+      sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4"
       url: "https://pub.dev"
     source: hosted
-    version: "0.6.4"
+    version: "0.6.0"
   tezart:
     dependency: "direct main"
     description:
       path: "."
-      ref: d000cc245e51d3ff50e6467960fb3d9159d5b2a9
-      resolved-ref: d000cc245e51d3ff50e6467960fb3d9159d5b2a9
+      ref: "13fa937ea9a9fc34caf047e068df9535f65c27ad"
+      resolved-ref: "13fa937ea9a9fc34caf047e068df9535f65c27ad"
       url: "https://github.com/cypherstack/tezart.git"
     source: git
     version: "2.0.5"
@@ -2072,7 +2088,7 @@ packages:
     dependency: transitive
     description:
       name: vm_service
-      sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
+      sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
       url: "https://pub.dev"
     source: hosted
     version: "14.2.5"
@@ -2174,7 +2190,7 @@ packages:
     source: hosted
     version: "1.2.1"
   win32:
-    dependency: "direct overridden"
+    dependency: transitive
     description:
       name: win32
       sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a"
diff --git a/scripts/app_config/configure_stack_wallet.sh b/scripts/app_config/configure_stack_wallet.sh
index 7f7c51ab7..6f4a87981 100755
--- a/scripts/app_config/configure_stack_wallet.sh
+++ b/scripts/app_config/configure_stack_wallet.sh
@@ -57,6 +57,7 @@ final List<CryptoCurrency> _supportedCoins = List.unmodifiable([
   Banano(CryptoCurrencyNetwork.main),
   Bitcoincash(CryptoCurrencyNetwork.main),
   BitcoinFrost(CryptoCurrencyNetwork.main),
+  Cardano(CryptoCurrencyNetwork.main),
   Dash(CryptoCurrencyNetwork.main),
   Dogecoin(CryptoCurrencyNetwork.main),
   Ecash(CryptoCurrencyNetwork.main),
diff --git a/scripts/app_config/templates/pubspec.template b/scripts/app_config/templates/pubspec.template
index b54ea0ba5..997ee09ed 100644
--- a/scripts/app_config/templates/pubspec.template
+++ b/scripts/app_config/templates/pubspec.template
@@ -204,6 +204,8 @@ dependencies:
       path: packages/camera/camera_windows
   camera_platform_interface: ^2.8.0
   camera_macos: ^0.0.8
+  blockchain_utils: ^3.3.0
+  on_chain: ^4.0.1
 
 dev_dependencies:
   flutter_test: