diff --git a/cw_decred/lib/api/libdcrwallet.dart b/cw_decred/lib/api/libdcrwallet.dart
index fc1c369e0..2166a7f10 100644
--- a/cw_decred/lib/api/libdcrwallet.dart
+++ b/cw_decred/lib/api/libdcrwallet.dart
@@ -216,3 +216,26 @@ String rescanFromHeight(String walletName, String height) {
   );
   return res.payload;
 }
+
+Future<String> signMessageAsync(
+    String name, String message, String address, String walletPass) {
+  final args = <String, String>{
+    "walletname": name,
+    "message": message,
+    "address": address,
+    "walletpass": walletPass,
+  };
+  return compute(signMessage, args);
+}
+
+String signMessage(Map<String, String> args) {
+  final cName = args["walletname"]!.toCString();
+  final cMessage = args["message"]!.toCString();
+  final cAddress = args["address"]!.toCString();
+  final cPass = args["walletpass"]!.toCString();
+  final res = executePayloadFn(
+    fn: () => dcrwalletApi.signMessage(cName, cMessage, cAddress, cPass),
+    ptrsToFree: [cName, cMessage, cAddress, cPass],
+  );
+  return res.payload;
+}
diff --git a/cw_decred/lib/wallet.dart b/cw_decred/lib/wallet.dart
index 38bc44584..d7e4b9f69 100644
--- a/cw_decred/lib/wallet.dart
+++ b/cw_decred/lib/wallet.dart
@@ -450,8 +450,19 @@ abstract class DecredWalletBase extends WalletBase<DecredBalance,
   }
 
   @override
-  String signMessage(String message, {String? address = null}) {
-    return ""; // TODO
+  Future<String> signMessage(String message, {String? address = null}) {
+    if (watchingOnly) {
+      throw "a watching only wallet cannot sign";
+    }
+    var addr = address;
+    if (addr == null) {
+      addr = libdcrwallet.currentReceiveAddress(walletInfo.name);
+    }
+    if (addr == null) {
+      throw "unable to get an address from unsynced wallet";
+    }
+    return libdcrwallet.signMessageAsync(
+        walletInfo.name, message, addr!, _password);
   }
 
   List<Unspent> unspents() {