diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart
index 9bf6f5b97..b908f713c 100644
--- a/cw_core/lib/node.dart
+++ b/cw_core/lib/node.dart
@@ -287,8 +287,20 @@ class Node extends HiveObject with Keyable {
       return false;
     }
   }
-}
 
   Future<bool> requestDecredNode() async {
+  final decredMainnetPort = 9108;
+  if (uri.host == "" && uri.port == decredMainnetPort) {
+    // Just show default port as ok. The wallet will connect to a list of known
+    // nodes automatically.
     return true;
+  }
+  try {
+    final socket = await Socket.connect(uri.host, uri.port, timeout: Duration(seconds: 5));
+      socket.destroy();
+      return true;
+    } catch (_) {
+      return false;
+    }
+  }
 }
diff --git a/cw_decred/lib/api/libdcrwallet.dart b/cw_decred/lib/api/libdcrwallet.dart
index 02c9f0c74..367b0e013 100644
--- a/cw_decred/lib/api/libdcrwallet.dart
+++ b/cw_decred/lib/api/libdcrwallet.dart
@@ -19,11 +19,10 @@ final dcrwalletApi = libdcrwallet(DynamicLibrary.open(libraryName));
 /// a wallet.
 void initLibdcrwallet(String logDir) {
   final cLogDir = logDir.toCString();
-  final res = executePayloadFn(
+  executePayloadFn(
     fn: () => dcrwalletApi.initialize(cLogDir),
     ptrsToFree: [cLogDir],
   );
-  print(res.payload);
 }
 
 /// createWalletAsync calls the libdcrwallet's createWallet function
@@ -46,11 +45,10 @@ void createWalletSync(Map<String, String> args) {
   final password = args["password"]!.toCString();
   final network = "testnet".toCString();
 
-  final res = executePayloadFn(
+  executePayloadFn(
     fn: () => dcrwalletApi.createWallet(name, dataDir, network, password),
     ptrsToFree: [name, dataDir, network, password],
   );
-  print(res.payload);
 }
 
 /// loadWalletAsync calls the libdcrwallet's loadWallet function asynchronously.
@@ -67,15 +65,35 @@ void loadWalletSync(Map<String, String> args) {
   final name = args["name"]!.toCString();
   final dataDir = args["dataDir"]!.toCString();
   final network = "testnet".toCString();
-  final res = executePayloadFn(
+  executePayloadFn(
     fn: () => dcrwalletApi.loadWallet(name, dataDir, network),
     ptrsToFree: [name, dataDir, network],
   );
-  print(res.payload);
+}
+
+Future<void> startSyncAsync({required String name, required String peers}) {
+  final args = <String, String>{
+    "name": name,
+    "peers": peers,
+  };
+  return compute(startSync, args);
+}
+
+void startSync(Map<String, String> args) {
+  final name = args["name"]!.toCString();
+  final peers = args["peers"]!.toCString();
+  executePayloadFn(
+    fn: () => dcrwalletApi.syncWallet(name, peers),
+    ptrsToFree: [name, peers],
+  );
 }
 
 void closeWallet(String walletName) {
-  // TODO.
+  final name = walletName.toCString();
+  executePayloadFn(
+    fn: () => dcrwalletApi.closeWallet(name),
+    ptrsToFree: [name],
+  );
 }
 
 Future<void> changeWalletPassword(
@@ -110,6 +128,15 @@ String? currentReceiveAddress(String walletName) {
   return res.payload;
 }
 
+String syncStatus(String walletName) {
+  final cName = walletName.toCString();
+  final res = executePayloadFn(
+    fn: () => dcrwalletApi.syncWalletStatus(cName),
+    ptrsToFree: [cName],
+  );
+  return res.payload;
+}
+
 Map balance(String walletName) {
   final cName = walletName.toCString();
   final res = executePayloadFn(
diff --git a/cw_decred/lib/wallet.dart b/cw_decred/lib/wallet.dart
index 940c8d737..9cc6b6ab3 100644
--- a/cw_decred/lib/wallet.dart
+++ b/cw_decred/lib/wallet.dart
@@ -1,3 +1,5 @@
+import 'dart:async';
+import 'dart:convert';
 import 'dart:io';
 import 'package:cw_core/transaction_direction.dart';
 import 'package:cw_decred/pending_transaction.dart';
@@ -38,9 +40,10 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance,
   // password is currently only used for seed display, but would likely also be
   // required to sign inputs when creating transactions.
   final String _password;
+  bool connecting = false;
+  String persistantPeer = "";
+  Timer? syncTimer;
 
-  // TODO: Set up a way to change the balance and sync status when dcrlibwallet
-  // changes. Long polling probably?
   @override
   @observable
   SyncStatus syncStatus;
@@ -65,19 +68,138 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance,
 
   Future<void> init() async {
     updateBalance();
-    // TODO: update other wallet properties such as syncStatus, walletAddresses
-    // and transactionHistory with data from libdcrwallet.
   }
 
+  void performBackgroundTasks() {
+    if (!checkSync()) {
+      return;
+    }
+    updateBalance();
+  }
+
+  bool checkSync() {
+    final syncStatusJSON = libdcrwallet.syncStatus(walletInfo.name);
+    final decoded = json.decode(syncStatusJSON);
+
+    final syncStatusCode = decoded["syncstatuscode"] ?? 0;
+    final syncStatusStr = decoded["syncstatus"] ?? "";
+    final targetHeight = decoded["targetheight"] ?? 1;
+    final numPeers = decoded["numpeers"] ?? 0;
+    // final cFiltersHeight = decoded["cfiltersheight"] ?? 0;
+    final headersHeight = decoded["headersheight"] ?? 0;
+    final rescanHeight = decoded["rescanheight"] ?? 0;
+
+    if (numPeers == 0) {
+      syncStatus = NotConnectedSyncStatus();
+      return false;
+    }
+
+    // Sync codes:
+    // NotStarted = 0
+    // FetchingCFilters = 1
+    // FetchingHeaders = 2
+    // DiscoveringAddrs = 3
+    // Rescanning = 4
+    // Complete = 5
+
+    if (syncStatusCode > 4) {
+      syncStatus = SyncedSyncStatus();
+      return true;
+    }
+
+    if (syncStatusCode == 0) {
+      syncStatus = ConnectedSyncStatus();
+      return false;
+    }
+
+    if (syncStatusCode == 1) {
+      syncStatus = SyncingSyncStatus(targetHeight, 0.0);
+      return false;
+    }
+
+    if (syncStatusCode == 2) {
+      final headersProg = headersHeight / targetHeight;
+      // Only allow headers progress to go up half way.
+      syncStatus =
+          SyncingSyncStatus(targetHeight - headersHeight, headersProg / 2);
+      return false;
+    }
+
+    // TODO: This step takes a while so should really get more info to the UI
+    // that we are discovering addresses.
+    if (syncStatusCode == 3) {
+      // Hover at half.
+      syncStatus = SyncingSyncStatus(0, .5);
+      return false;
+    }
+
+    if (syncStatusCode == 4) {
+      // Start at 75%.
+      final rescanProg = rescanHeight / targetHeight / 4;
+      syncStatus =
+          SyncingSyncStatus(targetHeight - rescanHeight, .75 + rescanProg);
+      return false;
+    }
+    return false;
+  }
+
+  @action
   @override
   Future<void> connectToNode({required Node node}) async {
-    //throw UnimplementedError();
+    if (connecting) {
+      throw "decred already connecting";
+    }
+    connecting = true;
+    String addr = "";
+    if (node.uri.host != "") {
+      addr = node.uri.host;
+      if (node.uri.port != "") {
+        addr += ":" + node.uri.port.toString();
+      }
+    }
+    if (addr != persistantPeer) {
+      if (syncTimer != null) {
+        syncTimer!.cancel();
+        syncTimer = null;
+      }
+      persistantPeer = addr;
+      libdcrwallet.closeWallet(walletInfo.name);
+      libdcrwallet.loadWalletSync({
+        "name": walletInfo.name,
+        "dataDir": walletInfo.dirPath,
+      });
+    }
+    await this._startSync();
+    connecting = false;
   }
 
   @action
   @override
   Future<void> startSync() async {
-    // TODO: call libdcrwallet.spvSync() and update syncStatus.
+    if (connecting) {
+      throw "decred already connecting";
+    }
+    connecting = true;
+    await this._startSync();
+    connecting = false;
+  }
+
+  Future<void> _startSync() async {
+    if (syncTimer != null) {
+      return;
+    }
+    try {
+      syncStatus = ConnectingSyncStatus();
+      libdcrwallet.startSyncAsync(
+        name: walletInfo.name,
+        peers: persistantPeer,
+      );
+      syncTimer = Timer.periodic(
+          Duration(seconds: 5), (Timer t) => performBackgroundTasks());
+    } catch (e) {
+      print(e.toString());
+      syncStatus = FailedSyncStatus();
+    }
   }
 
   @override
@@ -134,6 +256,10 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance,
 
   @override
   void close() {
+    if (syncTimer != null) {
+      syncTimer!.cancel();
+      syncTimer = null;
+    }
     libdcrwallet.closeWallet(walletInfo.name);
   }
 
diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart
index 9e06d25da..8d8cb6079 100644
--- a/lib/entities/default_settings_migration.dart
+++ b/lib/entities/default_settings_migration.dart
@@ -45,6 +45,7 @@ const tronDefaultNodeUri = 'api.trongrid.io';
 const newCakeWalletBitcoinUri = 'btc-electrum.cakewallet.com:50002';
 const wowneroDefaultNodeUri = 'node3.monerodevs.org:34568';
 const moneroWorldNodeUri = '.moneroworld.com';
+const decredDefaultUri = ":9108";
 
 Future<void> defaultSettingsMigration(
     {required int version,
@@ -95,6 +96,7 @@ Future<void> defaultSettingsMigration(
               PreferencesKey.currentBalanceDisplayModeKey, BalanceDisplayMode.availableBalance.raw);
           await sharedPreferences.setBool('save_recipient_address', true);
           await resetToDefault(nodes);
+          await setDefaultDecredNodeKey(sharedPreferences, nodes);
           await changeMoneroCurrentNodeToDefault(
               sharedPreferences: sharedPreferences, nodes: nodes);
           await changeBitcoinCurrentElectrumServerToDefault(
@@ -647,6 +649,11 @@ Node? getNanoDefaultNode({required Box<Node> nodes}) {
       nodes.values.firstWhereOrNull((node) => node.type == WalletType.nano);
 }
 
+Node? getDecredDefaultNode({required Box<Node> nodes}) {
+  return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == decredDefaultUri) ??
+      nodes.values.firstWhereOrNull((node) => (node.type == WalletType.decred));
+}
+
 Node? getNanoDefaultPowNode({required Box<Node> nodes}) {
   return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == nanoDefaultPowNodeUri) ??
       nodes.values.firstWhereOrNull((node) => (node.type == WalletType.nano));
@@ -812,6 +819,18 @@ Future<void> rewriteSecureStoragePin({required SecureStorage secureStorage}) asy
   );
 }
 
+// If "node_list.resetToDefault" is called the old node.key will still be set in
+// preferences. Set it to whatever it is now.
+//
+// TODO: There really isn't any reason to have a default node for decred, find
+// a different way to handle this.
+Future<void> setDefaultDecredNodeKey(
+    SharedPreferences sharedPreferences, Box<Node> nodeSource) async {
+  final node = nodeSource.values.firstWhere((node) => node.type == WalletType.decred);
+  await sharedPreferences.setInt(
+      PreferencesKey.currentDecredNodeIdKey, node.key as int);
+}
+
 Future<void> changeBitcoinCurrentElectrumServerToDefault(
     {required SharedPreferences sharedPreferences,
     required Box<Node> nodes,
@@ -1149,6 +1168,7 @@ Future<void> checkCurrentNodes(
   final currentPolygonNodeId = sharedPreferences.getInt(PreferencesKey.currentPolygonNodeIdKey);
   final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
   final currentNanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
+  final currentDecredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
   final currentBitcoinCashNodeId =
       sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
   final currentSolanaNodeId = sharedPreferences.getInt(PreferencesKey.currentSolanaNodeIdKey);
@@ -1168,6 +1188,8 @@ Future<void> checkCurrentNodes(
       nodeSource.values.firstWhereOrNull((node) => node.key == currentPolygonNodeId);
   final currentNanoNodeServer =
       nodeSource.values.firstWhereOrNull((node) => node.key == currentNanoNodeId);
+  final currentDecredNodeServer =
+      nodeSource.values.firstWhereOrNull((node) => node.key == currentDecredNodeId);
   final currentNanoPowNodeServer =
       powNodeSource.values.firstWhereOrNull((node) => node.key == currentNanoPowNodeId);
   final currentBitcoinCashNodeServer =
@@ -1261,6 +1283,14 @@ Future<void> checkCurrentNodes(
     await nodeSource.add(node);
     await sharedPreferences.setInt(PreferencesKey.currentWowneroNodeIdKey, node.key as int);
   }
+
+  if (currentDecredNodeServer == null) {
+    final decredMainnetPort = ":9108";
+    final node = Node(uri: decredDefaultUri, type: WalletType.decred);
+    await nodeSource.add(node);
+    await sharedPreferences.setInt(
+        PreferencesKey.currentDecredNodeIdKey, node.key as int);
+  }
 }
 
 Future<void> resetBitcoinElectrumServer(
diff --git a/lib/entities/node_list.dart b/lib/entities/node_list.dart
index 85e37a7bc..48a54f65b 100644
--- a/lib/entities/node_list.dart
+++ b/lib/entities/node_list.dart
@@ -1,6 +1,7 @@
 import 'package:flutter/services.dart';
 import 'package:hive/hive.dart';
 import "package:yaml/yaml.dart";
+import 'package:shared_preferences/shared_preferences.dart';
 import 'package:cw_core/node.dart';
 import 'package:cw_core/wallet_type.dart';
 
@@ -200,6 +201,12 @@ Future<List<Node>> loadDefaultWowneroNodes() async {
   return nodes;
 }
 
+Future<List<Node>> loadDefaultDecredNodes() async {
+  final decredMainnetPort = ":9108";
+  final node = Node(uri: decredMainnetPort, type: WalletType.decred);
+  return <Node>[node];
+}
+
 Future<void> resetToDefault(Box<Node> nodeSource) async {
   final moneroNodes = await loadDefaultNodes();
   final bitcoinElectrumServerList = await loadBitcoinElectrumServerList();
@@ -211,6 +218,7 @@ Future<void> resetToDefault(Box<Node> nodeSource) async {
   final polygonNodes = await loadDefaultPolygonNodes();
   final solanaNodes = await loadDefaultSolanaNodes();
   final tronNodes = await loadDefaultTronNodes();
+  final decredNodes = await loadDefaultDecredNodes();
 
   final nodes = moneroNodes +
       bitcoinElectrumServerList +
@@ -220,7 +228,9 @@ Future<void> resetToDefault(Box<Node> nodeSource) async {
       bitcoinCashElectrumServerList +
       nanoNodes +
       polygonNodes +
-      solanaNodes + tronNodes;
+      solanaNodes +
+      tronNodes +
+      decredNodes;
 
   await nodeSource.clear();
   await nodeSource.addAll(nodes);
diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart
index 99f0154da..94adb4237 100644
--- a/lib/store/settings_store.dart
+++ b/lib/store/settings_store.dart
@@ -816,11 +816,6 @@ abstract class SettingsStoreBase with Store {
   Node getCurrentNode(WalletType walletType) {
     final node = nodes[walletType];
 
-    // TODO: Implement connecting to a user's preferred node.
-    if (walletType == WalletType.decred) {
-      return Node();
-    }
-
     if (node == null) {
       throw Exception('No node found for wallet type: ${walletType.toString()}');
     }
@@ -1007,6 +1002,7 @@ abstract class SettingsStoreBase with Store {
     final solanaNodeId = sharedPreferences.getInt(PreferencesKey.currentSolanaNodeIdKey);
     final tronNodeId = sharedPreferences.getInt(PreferencesKey.currentTronNodeIdKey);
     final wowneroNodeId = sharedPreferences.getInt(PreferencesKey.currentWowneroNodeIdKey);
+    final decredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
     final moneroNode = nodeSource.get(nodeId);
     final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
     final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
@@ -1015,6 +1011,7 @@ abstract class SettingsStoreBase with Store {
     final polygonNode = nodeSource.get(polygonNodeId);
     final bitcoinCashElectrumServer = nodeSource.get(bitcoinCashElectrumServerId);
     final nanoNode = nodeSource.get(nanoNodeId);
+    final decredNode = nodeSource.get(decredNodeId);
     final nanoPowNode = powNodeSource.get(nanoPowNodeId);
     final solanaNode = nodeSource.get(solanaNodeId);
     final tronNode = nodeSource.get(tronNodeId);
@@ -1100,6 +1097,10 @@ abstract class SettingsStoreBase with Store {
       nodes[WalletType.wownero] = wowneroNode;
     }
 
+    if (decredNode != null) {
+      nodes[WalletType.decred] = decredNode;
+    }
+
     final savedSyncMode = SyncMode.all.firstWhere((element) {
       return element.type.index == (sharedPreferences.getInt(PreferencesKey.syncModeKey) ?? 0);
     });
@@ -1334,6 +1335,11 @@ abstract class SettingsStoreBase with Store {
       priority[WalletType.bitcoinCash] = bitcoinCash!.deserializeBitcoinCashTransactionPriority(
           sharedPreferences.getInt(PreferencesKey.bitcoinCashTransactionPriority)!);
     }
+    if (decred != null &&
+        sharedPreferences.getInt(PreferencesKey.decredTransactionPriority) != null) {
+      priority[WalletType.decred] = decred!.deserializeDecredTransactionPriority(
+          sharedPreferences.getInt(PreferencesKey.decredTransactionPriority)!);
+    }
 
     final generateSubaddresses =
         sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey);
@@ -1442,6 +1448,7 @@ abstract class SettingsStoreBase with Store {
     final solanaNodeId = sharedPreferences.getInt(PreferencesKey.currentSolanaNodeIdKey);
     final tronNodeId = sharedPreferences.getInt(PreferencesKey.currentTronNodeIdKey);
     final wowneroNodeId = sharedPreferences.getInt(PreferencesKey.currentWowneroNodeIdKey);
+    final decredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
     final moneroNode = nodeSource.get(nodeId);
     final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
     final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
@@ -1453,6 +1460,7 @@ abstract class SettingsStoreBase with Store {
     final solanaNode = nodeSource.get(solanaNodeId);
     final tronNode = nodeSource.get(tronNodeId);
     final wowneroNode = nodeSource.get(wowneroNodeId);
+    final decredNode = nodeSource.get(decredNodeId);
     if (moneroNode != null) {
       nodes[WalletType.monero] = moneroNode;
     }
@@ -1497,6 +1505,10 @@ abstract class SettingsStoreBase with Store {
       nodes[WalletType.wownero] = wowneroNode;
     }
 
+    if (decredNode != null) {
+      nodes[WalletType.decred] = decredNode;
+    }
+
     // MIGRATED:
 
     useTOTP2FA = await SecureKey.getBool(
@@ -1633,6 +1645,9 @@ abstract class SettingsStoreBase with Store {
       case WalletType.wownero:
         await _sharedPreferences.setInt(PreferencesKey.currentWowneroNodeIdKey, node.key as int);
         break;
+      case WalletType.decred:
+        await _sharedPreferences.setInt(PreferencesKey.currentDecredNodeIdKey, node.key as int);
+        break;
       default:
         break;
     }
diff --git a/lib/view_model/node_list/node_list_view_model.dart b/lib/view_model/node_list/node_list_view_model.dart
index 2721fd7b3..34e8bdf0d 100644
--- a/lib/view_model/node_list/node_list_view_model.dart
+++ b/lib/view_model/node_list/node_list_view_model.dart
@@ -8,6 +8,8 @@ import 'package:cake_wallet/store/settings_store.dart';
 import 'package:cw_core/node.dart';
 import 'package:cake_wallet/entities/node_list.dart';
 import 'package:cake_wallet/entities/default_settings_migration.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+import 'package:cake_wallet/di.dart';
 import 'package:cw_core/wallet_type.dart';
 
 part 'node_list_view_model.g.dart';
@@ -47,6 +49,9 @@ abstract class NodeListViewModelBase with Store {
 
   Future<void> reset() async {
     await resetToDefault(_nodeSource);
+    final decredNode = getDecredDefaultNode(nodes: _nodeSource)!;
+    final sharedPrefs = getIt.get<SharedPreferences>();
+    await setDefaultDecredNodeKey(sharedPrefs, _nodeSource);
 
     Node node;
 
@@ -88,6 +93,9 @@ abstract class NodeListViewModelBase with Store {
       case WalletType.wownero:
         node = getWowneroDefaultNode(nodes: _nodeSource);
         break;
+      case WalletType.decred:
+        node = decredNode;
+        break;
       default:
         throw Exception('Unexpected wallet type: ${_appStore.wallet!.type}');
     }