diff --git a/lib/db/sqlite/firo_cache.dart b/lib/db/sqlite/firo_cache.dart
index 6b3c70c8e..d32db1bf3 100644
--- a/lib/db/sqlite/firo_cache.dart
+++ b/lib/db/sqlite/firo_cache.dart
@@ -31,7 +31,7 @@ void _debugLog(Object? object) {
 }
 
 abstract class _FiroCache {
-  static const int _setCacheVersion = 1;
+  static const int _setCacheVersion = 2;
   static const int _tagsCacheVersion = 2;
 
   static final networks = [
@@ -43,17 +43,12 @@ abstract class _FiroCache {
       network == CryptoCurrencyNetwork.main
           ? "spark_set_v$_setCacheVersion.sqlite3"
           : "spark_set_v${_setCacheVersion}_${network.name}.sqlite3";
-  static String sparkSetMetaCacheFileName(CryptoCurrencyNetwork network) =>
-      network == CryptoCurrencyNetwork.main
-          ? "spark_set_meta_v$_setCacheVersion.sqlite3"
-          : "spark_set_meta_v${_setCacheVersion}_${network.name}.sqlite3";
   static String sparkUsedTagsCacheFileName(CryptoCurrencyNetwork network) =>
       network == CryptoCurrencyNetwork.main
           ? "spark_tags_v$_tagsCacheVersion.sqlite3"
           : "spark_tags_v${_tagsCacheVersion}_${network.name}.sqlite3";
 
   static final Map<CryptoCurrencyNetwork, Database> _setCacheDB = {};
-  static final Map<CryptoCurrencyNetwork, Database> _setMetaCacheDB = {};
   static final Map<CryptoCurrencyNetwork, Database> _usedTagsCacheDB = {};
   static Database setCacheDB(CryptoCurrencyNetwork network) {
     if (_setCacheDB[network] == null) {
@@ -64,15 +59,6 @@ abstract class _FiroCache {
     return _setCacheDB[network]!;
   }
 
-  static Database setMetaCacheDB(CryptoCurrencyNetwork network) {
-    if (_setMetaCacheDB[network] == null) {
-      throw Exception(
-        "FiroCache.init() must be called before accessing FiroCache.db!",
-      );
-    }
-    return _setMetaCacheDB[network]!;
-  }
-
   static Database usedTagsCacheDB(CryptoCurrencyNetwork network) {
     if (_usedTagsCacheDB[network] == null) {
       throw Exception(
@@ -93,18 +79,12 @@ abstract class _FiroCache {
       final sparkSetCacheFile =
           File("${sqliteDir.path}/${sparkSetCacheFileName(network)}");
 
-      final sparkSetMetaCacheFile =
-          File("${sqliteDir.path}/${sparkSetMetaCacheFileName(network)}");
-
       final sparkUsedTagsCacheFile =
           File("${sqliteDir.path}/${sparkUsedTagsCacheFileName(network)}");
 
       if (!(await sparkSetCacheFile.exists())) {
         await _createSparkSetCacheDb(sparkSetCacheFile.path);
       }
-      if (!(await sparkSetMetaCacheFile.exists())) {
-        await _createSparkSetMetaCacheDb(sparkSetMetaCacheFile.path);
-      }
       if (!(await sparkUsedTagsCacheFile.exists())) {
         await _createSparkUsedTagsCacheDb(sparkUsedTagsCacheFile.path);
       }
@@ -113,10 +93,6 @@ abstract class _FiroCache {
         sparkSetCacheFile.path,
         mode: OpenMode.readWrite,
       );
-      _setMetaCacheDB[network] = sqlite3.open(
-        sparkSetMetaCacheFile.path,
-        mode: OpenMode.readWrite,
-      );
       _usedTagsCacheDB[network] = sqlite3.open(
         sparkUsedTagsCacheFile.path,
         mode: OpenMode.readWrite,
@@ -134,12 +110,6 @@ abstract class _FiroCache {
         VACUUM;
       """,
     );
-    setMetaCacheDB(network).execute(
-      """
-        DELETE FROM PreviousMetaFetchResult;
-        VACUUM;
-      """,
-    );
     usedTagsCacheDB(network).execute(
       """
         DELETE FROM SparkUsedCoinTags;
@@ -165,7 +135,7 @@ abstract class _FiroCache {
           blockHash TEXT NOT NULL,
           setHash TEXT NOT NULL,
           groupId INTEGER NOT NULL,
-          timestampUTC INTEGER NOT NULL,
+          size INTEGER NOT NULL,
           UNIQUE (blockHash, setHash, groupId)
         );
         
@@ -174,7 +144,8 @@ abstract class _FiroCache {
           serialized TEXT NOT NULL,
           txHash TEXT NOT NULL,
           context TEXT NOT NULL,
-          UNIQUE(serialized, txHash, context)
+          groupId INTEGER NOT NULL,
+          UNIQUE(serialized, txHash, context, groupId)
         );
         
         CREATE TABLE SparkSetCoins (
@@ -190,27 +161,6 @@ abstract class _FiroCache {
     db.dispose();
   }
 
-  static Future<void> _createSparkSetMetaCacheDb(String file) async {
-    final db = sqlite3.open(
-      file,
-      mode: OpenMode.readWriteCreate,
-    );
-
-    db.execute(
-      """
-        CREATE TABLE PreviousMetaFetchResult (
-          id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
-          coinGroupId INTEGER NOT NULL UNIQUE,
-          blockHash TEXT NOT NULL,
-          setHash TEXT NOT NULL,
-          size INTEGER NOT NULL
-        );
-      """,
-    );
-
-    db.dispose();
-  }
-
   static Future<void> _createSparkUsedTagsCacheDb(String file) async {
     final db = sqlite3.open(
       file,
diff --git a/lib/db/sqlite/firo_cache_coordinator.dart b/lib/db/sqlite/firo_cache_coordinator.dart
index 45fa4c62e..038668248 100644
--- a/lib/db/sqlite/firo_cache_coordinator.dart
+++ b/lib/db/sqlite/firo_cache_coordinator.dart
@@ -32,9 +32,6 @@ abstract class FiroCacheCoordinator {
     final setCacheFile = File(
       "${dir.path}/${_FiroCache.sparkSetCacheFileName(network)}",
     );
-    final setMetaCacheFile = File(
-      "${dir.path}/${_FiroCache.sparkSetMetaCacheFileName(network)}",
-    );
     final usedTagsCacheFile = File(
       "${dir.path}/${_FiroCache.sparkUsedTagsCacheFileName(network)}",
     );
@@ -44,8 +41,6 @@ abstract class FiroCacheCoordinator {
     final tagsSize = (await usedTagsCacheFile.exists())
         ? await usedTagsCacheFile.length()
         : 0;
-    final setMetaSize =
-        (await setMetaCacheFile.exists()) ? await setMetaCacheFile.length() : 0;
 
     Logging.instance.log(
       "Spark cache used tags size: $tagsSize",
@@ -55,12 +50,8 @@ abstract class FiroCacheCoordinator {
       "Spark cache anon set size: $setSize",
       level: LogLevel.Debug,
     );
-    Logging.instance.log(
-      "Spark cache set meta size: $setMetaSize",
-      level: LogLevel.Debug,
-    );
 
-    final int bytes = tagsSize + setSize + setMetaSize;
+    final int bytes = tagsSize + setSize;
 
     if (bytes < 1024) {
       return '$bytes B';
@@ -104,93 +95,70 @@ abstract class FiroCacheCoordinator {
     void Function(int countFetched, int totalCount)? progressUpdated,
   ) async {
     await _setLocks[network]!.protect(() async {
-      Map<String, dynamic> json;
-      SparkAnonymitySetMeta? meta;
+      const sectorSize = 12000; // TODO adjust this?
+      final prevMeta = await FiroCacheCoordinator.getLatestSetInfoForGroupId(
+        groupId,
+        network,
+      );
 
-      if (progressUpdated == null) {
-        // Legacy
-        final blockhashResult =
-            await FiroCacheCoordinator.getLatestSetInfoForGroupId(
-          groupId,
-          network,
+      final prevSize = prevMeta?.size ?? 0;
+
+      final meta = await client.getSparkAnonymitySetMeta(
+        coinGroupId: groupId,
+      );
+
+      progressUpdated?.call(prevSize, meta.size);
+
+      if (prevMeta?.blockHash == meta.blockHash) {
+        Logging.instance.log(
+          "prevMeta?.blockHash == meta.blockHash",
+          level: LogLevel.Debug,
         );
-        final blockHash = blockhashResult?.blockHash ?? "";
-
-        json = await client.getSparkAnonymitySet(
-          coinGroupId: groupId.toString(),
-          startBlockHash: blockHash.toHexReversedFromBase64,
-        );
-      } else {
-        const sectorSize = 2000; // TODO adjust this?
-        final prevMetaSize =
-            await FiroCacheCoordinator.getSparkMetaSetSizeForGroupId(
-          groupId,
-          network,
-        );
-        final prevSize = prevMetaSize ?? 0;
-
-        meta = await client.getSparkAnonymitySetMeta(
-          coinGroupId: groupId,
-        );
-
-        progressUpdated.call(prevSize, meta.size);
-
-        /// Returns blockHash (last block hash),
-        /// setHash (hash of current set)
-        /// and coins (the list of pairs serialized coin and tx hash)
-
-        final fullSectorCount = (meta.size - prevSize) ~/ sectorSize;
-        final remainder = (meta.size - prevSize) % sectorSize;
-
-        final List<dynamic> coins = [];
-
-        for (int i = 0; i < fullSectorCount; i++) {
-          final start = (i * sectorSize) + prevSize;
-          final data = await client.getSparkAnonymitySetBySector(
-            coinGroupId: groupId,
-            latestBlock: meta.blockHash.toHexReversedFromBase64,
-            startIndex: start,
-            endIndex: start + sectorSize,
-          );
-          progressUpdated.call(start + sectorSize, meta.size);
-
-          coins.addAll(data);
-        }
-
-        if (remainder > 0) {
-          final data = await client.getSparkAnonymitySetBySector(
-            coinGroupId: groupId,
-            latestBlock: meta.blockHash.toHexReversedFromBase64,
-            startIndex: meta.size - remainder,
-            endIndex: meta.size,
-          );
-          progressUpdated.call(meta.size, meta.size);
-
-          coins.addAll(data);
-        }
-
-        json = {
-          "blockHash": meta.blockHash,
-          "setHash": meta.setHash,
-          "coins": coins,
-        };
+        return;
       }
 
+      final numberOfCoinsToFetch = meta.size - prevSize;
+
+      final fullSectorCount = numberOfCoinsToFetch ~/ sectorSize;
+      final remainder = numberOfCoinsToFetch % sectorSize;
+
+      final List<dynamic> coins = [];
+
+      for (int i = 0; i < fullSectorCount; i++) {
+        final start = (i * sectorSize);
+        final data = await client.getSparkAnonymitySetBySector(
+          coinGroupId: groupId,
+          latestBlock: meta.blockHash.toHexReversedFromBase64,
+          startIndex: start,
+          endIndex: start + sectorSize,
+        );
+        progressUpdated?.call(start + sectorSize, numberOfCoinsToFetch);
+
+        coins.addAll(data);
+      }
+
+      if (remainder > 0) {
+        final data = await client.getSparkAnonymitySetBySector(
+          coinGroupId: groupId,
+          latestBlock: meta.blockHash.toHexReversedFromBase64,
+          startIndex: numberOfCoinsToFetch - remainder,
+          endIndex: numberOfCoinsToFetch,
+        );
+        progressUpdated?.call(numberOfCoinsToFetch, numberOfCoinsToFetch);
+
+        coins.addAll(data);
+      }
+
+      final result = coins
+          .map((e) => RawSparkCoin.fromRPCResponse(e as List, groupId))
+          .toList();
+
       await _workers[network]!.runTask(
         FCTask(
           func: FCFuncName._updateSparkAnonSetCoinsWith,
-          data: (groupId, json),
+          data: (meta, result),
         ),
       );
-
-      if (meta != null) {
-        await _workers[network]!.runTask(
-          FCTask(
-            func: FCFuncName._updateSparkAnonSetMetaWith,
-            data: meta,
-          ),
-        );
-      }
     });
   }
 
@@ -265,28 +233,29 @@ abstract class FiroCacheCoordinator {
     );
   }
 
-  static Future<
-      List<
-          ({
-            String serialized,
-            String txHash,
-            String context,
-          })>> getSetCoinsForGroupId(
+  static Future<List<RawSparkCoin>> getSetCoinsForGroupId(
     int groupId, {
-    int? newerThanTimeStamp,
+    String? afterBlockHash,
     required CryptoCurrencyNetwork network,
   }) async {
-    final resultSet = await _Reader._getSetCoinsForGroupId(
-      groupId,
-      db: _FiroCache.setCacheDB(network),
-      newerThanTimeStamp: newerThanTimeStamp,
-    );
+    final resultSet = afterBlockHash == null
+        ? await _Reader._getSetCoinsForGroupId(
+            groupId,
+            db: _FiroCache.setCacheDB(network),
+          )
+        : await _Reader._getSetCoinsForGroupIdAndBlockHash(
+            groupId,
+            afterBlockHash,
+            db: _FiroCache.setCacheDB(network),
+          );
+
     return resultSet
         .map(
-          (row) => (
+          (row) => RawSparkCoin(
             serialized: row["serialized"] as String,
             txHash: row["txHash"] as String,
             context: row["context"] as String,
+            groupId: groupId,
           ),
         )
         .toList()
@@ -294,12 +263,7 @@ abstract class FiroCacheCoordinator {
         .toList();
   }
 
-  static Future<
-      ({
-        String blockHash,
-        String setHash,
-        int timestampUTC,
-      })?> getLatestSetInfoForGroupId(
+  static Future<SparkAnonymitySetMeta?> getLatestSetInfoForGroupId(
     int groupId,
     CryptoCurrencyNetwork network,
   ) async {
@@ -312,10 +276,11 @@ abstract class FiroCacheCoordinator {
       return null;
     }
 
-    return (
+    return SparkAnonymitySetMeta(
+      coinGroupId: groupId,
       blockHash: result.first["blockHash"] as String,
       setHash: result.first["setHash"] as String,
-      timestampUTC: result.first["timestampUTC"] as int,
+      size: result.first["size"] as int,
     );
   }
 
@@ -328,19 +293,4 @@ abstract class FiroCacheCoordinator {
       db: _FiroCache.setCacheDB(network),
     );
   }
-
-  static Future<int?> getSparkMetaSetSizeForGroupId(
-    int groupId,
-    CryptoCurrencyNetwork network,
-  ) async {
-    final result = await _Reader._getSizeForGroupId(
-      groupId,
-      db: _FiroCache.setMetaCacheDB(network),
-    );
-    if (result.isEmpty) {
-      return null;
-    }
-
-    return result.first["size"] as int;
-  }
 }
diff --git a/lib/db/sqlite/firo_cache_reader.dart b/lib/db/sqlite/firo_cache_reader.dart
index b27cd77e3..67fea7764 100644
--- a/lib/db/sqlite/firo_cache_reader.dart
+++ b/lib/db/sqlite/firo_cache_reader.dart
@@ -8,21 +8,15 @@ abstract class _Reader {
   static Future<ResultSet> _getSetCoinsForGroupId(
     int groupId, {
     required Database db,
-    int? newerThanTimeStamp,
   }) async {
-    String query = """
-      SELECT sc.serialized, sc.txHash, sc.context
+    final query = """
+      SELECT sc.serialized, sc.txHash, sc.context, sc.groupId
       FROM SparkSet AS ss
       JOIN SparkSetCoins AS ssc ON ss.id = ssc.setId
       JOIN SparkCoin AS sc ON ssc.coinId = sc.id
-      WHERE ss.groupId = $groupId
+      WHERE ss.groupId = $groupId;
     """;
 
-    if (newerThanTimeStamp != null) {
-      query += " AND ss.timestampUTC"
-          " > $newerThanTimeStamp";
-    }
-
     return db.select("$query;");
   }
 
@@ -31,16 +25,45 @@ abstract class _Reader {
     required Database db,
   }) async {
     final query = """
-      SELECT ss.blockHash, ss.setHash, ss.timestampUTC
+      SELECT ss.blockHash, ss.setHash, ss.size
       FROM SparkSet ss
       WHERE ss.groupId = $groupId
-      ORDER BY ss.timestampUTC DESC
+      ORDER BY ss.size DESC
       LIMIT 1;
     """;
 
     return db.select("$query;");
   }
 
+  static Future<ResultSet> _getSetCoinsForGroupIdAndBlockHash(
+    int groupId,
+    String blockHash, {
+    required Database db,
+  }) async {
+    const query = """
+        WITH TargetBlock AS (
+          SELECT id
+          FROM SparkSet
+          WHERE blockHash = ?
+        ),
+        TargetSets AS (
+          SELECT id AS setId
+          FROM SparkSet
+          WHERE groupId = ? AND id > (SELECT id FROM TargetBlock)
+        )
+        SELECT 
+          SparkCoin.serialized,
+          SparkCoin.txHash,
+          SparkCoin.context,
+          SparkCoin.groupId
+        FROM SparkSetCoins
+        JOIN SparkCoin ON SparkSetCoins.coinId = SparkCoin.id
+        WHERE SparkSetCoins.setId IN (SELECT setId FROM TargetSets);
+    """;
+
+    return db.select("$query;", [blockHash, groupId]);
+  }
+
   static Future<bool> _checkSetInfoForGroupIdExists(
     int groupId, {
     required Database db,
@@ -56,21 +79,6 @@ abstract class _Reader {
     return db.select("$query;").first["setExists"] == 1;
   }
 
-  // ===========================================================================
-  // =============== Spark anonymity set meta queries ==========================
-  static Future<ResultSet> _getSizeForGroupId(
-    int groupId, {
-    required Database db,
-  }) async {
-    final query = """
-      SELECT size
-      FROM PreviousMetaFetchResult
-      WHERE coinGroupId = $groupId;
-    """;
-
-    return db.select("$query;");
-  }
-
   // ===========================================================================
   // =============== Spark used coin tags queries ==============================
 
diff --git a/lib/db/sqlite/firo_cache_worker.dart b/lib/db/sqlite/firo_cache_worker.dart
index a417cdb07..abaceb288 100644
--- a/lib/db/sqlite/firo_cache_worker.dart
+++ b/lib/db/sqlite/firo_cache_worker.dart
@@ -3,7 +3,6 @@ part of 'firo_cache.dart';
 enum FCFuncName {
   _updateSparkAnonSetCoinsWith,
   _updateSparkUsedTagsWith,
-  _updateSparkAnonSetMetaWith,
 }
 
 class FCTask {
@@ -30,8 +29,6 @@ class _FiroCacheWorker {
     final dir = await StackFileSystem.applicationFiroCacheSQLiteDirectory();
     final setCacheFilePath =
         "${dir.path}/${_FiroCache.sparkSetCacheFileName(network)}";
-    final setMetaCacheFilePath =
-        "${dir.path}/${_FiroCache.sparkSetMetaCacheFileName(network)}";
     final usedTagsCacheFilePath =
         "${dir.path}/${_FiroCache.sparkUsedTagsCacheFileName(network)}";
 
@@ -54,7 +51,6 @@ class _FiroCacheWorker {
         (
           initPort.sendPort,
           setCacheFilePath,
-          setMetaCacheFilePath,
           usedTagsCacheFilePath,
         ),
       );
@@ -87,7 +83,6 @@ class _FiroCacheWorker {
     ReceivePort receivePort,
     SendPort sendPort,
     Database setCacheDb,
-    Database setMetaCacheDb,
     Database usedTagsCacheDb,
     Mutex mutex,
   ) {
@@ -99,7 +94,8 @@ class _FiroCacheWorker {
           final FCResult result;
           switch (task.func) {
             case FCFuncName._updateSparkAnonSetCoinsWith:
-              final data = task.data as (int, Map<String, dynamic>);
+              final data =
+                  task.data as (SparkAnonymitySetMeta, List<RawSparkCoin>);
               result = _updateSparkAnonSetCoinsWith(
                 setCacheDb,
                 data.$2,
@@ -113,13 +109,6 @@ class _FiroCacheWorker {
                 task.data as List<List<dynamic>>,
               );
               break;
-
-            case FCFuncName._updateSparkAnonSetMetaWith:
-              result = _updateSparkAnonSetMetaWith(
-                setMetaCacheDb,
-                task.data as SparkAnonymitySetMeta,
-              );
-              break;
           }
 
           if (result.success) {
@@ -134,7 +123,7 @@ class _FiroCacheWorker {
     });
   }
 
-  static void _startWorkerIsolate((SendPort, String, String, String) args) {
+  static void _startWorkerIsolate((SendPort, String, String) args) {
     final receivePort = ReceivePort();
     args.$1.send(receivePort.sendPort);
     final mutex = Mutex();
@@ -142,19 +131,14 @@ class _FiroCacheWorker {
       args.$2,
       mode: OpenMode.readWrite,
     );
-    final setMetaCacheDb = sqlite3.open(
-      args.$3,
-      mode: OpenMode.readWrite,
-    );
     final usedTagsCacheDb = sqlite3.open(
-      args.$4,
+      args.$3,
       mode: OpenMode.readWrite,
     );
     _handleCommandsToIsolate(
       receivePort,
       args.$1,
       setCacheDb,
-      setMetaCacheDb,
       usedTagsCacheDb,
       mutex,
     );
diff --git a/lib/db/sqlite/firo_cache_writer.dart b/lib/db/sqlite/firo_cache_writer.dart
index 36b71369b..63192d964 100644
--- a/lib/db/sqlite/firo_cache_writer.dart
+++ b/lib/db/sqlite/firo_cache_writer.dart
@@ -48,58 +48,17 @@ FCResult _updateSparkUsedTagsWith(
   }
 }
 
-// ===========================================================================
-// ================== write to spark anon set Meta cache ==========================
-FCResult _updateSparkAnonSetMetaWith(
-  Database db,
-  SparkAnonymitySetMeta meta,
-) {
-  db.execute("BEGIN;");
-  try {
-    db.execute(
-      """
-        INSERT OR REPLACE INTO PreviousMetaFetchResult (coinGroupId, blockHash, setHash, size)
-        VALUES (?, ?, ?, ?);
-      """,
-      [meta.coinGroupId, meta.blockHash, meta.setHash, meta.size],
-    );
-
-    db.execute("COMMIT;");
-
-    return FCResult(success: true);
-  } catch (e) {
-    db.execute("ROLLBACK;");
-    return FCResult(success: false, error: e);
-  }
-}
-
 // ===========================================================================
 // ================== write to spark anon set cache ==========================
 
 /// update the sqlite cache
-/// Expected json format:
-///    {
-///         "blockHash": "someBlockHash",
-///         "setHash": "someSetHash",
-///         "coins": [
-///           ["serliazed1", "hash1", "context1"],
-///           ["serliazed2", "hash2", "context2"],
-///           ...
-///           ["serliazed3", "hash3", "context3"],
-///           ["serliazed4", "hash4", "context4"],
-///         ],
-///     }
 ///
 /// returns true if successful, otherwise false
 FCResult _updateSparkAnonSetCoinsWith(
   Database db,
-  Map<String, dynamic> json,
-  int groupId,
+  final List<RawSparkCoin> coinsRaw,
+  SparkAnonymitySetMeta meta,
 ) {
-  final blockHash = json["blockHash"] as String;
-  final setHash = json["setHash"] as String;
-  final coinsRaw = json["coins"] as List;
-
   if (coinsRaw.isEmpty) {
     // no coins to actually insert
     return FCResult(success: true);
@@ -112,9 +71,9 @@ FCResult _updateSparkAnonSetCoinsWith(
       WHERE blockHash = ? AND setHash = ? AND groupId = ?;
     """,
     [
-      blockHash,
-      setHash,
-      groupId,
+      meta.blockHash,
+      meta.setHash,
+      meta.coinGroupId,
     ],
   );
 
@@ -123,59 +82,28 @@ FCResult _updateSparkAnonSetCoinsWith(
     return FCResult(success: true);
   }
 
-  final coins = coinsRaw
-      .map(
-        (e) => [
-          e[0] as String,
-          e[1] as String,
-          e[2] as String,
-        ],
-      )
-      .toList()
-      .reversed;
-
-  final timestamp = DateTime.now().toUtc().millisecondsSinceEpoch ~/ 1000;
+  final coins = coinsRaw.reversed;
 
   db.execute("BEGIN;");
   try {
     db.execute(
       """
-        INSERT INTO SparkSet (blockHash, setHash, groupId, timestampUTC)
+        INSERT INTO SparkSet (blockHash, setHash, groupId, size)
         VALUES (?, ?, ?, ?);
       """,
-      [blockHash, setHash, groupId, timestamp],
+      [meta.blockHash, meta.setHash, meta.coinGroupId, meta.size],
     );
     final setId = db.lastInsertRowId;
 
     for (final coin in coins) {
-      int coinId;
-      try {
-        // try to insert and get row id
-        db.execute(
-          """
-            INSERT INTO SparkCoin (serialized, txHash, context)
-            VALUES (?, ?, ?);
+      db.execute(
+        """
+            INSERT INTO SparkCoin (serialized, txHash, context, groupId)
+            VALUES (?, ?, ?, ?);
           """,
-          coin,
-        );
-        coinId = db.lastInsertRowId;
-      } on SqliteException catch (e) {
-        // if there already is a matching coin in the db
-        // just grab its row id
-        if (e.extendedResultCode == 2067) {
-          final result = db.select(
-            """
-              SELECT id
-              FROM SparkCoin
-              WHERE serialized = ? AND txHash = ? AND context = ?;
-            """,
-            coin,
-          );
-          coinId = result.first["id"] as int;
-        } else {
-          rethrow;
-        }
-      }
+        [coin.serialized, coin.txHash, coin.context, coin.groupId],
+      );
+      final coinId = db.lastInsertRowId;
 
       // finally add the row id to the newly added set
       db.execute(
diff --git a/lib/electrumx_rpc/electrumx_client.dart b/lib/electrumx_rpc/electrumx_client.dart
index 3f8241bca..8ff04712a 100644
--- a/lib/electrumx_rpc/electrumx_client.dart
+++ b/lib/electrumx_rpc/electrumx_client.dart
@@ -399,7 +399,11 @@ class ElectrumXClient {
         rethrow;
       }
     } catch (e) {
+      final errorMessage = e.toString();
       Logging.instance.log("$host $e", level: LogLevel.Debug);
+      if (errorMessage.contains("JSON-RPC error")) {
+        currentFailoverIndex = _failovers.length;
+      }
       if (currentFailoverIndex < _failovers.length - 1) {
         currentFailoverIndex++;
         return request(
diff --git a/lib/models/electrumx_response/spark_models.dart b/lib/models/electrumx_response/spark_models.dart
index 499f20cf6..43bf9f61f 100644
--- a/lib/models/electrumx_response/spark_models.dart
+++ b/lib/models/electrumx_response/spark_models.dart
@@ -45,3 +45,54 @@ class SparkAnonymitySetMeta {
         "}";
   }
 }
+
+class RawSparkCoin {
+  final String serialized;
+  final String txHash;
+  final String context;
+  final int groupId;
+
+  RawSparkCoin({
+    required this.serialized,
+    required this.txHash,
+    required this.context,
+    required this.groupId,
+  });
+
+  static RawSparkCoin fromRPCResponse(List<dynamic> data, int groupId) {
+    try {
+      if (data.length != 3) throw Exception();
+      return RawSparkCoin(
+        serialized: data[0] as String,
+        txHash: data[1] as String,
+        context: data[2] as String,
+        groupId: groupId,
+      );
+    } catch (_) {
+      throw Exception("Invalid coin data: $data");
+    }
+  }
+
+  @override
+  bool operator ==(Object other) {
+    if (identical(this, other)) return true;
+    if (other is! RawSparkCoin) return false;
+    return serialized == other.serialized &&
+        txHash == other.txHash &&
+        groupId == other.groupId &&
+        context == other.context;
+  }
+
+  @override
+  int get hashCode => Object.hash(serialized, txHash, context);
+
+  @override
+  String toString() {
+    return "SparkAnonymitySetMeta{"
+        "serialized: $serialized, "
+        "txHash: $txHash, "
+        "context: $context, "
+        "groupId: $groupId"
+        "}";
+  }
+}
diff --git a/lib/wallets/isar/models/wallet_info.dart b/lib/wallets/isar/models/wallet_info.dart
index eb6a4e9ea..51aa69a45 100644
--- a/lib/wallets/isar/models/wallet_info.dart
+++ b/lib/wallets/isar/models/wallet_info.dart
@@ -520,8 +520,8 @@ abstract class WalletInfoKeys {
   static const String lelantusCoinIsarRescanRequired =
       "lelantusCoinIsarRescanRequired";
   static const String enableLelantusScanning = "enableLelantusScanningKey";
-  static const String firoSparkCacheSetTimestampCache =
-      "firoSparkCacheSetTimestampCacheKey";
+  static const String firoSparkCacheSetBlockHashCache =
+      "firoSparkCacheSetBlockHashCacheKey";
   static const String enableOptInRbf = "enableOptInRbfKey";
   static const String reuseAddress = "reuseAddressKey";
   static const String isViewOnlyKey = "isViewOnlyKey";
diff --git a/lib/wallets/wallet/impl/firo_wallet.dart b/lib/wallets/wallet/impl/firo_wallet.dart
index d4faabef9..d412f1d5b 100644
--- a/lib/wallets/wallet/impl/firo_wallet.dart
+++ b/lib/wallets/wallet/impl/firo_wallet.dart
@@ -671,7 +671,7 @@ class FiroWallet<T extends ElectrumXCurrencyInterface> extends Bip39HDWallet<T>
     // reset last checked values
     await info.updateOtherData(
       newEntries: {
-        WalletInfoKeys.firoSparkCacheSetTimestampCache: <String, int>{},
+        WalletInfoKeys.firoSparkCacheSetBlockHashCache: <String, String>{},
       },
       isar: mainDB.isar,
     );
diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart
index 5390b66d3..2b1f0f903 100644
--- a/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart
+++ b/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart
@@ -886,11 +886,11 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
         currentPercent = _triggerEventHelper(currentPercent, percentIncrement);
       }
 
-      // Get cached timestamps per groupId. These timestamps are used to check
+      // Get cached block hashes per groupId. These hashes are used to check
       // and try to id coins that were added to the spark anon set cache
-      // after that timestamp.
-      final groupIdTimestampUTCMap =
-          info.otherData[WalletInfoKeys.firoSparkCacheSetTimestampCache]
+      // after that block.
+      final groupIdBlockHashMap =
+          info.otherData[WalletInfoKeys.firoSparkCacheSetBlockHashCache]
                   as Map? ??
               {};
 
@@ -898,8 +898,7 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
       // processed by this wallet yet
       final Map<int, List<List<String>>> rawCoinsBySetId = {};
       for (int i = 1; i <= latestGroupId; i++) {
-        final lastCheckedTimeStampUTC =
-            groupIdTimestampUTCMap[i.toString()] as int? ?? 0;
+        final lastCheckedHash = groupIdBlockHashMap[i.toString()] as String?;
         final info = await FiroCacheCoordinator.getLatestSetInfoForGroupId(
           i,
           cryptoCurrency.network,
@@ -907,7 +906,7 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
         final anonymitySetResult =
             await FiroCacheCoordinator.getSetCoinsForGroupId(
           i,
-          newerThanTimeStamp: lastCheckedTimeStampUTC,
+          afterBlockHash: lastCheckedHash,
           network: cryptoCurrency.network,
         );
         final coinsRaw = anonymitySetResult
@@ -924,11 +923,8 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
           rawCoinsBySetId[i] = coinsRaw;
         }
 
-        // update last checked timestamp data
-        groupIdTimestampUTCMap[i.toString()] = max(
-          lastCheckedTimeStampUTC,
-          info?.timestampUTC ?? lastCheckedTimeStampUTC,
-        );
+        // update last checked
+        groupIdBlockHashMap[i.toString()] = info?.blockHash;
       }
 
       if (percentIncrement != null) {
@@ -973,11 +969,10 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
         });
       }
 
-      // finally update the cached timestamps in the database
+      // finally update the cached block hashes in the database
       await info.updateOtherData(
         newEntries: {
-          WalletInfoKeys.firoSparkCacheSetTimestampCache:
-              groupIdTimestampUTCMap,
+          WalletInfoKeys.firoSparkCacheSetBlockHashCache: groupIdBlockHashMap,
         },
         isar: mainDB.isar,
       );