Updated on 2026-08-14

This commit is contained in:
Tangem 2025-02-12 23:05:18 +04:00
parent 777a05d716
commit 561b7b892c
7 changed files with 88 additions and 25 deletions

View file

@ -56,6 +56,7 @@ class MoshiModule {
ExtendedPublicKeysMapAdapter(),
CardBackupStatusAdapter(),
DerivationPathAdapterWithMigration(),
DateTimeAdapter(),
)
val typedAdapters = MoshiJsonConverter.getTangemSdkTypedAdapters()

View file

@ -1,13 +1,20 @@
package com.tangem.datasource.di
import android.content.Context
import androidx.datastore.core.DataStoreFactory
import androidx.datastore.dataStoreFile
import com.squareup.moshi.Moshi
import com.tangem.datasource.local.datastore.RuntimeDataStore
import com.tangem.datasource.local.token.*
import com.tangem.datasource.local.token.DefaultStakingBalanceStore
import com.tangem.datasource.local.token.DefaultStakingYieldsStore
import com.tangem.datasource.local.token.utils.YieldBalancesSerializer
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import javax.inject.Singleton
@Module
@ -22,8 +29,18 @@ internal object StakingStoreModule {
@Provides
@Singleton
fun provideStakingBalanceStore(): StakingBalanceStore {
return DefaultStakingBalanceStore(dataStore = RuntimeDataStore())
fun provideStakingBalanceStore(
@NetworkMoshi moshi: Moshi,
@ApplicationContext context: Context,
dispatchers: CoroutineDispatcherProvider,
): StakingBalanceStore {
return DefaultStakingBalanceStore(
dataStore = DataStoreFactory.create(
serializer = YieldBalancesSerializer(moshi),
produceFile = { context.dataStoreFile(fileName = "yield_balances") },
scope = CoroutineScope(context = dispatchers.io + SupervisorJob()),
),
)
}
@Provides

View file

@ -1,31 +1,32 @@
package com.tangem.datasource.local.token
import androidx.datastore.core.DataStore
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import com.tangem.datasource.local.token.entity.YieldBalanceWrappersDTO
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.utils.extensions.addOrReplace
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
internal class DefaultStakingBalanceStore(
private val dataStore: StringKeyDataStore<Set<YieldBalanceWrapperDTO>>,
private val dataStore: DataStore<YieldBalanceWrappersDTO>,
) : StakingBalanceStore {
private val mutex = Mutex()
override fun get(userWalletId: UserWalletId): Flow<Set<YieldBalanceWrapperDTO>> {
return dataStore.get(userWalletId.stringValue)
return dataStore.data.map { it[userWalletId.stringValue].orEmpty() }
}
override suspend fun getSyncOrNull(userWalletId: UserWalletId): Set<YieldBalanceWrapperDTO>? {
return dataStore.getSyncOrNull(userWalletId.stringValue)
return dataStore.data.firstOrNull()
?.get(userWalletId.stringValue)
}
override suspend fun store(userWalletId: UserWalletId, items: Set<YieldBalanceWrapperDTO>) {
mutex.withLock {
dataStore.store(userWalletId.stringValue, items)
dataStore.updateData { current ->
current.toMutableMap().apply {
this[userWalletId.stringValue] = items
}
}
}
@ -34,7 +35,7 @@ internal class DefaultStakingBalanceStore(
address: String,
integrationId: String,
): Flow<YieldBalanceWrapperDTO?> {
return dataStore.get(userWalletId.stringValue)
return get(userWalletId)
.map { balances ->
balances.firstOrNull { it.integrationId == integrationId && it.addresses.address == address }
}
@ -45,7 +46,7 @@ internal class DefaultStakingBalanceStore(
address: String,
integrationId: String,
): YieldBalanceWrapperDTO? {
return dataStore.getSyncOrNull(userWalletId.stringValue)
return getSyncOrNull(userWalletId)
?.firstOrNull { it.integrationId == integrationId && it.addresses.address == address }
}
@ -55,12 +56,10 @@ internal class DefaultStakingBalanceStore(
address: String,
item: YieldBalanceWrapperDTO,
) {
mutex.withLock {
val balances = dataStore.getSyncOrNull(userWalletId.stringValue)
?.addOrReplace(item) { it.integrationId == integrationId && it.addresses.address == address }
?: setOf(item)
val balances = getSyncOrNull(userWalletId)
?.addOrReplace(item) { it.integrationId == integrationId && it.addresses.address == address }
?: setOf(item)
dataStore.store(userWalletId.stringValue, balances)
}
store(userWalletId, balances)
}
}

View file

@ -0,0 +1,5 @@
package com.tangem.datasource.local.token.entity
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
internal typealias YieldBalanceWrappersDTO = Map<String, Set<YieldBalanceWrapperDTO>>

View file

@ -0,0 +1,36 @@
package com.tangem.datasource.local.token.utils
import androidx.datastore.core.Serializer
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
import com.tangem.datasource.local.token.entity.YieldBalanceWrappersDTO
import java.io.InputStream
import java.io.OutputStream
internal class YieldBalancesSerializer(moshi: Moshi) : Serializer<YieldBalanceWrappersDTO> {
private val adapter by lazy {
val type = Types.newParameterizedType(
Map::class.java,
String::class.java,
Types.newParameterizedType(Set::class.java, YieldBalanceWrapperDTO::class.java),
)
moshi.adapter<YieldBalanceWrappersDTO>(type)
}
override val defaultValue: YieldBalanceWrappersDTO = emptyMap()
override suspend fun readFrom(input: InputStream): YieldBalanceWrappersDTO {
return input.bufferedReader().use { reader ->
adapter.fromJson(reader.readText()) ?: defaultValue
}
}
override suspend fun writeTo(t: YieldBalanceWrappersDTO, output: OutputStream) {
output.bufferedWriter().use { writer ->
writer.write(adapter.toJson(t))
}
}
}

View file

@ -484,7 +484,9 @@ internal class DefaultStakingRepository(
userWalletId: UserWalletId,
cryptoCurrencies: List<CryptoCurrency>,
): Flow<YieldBalanceList> {
TODO("Will be implemented in [REDACTED_TASK_KEY]")
return stakingBalanceStore.get(userWalletId)
.map(yieldBalanceListConverter::convert)
.flowOn(dispatchers.io)
}
override fun getMultiYieldBalanceUpdatesLegacy(

View file

@ -4,7 +4,7 @@ import com.squareup.moshi.Moshi
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.data.common.cache.CacheRegistry
import com.tangem.data.staking.*
import com.tangem.data.staking.DefaultStakingActionRepository
import com.tangem.data.staking.DefaultStakingErrorResolver
import com.tangem.data.staking.DefaultStakingRepository
import com.tangem.data.staking.DefaultStakingTransactionHashRepository
@ -17,7 +17,10 @@ import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.token.StakingActionsStore
import com.tangem.datasource.local.token.StakingBalanceStore
import com.tangem.datasource.local.token.StakingYieldsStore
import com.tangem.domain.staking.repositories.*
import com.tangem.domain.staking.repositories.StakingActionRepository
import com.tangem.domain.staking.repositories.StakingErrorResolver
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.staking.repositories.StakingTransactionHashRepository
import com.tangem.domain.staking.toggles.StakingFeatureToggles
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase