diff --git a/.idea/dictionaries/ganfra.xml b/.idea/dictionaries/ganfra.xml
index 806a104826..1ca7a97a77 100644
--- a/.idea/dictionaries/ganfra.xml
+++ b/.idea/dictionaries/ganfra.xml
@@ -6,6 +6,7 @@
       <w>merlins</w>
       <w>moshi</w>
       <w>synchronizer</w>
+      <w>untimelined</w>
     </words>
   </dictionary>
 </component>
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt
index 07316c10f1..03b4b1e848 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt
@@ -1,12 +1,15 @@
 package im.vector.matrix.android.internal.database.helper
 
 import im.vector.matrix.android.api.session.events.model.Event
+import im.vector.matrix.android.api.session.events.model.EventType
 import im.vector.matrix.android.internal.database.mapper.asDomain
 import im.vector.matrix.android.internal.database.mapper.asEntity
 import im.vector.matrix.android.internal.database.model.ChunkEntity
+import im.vector.matrix.android.internal.database.model.EventEntityFields
 import im.vector.matrix.android.internal.database.query.fastContains
 import im.vector.matrix.android.internal.database.query.find
 import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
+import io.realm.Sort
 
 
 internal fun ChunkEntity.merge(chunkEntity: ChunkEntity,
@@ -25,16 +28,16 @@ internal fun ChunkEntity.merge(chunkEntity: ChunkEntity,
 
 internal fun ChunkEntity.addAll(events: List<Event>,
                                 direction: PaginationDirection,
-                                updateStateIndex: Boolean = true) {
+                                stateIndexOffset: Int = 0) {
 
     events.forEach { event ->
-        addOrUpdate(event, direction, updateStateIndex)
+        addOrUpdate(event, direction, stateIndexOffset)
     }
 }
 
 internal fun ChunkEntity.addOrUpdate(event: Event,
                                      direction: PaginationDirection,
-                                     updateStateIndex: Boolean = true) {
+                                     stateIndexOffset: Int = 0) {
     if (!isManaged) {
         throw IllegalStateException("Chunk entity should be managed to use fast contains")
     }
@@ -43,11 +46,16 @@ internal fun ChunkEntity.addOrUpdate(event: Event,
         return
     }
 
-    if (updateStateIndex && event.isStateEvent()) {
-        updateStateIndex(direction)
+    var currentStateIndex = lastStateIndex(direction, defaultValue = stateIndexOffset)
+    if (direction == PaginationDirection.FORWARDS && event.isStateEvent()) {
+        currentStateIndex += 1
+    } else if (direction == PaginationDirection.BACKWARDS && events.isNotEmpty()) {
+        val lastEventType = events.last()?.type ?: ""
+        if (EventType.isStateEvent(lastEventType)) {
+            currentStateIndex -= 1
+        }
     }
 
-    val currentStateIndex = stateIndex(direction)
     if (!events.fastContains(event.eventId)) {
         val eventEntity = event.asEntity()
         eventEntity.stateIndex = currentStateIndex
@@ -57,4 +65,11 @@ internal fun ChunkEntity.addOrUpdate(event: Event,
         val eventEntity = events.find(event.eventId)
         eventEntity?.stateIndex = currentStateIndex
     }
+}
+
+internal fun ChunkEntity.lastStateIndex(direction: PaginationDirection, defaultValue: Int = 0): Int {
+    return when (direction) {
+               PaginationDirection.FORWARDS  -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.DESCENDING).findFirst()?.stateIndex
+               PaginationDirection.BACKWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.ASCENDING).findFirst()?.stateIndex
+           } ?: defaultValue
 }
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt
index 7cf8ecbb87..0b69f2c0cd 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt
@@ -1,5 +1,7 @@
 package im.vector.matrix.android.internal.database.helper
 
+import im.vector.matrix.android.api.session.events.model.Event
+import im.vector.matrix.android.internal.database.mapper.asEntity
 import im.vector.matrix.android.internal.database.model.ChunkEntity
 import im.vector.matrix.android.internal.database.model.RoomEntity
 
@@ -15,4 +17,18 @@ internal fun RoomEntity.addOrUpdate(chunkEntity: ChunkEntity) {
     if (!chunks.contains(chunkEntity)) {
         chunks.add(chunkEntity)
     }
+}
+
+internal fun RoomEntity.addStateEvents(stateEvents: List<Event>, stateIndex: Int = Int.MIN_VALUE) {
+    if (!isManaged) {
+        throw IllegalStateException("Chunk entity should be managed to use fast contains")
+    }
+    stateEvents.forEach { event ->
+        if (event.eventId == null) {
+            return@forEach
+        }
+        val eventEntity = event.asEntity()
+        eventEntity.stateIndex = stateIndex
+        untimelinedStateEvents.add(eventEntity)
+    }
 }
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt
index 64aa9e28f8..354720df84 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt
@@ -1,6 +1,5 @@
 package im.vector.matrix.android.internal.database.model
 
-import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
 import io.realm.RealmList
 import io.realm.RealmObject
 import io.realm.RealmResults
@@ -8,8 +7,6 @@ import io.realm.annotations.LinkingObjects
 
 internal open class ChunkEntity(var prevToken: String? = null,
                                 var nextToken: String? = null,
-                                var prevStateIndex: Int = -1,
-                                var nextStateIndex: Int = 1,
                                 var isLast: Boolean = false,
                                 var events: RealmList<EventEntity> = RealmList()
 ) : RealmObject() {
@@ -18,19 +15,4 @@ internal open class ChunkEntity(var prevToken: String? = null,
     val room: RealmResults<RoomEntity>? = null
 
     companion object
-
-    fun stateIndex(direction: PaginationDirection): Int {
-        return when (direction) {
-            PaginationDirection.FORWARDS  -> nextStateIndex
-            PaginationDirection.BACKWARDS -> prevStateIndex
-        }
-    }
-
-    fun updateStateIndex(direction: PaginationDirection) {
-        when (direction) {
-            PaginationDirection.FORWARDS  -> nextStateIndex += 1
-            PaginationDirection.BACKWARDS -> prevStateIndex -= 1
-        }
-    }
-
 }
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventEntity.kt
index 2bcb91e8a5..96ba986afb 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventEntity.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/EventEntity.kt
@@ -24,4 +24,7 @@ internal open class EventEntity(var eventId: String = "",
     @LinkingObjects("events")
     val chunk: RealmResults<ChunkEntity>? = null
 
+    @LinkingObjects("untimelinedStateEvents")
+    val room: RealmResults<RoomEntity>? = null
+
 }
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt
index e8df6e34bf..906dff0d60 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt
@@ -8,8 +8,9 @@ import io.realm.annotations.PrimaryKey
 import kotlin.properties.Delegates
 
 internal open class RoomEntity(@PrimaryKey var roomId: String = "",
-                      var chunks: RealmList<ChunkEntity> = RealmList(),
-                      var areAllMembersLoaded: Boolean = false
+                               var chunks: RealmList<ChunkEntity> = RealmList(),
+                               var untimelinedStateEvents: RealmList<EventEntity> = RealmList(),
+                               var areAllMembersLoaded: Boolean = false
 ) : RealmObject() {
 
     private var membershipStr: String = MyMembership.NONE.name
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ChunkEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ChunkEntityQueries.kt
index 5f1a7a15c1..e3b071a2ba 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ChunkEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ChunkEntityQueries.kt
@@ -1,6 +1,5 @@
 package im.vector.matrix.android.internal.database.query
 
-import im.vector.matrix.android.internal.database.DBConstants
 import im.vector.matrix.android.internal.database.model.ChunkEntity
 import im.vector.matrix.android.internal.database.model.ChunkEntityFields
 import im.vector.matrix.android.internal.database.model.RoomEntityFields
@@ -34,7 +33,5 @@ internal fun ChunkEntity.Companion.findLastLiveChunkFromRoom(realm: Realm, roomI
 internal fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, eventIds: List<String>): RealmResults<ChunkEntity> {
     return realm.where<ChunkEntity>()
             .`in`(ChunkEntityFields.EVENTS.EVENT_ID, eventIds.toTypedArray())
-            .notEqualTo(ChunkEntityFields.PREV_TOKEN, DBConstants.STATE_EVENTS_CHUNK_TOKEN)
-            .notEqualTo(ChunkEntityFields.NEXT_TOKEN, DBConstants.STATE_EVENTS_CHUNK_TOKEN)
             .findAll()
 }
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt
index f54881a397..91a828c7ed 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt
@@ -18,7 +18,11 @@ internal fun EventEntity.Companion.where(realm: Realm, eventId: String): RealmQu
 internal fun EventEntity.Companion.where(realm: Realm, roomId: String? = null, type: String? = null): RealmQuery<EventEntity> {
     val query = realm.where<EventEntity>()
     if (roomId != null) {
-        query.equalTo("${EventEntityFields.CHUNK}.${ChunkEntityFields.ROOM}.${RoomEntityFields.ROOM_ID}", roomId)
+        query.beginGroup()
+                .equalTo("${EventEntityFields.CHUNK}.${ChunkEntityFields.ROOM}.${RoomEntityFields.ROOM_ID}", roomId)
+                .or()
+                .equalTo("${EventEntityFields.ROOM}.${RoomEntityFields.ROOM_ID}", roomId)
+                .endGroup()
     }
     if (type != null) {
         query.equalTo(EventEntityFields.TYPE, type)
@@ -26,21 +30,28 @@ internal fun EventEntity.Companion.where(realm: Realm, roomId: String? = null, t
     return query
 }
 
-internal fun RealmQuery<EventEntity>.findMostSuitableStateEvent(stateIndex: Int): EventEntity? {
-    val sort: Sort = if (stateIndex < 0) {
-        this.greaterThanOrEqualTo(EventEntityFields.STATE_INDEX, stateIndex)
-        Sort.ASCENDING
-    } else {
-        this.lessThanOrEqualTo(EventEntityFields.STATE_INDEX, stateIndex)
-        Sort.DESCENDING
+internal fun RealmQuery<EventEntity>.next(from: Int? = null, strict: Boolean = true): EventEntity? {
+    if (from != null) {
+        if (strict) {
+            this.greaterThan(EventEntityFields.STATE_INDEX, from)
+        } else {
+            this.greaterThanOrEqualTo(EventEntityFields.STATE_INDEX, from)
+        }
     }
     return this
-            .sort(EventEntityFields.STATE_INDEX, sort)
+            .sort(EventEntityFields.STATE_INDEX, Sort.ASCENDING)
             .findFirst()
 }
 
 
-internal fun RealmQuery<EventEntity>.last(): EventEntity? {
+internal fun RealmQuery<EventEntity>.last(since: Int? = null, strict: Boolean = false): EventEntity? {
+    if (since != null) {
+        if (strict) {
+            this.lessThan(EventEntityFields.STATE_INDEX, since)
+        } else {
+            this.lessThanOrEqualTo(EventEntityFields.STATE_INDEX, since)
+        }
+    }
     return this
             .sort(EventEntityFields.STATE_INDEX, Sort.DESCENDING)
             .findFirst()
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt
index bfd9052ebe..14dee22b06 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt
@@ -25,11 +25,11 @@ class RoomModule : Module {
         }
 
         scope(DefaultSession.SCOPE) {
-            LoadRoomMembersRequest(get(), get(), get(), get())
+            LoadRoomMembersRequest(get(), get(), get())
         }
 
         scope(DefaultSession.SCOPE) {
-            PaginationRequest(get(), get(), get(), get())
+            PaginationRequest(get(), get(), get())
         }
 
 
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/LoadRoomMembersRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/LoadRoomMembersRequest.kt
index 430b08b69c..c3fca61d7b 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/LoadRoomMembersRequest.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/LoadRoomMembersRequest.kt
@@ -5,12 +5,11 @@ import com.zhuinden.monarchy.Monarchy
 import im.vector.matrix.android.api.MatrixCallback
 import im.vector.matrix.android.api.session.room.model.Membership
 import im.vector.matrix.android.api.util.Cancelable
-import im.vector.matrix.android.internal.database.helper.addOrUpdate
+import im.vector.matrix.android.internal.database.helper.addStateEvents
 import im.vector.matrix.android.internal.database.model.RoomEntity
 import im.vector.matrix.android.internal.database.query.where
 import im.vector.matrix.android.internal.network.executeRequest
 import im.vector.matrix.android.internal.session.room.RoomAPI
-import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
 import im.vector.matrix.android.internal.util.CancelableCoroutine
 import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
 import im.vector.matrix.android.internal.util.tryTransactionSync
@@ -20,8 +19,7 @@ import kotlinx.coroutines.withContext
 
 internal class LoadRoomMembersRequest(private val roomAPI: RoomAPI,
                                       private val monarchy: Monarchy,
-                                      private val coroutineDispatchers: MatrixCoroutineDispatchers,
-                                      private val stateEventsChunkHandler: StateEventsChunkHandler) {
+                                      private val coroutineDispatchers: MatrixCoroutineDispatchers) {
 
     fun execute(roomId: String,
                 streamToken: String?,
@@ -57,8 +55,7 @@ internal class LoadRoomMembersRequest(private val roomAPI: RoomAPI,
                     val roomMembers = RoomMembers(realm, roomId).getLoaded()
                     val eventsToInsert = response.roomMemberEvents.filter { !roomMembers.containsKey(it.stateKey) }
 
-                    val chunk = stateEventsChunkHandler.handle(realm, roomId, eventsToInsert)
-                    roomEntity.addOrUpdate(chunk)
+                    roomEntity.addStateEvents(eventsToInsert)
                     roomEntity.areAllMembersLoaded = true
                 }
                 .map { response }
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMemberExtractor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMemberExtractor.kt
index d7c51b71b2..08012cb5fd 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMemberExtractor.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMemberExtractor.kt
@@ -2,14 +2,12 @@ package im.vector.matrix.android.internal.session.room.members
 
 import im.vector.matrix.android.api.session.events.model.EventType
 import im.vector.matrix.android.api.session.room.model.RoomMember
-import im.vector.matrix.android.internal.database.DBConstants
 import im.vector.matrix.android.internal.database.mapper.asDomain
-import im.vector.matrix.android.internal.database.model.ChunkEntity
 import im.vector.matrix.android.internal.database.model.EventEntity
 import im.vector.matrix.android.internal.database.model.EventEntityFields
-import im.vector.matrix.android.internal.database.query.find
-import im.vector.matrix.android.internal.database.query.findMostSuitableStateEvent
 import im.vector.matrix.android.internal.database.query.last
+import im.vector.matrix.android.internal.database.query.next
+import im.vector.matrix.android.internal.database.query.where
 import io.realm.Realm
 import io.realm.RealmQuery
 
@@ -17,35 +15,23 @@ internal class RoomMemberExtractor(private val realm: Realm,
                                    private val roomId: String) {
 
     fun extractFrom(event: EventEntity): RoomMember? {
-        val stateIndex = event.stateIndex
-        val chunkEntity = event.chunk?.firstOrNull()
-                          ?: throw IllegalStateException("An event should be attached to a chunk")
-
-        // First of all, try to get the most suitable state event coming from a chunk
-        val roomMember = buildQuery(chunkEntity, event.sender)
-                .findMostSuitableStateEvent(stateIndex = stateIndex)
-                ?.asDomain()
-                ?.pickContent<RoomMember>(stateIndex)
-
-        if (roomMember != null) {
-            return roomMember
+        val sender = event.sender ?: return null
+        // When stateIndex is negative, we try to get the next stateEvent prevContent()
+        // If prevContent is null we fallback to the Int.MIN state events content()
+        return if (event.stateIndex <= 0) {
+            baseQuery(realm, roomId, sender).next(from = event.stateIndex)?.asDomain()?.prevContent()
+            ?: baseQuery(realm, roomId, sender).last(since = event.stateIndex)?.asDomain()?.content()
+        } else {
+            baseQuery(realm, roomId, sender).last(since = event.stateIndex)?.asDomain()?.content()
         }
-
-        // If the content is null, we try get the last state event coming from a state events chunk
-        val stateChunkEntity = ChunkEntity.find(realm, roomId, nextToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN)
-                               ?: return null
-
-        return buildQuery(stateChunkEntity, event.sender)
-                .last()
-                ?.asDomain()
-                ?.content()
     }
 
-    private fun buildQuery(chunk: ChunkEntity,
-                           sender: String?): RealmQuery<EventEntity> {
-        return chunk.events
-                .where()
-                .equalTo(EventEntityFields.TYPE, EventType.STATE_ROOM_MEMBER)
+    private fun baseQuery(realm: Realm,
+                          roomId: String,
+                          sender: String): RealmQuery<EventEntity> {
+
+        return EventEntity
+                .where(realm, roomId = roomId, type = EventType.STATE_ROOM_MEMBER)
                 .equalTo(EventEntityFields.STATE_KEY, sender)
 
     }
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetContextOfEventRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetContextOfEventRequest.kt
index fcab9e8297..248c616a47 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetContextOfEventRequest.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetContextOfEventRequest.kt
@@ -6,6 +6,7 @@ import im.vector.matrix.android.api.MatrixCallback
 import im.vector.matrix.android.api.util.Cancelable
 import im.vector.matrix.android.internal.database.helper.addAll
 import im.vector.matrix.android.internal.database.helper.addOrUpdate
+import im.vector.matrix.android.internal.database.helper.addStateEvents
 import im.vector.matrix.android.internal.database.helper.deleteOnCascade
 import im.vector.matrix.android.internal.database.helper.merge
 import im.vector.matrix.android.internal.database.model.ChunkEntity
@@ -15,7 +16,6 @@ import im.vector.matrix.android.internal.database.query.where
 import im.vector.matrix.android.internal.legacy.util.FilterUtil
 import im.vector.matrix.android.internal.network.executeRequest
 import im.vector.matrix.android.internal.session.room.RoomAPI
-import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
 import im.vector.matrix.android.internal.util.CancelableCoroutine
 import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
 import im.vector.matrix.android.internal.util.tryTransactionSync
@@ -26,8 +26,7 @@ import kotlinx.coroutines.withContext
 
 internal class GetContextOfEventRequest(private val roomAPI: RoomAPI,
                                         private val monarchy: Monarchy,
-                                        private val coroutineDispatchers: MatrixCoroutineDispatchers,
-                                        private val stateEventsChunkHandler: StateEventsChunkHandler
+                                        private val coroutineDispatchers: MatrixCoroutineDispatchers
 ) {
 
     fun execute(roomId: String,
@@ -91,9 +90,7 @@ internal class GetContextOfEventRequest(private val roomAPI: RoomAPI,
                             }
                     */
                     roomEntity.addOrUpdate(currentChunk)
-
-                    val stateEventsChunk = stateEventsChunkHandler.handle(realm, roomId, response.stateEvents)
-                    roomEntity.addOrUpdate(stateEventsChunk)
+                    roomEntity.addStateEvents(response.stateEvents)
                 }
                 .map { response }
     }
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetEventRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetEventRequest.kt
index 1a8ebc7b3b..28abd07225 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetEventRequest.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/GetEventRequest.kt
@@ -6,7 +6,6 @@ import im.vector.matrix.android.api.session.events.model.Event
 import im.vector.matrix.android.api.util.Cancelable
 import im.vector.matrix.android.internal.network.executeRequest
 import im.vector.matrix.android.internal.session.room.RoomAPI
-import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
 import im.vector.matrix.android.internal.util.CancelableCoroutine
 import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
 import kotlinx.coroutines.GlobalScope
@@ -15,8 +14,7 @@ import kotlinx.coroutines.withContext
 
 internal class GetEventRequest(private val roomAPI: RoomAPI,
                                private val monarchy: Monarchy,
-                               private val coroutineDispatchers: MatrixCoroutineDispatchers,
-                               private val stateEventsChunkHandler: StateEventsChunkHandler
+                               private val coroutineDispatchers: MatrixCoroutineDispatchers
 ) {
 
     fun execute(roomId: String,
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationRequest.kt
index 5ca59f71d2..29a3e6c936 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationRequest.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/PaginationRequest.kt
@@ -7,6 +7,7 @@ import im.vector.matrix.android.api.MatrixCallback
 import im.vector.matrix.android.api.util.Cancelable
 import im.vector.matrix.android.internal.database.helper.addAll
 import im.vector.matrix.android.internal.database.helper.addOrUpdate
+import im.vector.matrix.android.internal.database.helper.addStateEvents
 import im.vector.matrix.android.internal.database.helper.deleteOnCascade
 import im.vector.matrix.android.internal.database.helper.merge
 import im.vector.matrix.android.internal.database.model.ChunkEntity
@@ -17,7 +18,6 @@ import im.vector.matrix.android.internal.database.query.where
 import im.vector.matrix.android.internal.legacy.util.FilterUtil
 import im.vector.matrix.android.internal.network.executeRequest
 import im.vector.matrix.android.internal.session.room.RoomAPI
-import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
 import im.vector.matrix.android.internal.util.CancelableCoroutine
 import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
 import im.vector.matrix.android.internal.util.tryTransactionSync
@@ -28,8 +28,7 @@ import kotlinx.coroutines.withContext
 
 internal class PaginationRequest(private val roomAPI: RoomAPI,
                                  private val monarchy: Monarchy,
-                                 private val coroutineDispatchers: MatrixCoroutineDispatchers,
-                                 private val stateEventsChunkHandler: StateEventsChunkHandler
+                                 private val coroutineDispatchers: MatrixCoroutineDispatchers
 ) {
 
     fun execute(roomId: String,
@@ -92,10 +91,8 @@ internal class PaginationRequest(private val roomAPI: RoomAPI,
                     }
 
                     roomEntity.addOrUpdate(currentChunk)
-
                     // TODO : there is an issue with the pagination sending unwanted room member events
-                    val stateEventsChunk = stateEventsChunkHandler.handle(realm, roomId, receivedChunk.stateEvents)
-                    roomEntity.addOrUpdate(stateEventsChunk)
+                    roomEntity.addStateEvents(receivedChunk.stateEvents)
                 }
                 .map { receivedChunk }
     }
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt
index 7b1227115a..adf0b9c7a6 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt
@@ -6,10 +6,11 @@ import im.vector.matrix.android.api.session.events.model.EventType
 import im.vector.matrix.android.api.session.room.model.MyMembership
 import im.vector.matrix.android.internal.database.helper.addAll
 import im.vector.matrix.android.internal.database.helper.addOrUpdate
+import im.vector.matrix.android.internal.database.helper.addStateEvents
+import im.vector.matrix.android.internal.database.helper.lastStateIndex
 import im.vector.matrix.android.internal.database.model.ChunkEntity
 import im.vector.matrix.android.internal.database.model.RoomEntity
 import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
-import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
 import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
 import im.vector.matrix.android.internal.database.query.where
 import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
@@ -23,7 +24,6 @@ import io.realm.kotlin.createObject
 
 
 internal class RoomSyncHandler(private val monarchy: Monarchy,
-                               private val stateEventsChunkHandler: StateEventsChunkHandler,
                                private val readReceiptHandler: ReadReceiptHandler) {
 
     sealed class HandlingStrategy {
@@ -56,7 +56,7 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
                                  roomSync: RoomSync): RoomEntity {
 
         val roomEntity = RoomEntity.where(realm, roomId).findFirst()
-                         ?: RoomEntity(roomId)
+                         ?: realm.createObject(roomId)
 
         if (roomEntity.membership == MyMembership.INVITED) {
             roomEntity.chunks.deleteAllFromRealm()
@@ -64,13 +64,27 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
 
         roomEntity.membership = MyMembership.JOINED
 
+        val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
+        val isInitialSync = lastChunk == null
+        val lastStateIndex = lastChunk?.lastStateIndex(PaginationDirection.FORWARDS) ?: 0
+        val numberOfStateEvents = roomSync.state?.events?.size ?: 0
+        val stateIndexOffset = lastStateIndex + numberOfStateEvents
+
         if (roomSync.state != null && roomSync.state.events.isNotEmpty()) {
-            val chunkEntity = stateEventsChunkHandler.handle(realm, roomId, roomSync.state.events)
-            roomEntity.addOrUpdate(chunkEntity)
+            val untimelinedStateIndex = if (isInitialSync) Int.MIN_VALUE else stateIndexOffset
+            roomEntity.addStateEvents(roomSync.state.events, stateIndex = untimelinedStateIndex)
         }
 
         if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) {
-            val chunkEntity = handleTimelineEvents(realm, roomId, roomSync.timeline.events, roomSync.timeline.prevToken, isLimited = roomSync.timeline.limited)
+            val timelineStateOffset = if (isInitialSync || roomSync.timeline.limited.not()) 0 else stateIndexOffset
+            val chunkEntity = handleTimelineEvents(
+                    realm,
+                    roomId,
+                    roomSync.timeline.events,
+                    roomSync.timeline.prevToken,
+                    roomSync.timeline.limited,
+                    timelineStateOffset
+            )
             roomEntity.addOrUpdate(chunkEntity)
         }
 
@@ -111,22 +125,19 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
                                      roomId: String,
                                      eventList: List<Event>,
                                      prevToken: String? = null,
-                                     nextToken: String? = null,
-                                     isLimited: Boolean = true): ChunkEntity {
+                                     isLimited: Boolean = true,
+                                     stateIndexOffset: Int = 0): ChunkEntity {
 
         val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
-        val chunkEntity = if (!isLimited) {
+        val chunkEntity = if (!isLimited && lastChunk != null) {
             lastChunk
         } else {
-            val eventIds = eventList.filter { it.eventId != null }.map { it.eventId!! }
-            ChunkEntity.findAllIncludingEvents(realm, eventIds).firstOrNull()
-        } ?: realm.createObject<ChunkEntity>().apply { this.prevToken = prevToken }
+            realm.createObject<ChunkEntity>().apply { this.prevToken = prevToken }
+        }
 
         lastChunk?.isLast = false
         chunkEntity.isLast = true
-        chunkEntity.nextToken = nextToken
-
-        chunkEntity.addAll(eventList, PaginationDirection.FORWARDS)
+        chunkEntity.addAll(eventList, PaginationDirection.FORWARDS, stateIndexOffset)
         return chunkEntity
     }
 
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/StateEventsChunkHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/StateEventsChunkHandler.kt
deleted file mode 100644
index 8046b74f2e..0000000000
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/StateEventsChunkHandler.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package im.vector.matrix.android.internal.session.sync
-
-import im.vector.matrix.android.api.session.events.model.Event
-import im.vector.matrix.android.internal.database.DBConstants
-import im.vector.matrix.android.internal.database.helper.addAll
-import im.vector.matrix.android.internal.database.model.ChunkEntity
-import im.vector.matrix.android.internal.database.query.find
-import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection
-import io.realm.Realm
-import io.realm.kotlin.createObject
-
-internal class StateEventsChunkHandler {
-
-    fun handle(realm: Realm, roomId: String, stateEvents: List<Event>): ChunkEntity {
-        val chunkEntity = ChunkEntity.find(realm, roomId, nextToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN)
-                          ?: realm.createObject<ChunkEntity>()
-                                  .apply {
-                                      prevToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN
-                                      nextToken = DBConstants.STATE_EVENTS_CHUNK_TOKEN
-                                      nextStateIndex = Int.MIN_VALUE
-                                      prevStateIndex = Int.MIN_VALUE
-                                  }
-
-        // We always consider going forwards as data from server are the most recent
-        chunkEntity.addAll(stateEvents, direction = PaginationDirection.FORWARDS, updateStateIndex = false)
-        return chunkEntity
-    }
-
-
-}
-
-
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt
index 86b739e451..0ae3e61837 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt
@@ -17,16 +17,12 @@ internal class SyncModule : Module {
             retrofit.create(SyncAPI::class.java)
         }
 
-        scope(DefaultSession.SCOPE) {
-            StateEventsChunkHandler()
-        }
-
         scope(DefaultSession.SCOPE) {
             ReadReceiptHandler()
         }
 
         scope(DefaultSession.SCOPE) {
-            RoomSyncHandler(get(), get(), get())
+            RoomSyncHandler(get(), get())
         }
 
         scope(DefaultSession.SCOPE) {