Updated on 2026-08-14
This commit is contained in:
commit
43c376489a
316 changed files with 7586 additions and 3131 deletions
|
|
@ -34,7 +34,7 @@ interface StakeKitApi {
|
|||
@POST("yields/balances")
|
||||
suspend fun getMultipleYieldBalances(
|
||||
@Body body: List<YieldBalanceRequestBody>,
|
||||
): ApiResponse<List<YieldBalanceWrapperDTO>>
|
||||
): ApiResponse<Set<YieldBalanceWrapperDTO>>
|
||||
|
||||
@POST("yields/{integrationId}/balances")
|
||||
suspend fun getSingleYieldBalance(
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ data class ActionRequestBodyArgs(
|
|||
@Json(name = "ledgerWalletAPICompatible")
|
||||
val ledgerWalletAPICompatible: Boolean? = null,
|
||||
@Json(name = "tronResource")
|
||||
val tronResource: String? = null,
|
||||
val tronResource: TronResource? = null,
|
||||
@Json(name = "signatureVerification")
|
||||
val signatureVerification: SignatureVerification? = null,
|
||||
@Json(name = "inputToken")
|
||||
|
|
@ -60,4 +60,12 @@ data class SignatureVerification(
|
|||
val message: String,
|
||||
@Json(name = "signed")
|
||||
val signed: String,
|
||||
)
|
||||
)
|
||||
|
||||
enum class TronResource {
|
||||
@Json(name = "ENERGY")
|
||||
ENERGY,
|
||||
|
||||
@Json(name = "BANDWIDTH")
|
||||
BANDWIDTH,
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.datasource.api.stakekit.models.response.model.transaction.tron
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class TronStakeKitTransaction(
|
||||
@Json(name = "raw_data_hex")
|
||||
val rawDataHex: String,
|
||||
)
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
package com.tangem.datasource.di
|
||||
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.token.AppPreferencesUserTokensStore
|
||||
import com.tangem.datasource.local.token.UserTokensStore
|
||||
import com.tangem.datasource.local.token.UserTokensStoreMigrationRunner
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object UserTokensStoreModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideUserTokensStore(
|
||||
appPreferencesStore: AppPreferencesStore,
|
||||
userTokensStoreMigrationRunner: UserTokensStoreMigrationRunner,
|
||||
userWalletsStore: UserWalletsStore,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): UserTokensStore {
|
||||
return AppPreferencesUserTokensStore(
|
||||
appPreferencesStore = appPreferencesStore,
|
||||
userTokensStoreMigrationRunner = userTokensStoreMigrationRunner,
|
||||
userWalletsStore = userWalletsStore,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
package com.tangem.datasource.local.token
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.getObject
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
|
||||
import com.tangem.datasource.local.preferences.utils.storeObject
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
/**
|
||||
* Implementation of [UserTokensStore] that based on [appPreferencesStore]
|
||||
*
|
||||
* @property appPreferencesStore application preference store
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class AppPreferencesUserTokensStore(
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val userTokensStoreMigrationRunner: UserTokensStoreMigrationRunner,
|
||||
private val userWalletsStore: UserWalletsStore,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : UserTokensStore {
|
||||
|
||||
init {
|
||||
runUserTokensMigrations()
|
||||
}
|
||||
|
||||
override fun get(key: UserWalletId): Flow<UserTokensResponse> {
|
||||
return appPreferencesStore
|
||||
.getObject<UserTokensResponse>(PreferencesKeys.getUserTokensKey(userWalletId = key.stringValue))
|
||||
.filterNotNull()
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(key: UserWalletId): UserTokensResponse? {
|
||||
return appPreferencesStore.getObjectSyncOrNull(
|
||||
key = PreferencesKeys.getUserTokensKey(userWalletId = key.stringValue),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun store(key: UserWalletId, value: UserTokensResponse) {
|
||||
appPreferencesStore.storeObject(
|
||||
key = PreferencesKeys.getUserTokensKey(userWalletId = key.stringValue),
|
||||
value = value,
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: delete in 5.15 (Mobile Sprint 161) [REDACTED_JIRA]
|
||||
private fun runUserTokensMigrations() {
|
||||
userWalletsStore.userWallets
|
||||
.filter { it.isNotEmpty() }
|
||||
.take(1)
|
||||
.onEach { userWallets ->
|
||||
userTokensStoreMigrationRunner.run(ids = userWallets.map { it.walletId.stringValue })
|
||||
}
|
||||
.flowOn(dispatchers.io)
|
||||
.launchIn(CoroutineScope(dispatchers.io))
|
||||
}
|
||||
}
|
||||
|
|
@ -3,49 +3,53 @@ package com.tangem.datasource.local.token
|
|||
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
internal class DefaultStakingBalanceStore(
|
||||
private val dataStore: StringKeyDataStore<List<YieldBalanceWrapperDTO>>,
|
||||
private val dataStore: StringKeyDataStore<Set<YieldBalanceWrapperDTO>>,
|
||||
) : StakingBalanceStore {
|
||||
|
||||
override fun get(): Flow<List<YieldBalanceWrapperDTO>> {
|
||||
return dataStore.get(STAKING_BALANCE_KEY)
|
||||
private val mutex = Mutex()
|
||||
|
||||
override fun get(userWalletId: UserWalletId): Flow<Set<YieldBalanceWrapperDTO>> {
|
||||
return dataStore.get(userWalletId.stringValue)
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(): List<YieldBalanceWrapperDTO>? {
|
||||
return dataStore.getSyncOrNull(STAKING_BALANCE_KEY)
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId): Set<YieldBalanceWrapperDTO>? {
|
||||
return dataStore.getSyncOrNull(userWalletId.stringValue)
|
||||
}
|
||||
|
||||
override suspend fun store(items: List<YieldBalanceWrapperDTO>) {
|
||||
return dataStore.store(STAKING_BALANCE_KEY, items)
|
||||
override suspend fun store(userWalletId: UserWalletId, items: Set<YieldBalanceWrapperDTO>) {
|
||||
mutex.withLock {
|
||||
dataStore.store(userWalletId.stringValue, items)
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(integrationId: String): Flow<List<BalanceDTO>> {
|
||||
return dataStore.get(STAKING_BALANCE_KEY)
|
||||
override fun get(userWalletId: UserWalletId, integrationId: String): Flow<List<BalanceDTO>> {
|
||||
return dataStore.get(userWalletId.stringValue)
|
||||
.map { balances ->
|
||||
balances.filter { it.integrationId == integrationId }
|
||||
.flatMap { it.balances }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(integrationId: String): List<BalanceDTO>? {
|
||||
return dataStore.getSyncOrNull(STAKING_BALANCE_KEY)
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId, integrationId: String): List<BalanceDTO>? {
|
||||
return dataStore.getSyncOrNull(userWalletId.stringValue)
|
||||
?.firstOrNull { it.integrationId == integrationId }?.balances
|
||||
}
|
||||
|
||||
override suspend fun store(integrationId: String, item: YieldBalanceWrapperDTO) {
|
||||
val balances = dataStore.getSyncOrNull(STAKING_BALANCE_KEY)
|
||||
?.toMutableList()
|
||||
?.addOrReplace(item) { item.integrationId == integrationId }
|
||||
?: listOf(item)
|
||||
override suspend fun store(userWalletId: UserWalletId, integrationId: String, item: YieldBalanceWrapperDTO) {
|
||||
mutex.withLock {
|
||||
val balances = dataStore.getSyncOrNull(userWalletId.stringValue)
|
||||
?.addOrReplace(item) { it.integrationId == integrationId }
|
||||
?: setOf(item)
|
||||
|
||||
return dataStore.store(STAKING_BALANCE_KEY, balances)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val STAKING_BALANCE_KEY = "STAKING_BALANCE_KEY"
|
||||
dataStore.store(userWalletId.stringValue, balances)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,19 +2,20 @@ package com.tangem.datasource.local.token
|
|||
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface StakingBalanceStore {
|
||||
|
||||
fun get(): Flow<List<YieldBalanceWrapperDTO>>
|
||||
fun get(userWalletId: UserWalletId): Flow<Set<YieldBalanceWrapperDTO>>
|
||||
|
||||
suspend fun getSyncOrNull(): List<YieldBalanceWrapperDTO>?
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId): Set<YieldBalanceWrapperDTO>?
|
||||
|
||||
suspend fun store(items: List<YieldBalanceWrapperDTO>)
|
||||
suspend fun store(userWalletId: UserWalletId, items: Set<YieldBalanceWrapperDTO>)
|
||||
|
||||
fun get(integrationId: String): Flow<List<BalanceDTO>>
|
||||
fun get(userWalletId: UserWalletId, integrationId: String): Flow<List<BalanceDTO>>
|
||||
|
||||
suspend fun getSyncOrNull(integrationId: String): List<BalanceDTO>?
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId, integrationId: String): List<BalanceDTO>?
|
||||
|
||||
suspend fun store(integrationId: String, item: YieldBalanceWrapperDTO)
|
||||
suspend fun store(userWalletId: UserWalletId, integrationId: String, item: YieldBalanceWrapperDTO)
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
package com.tangem.datasource.local.token
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Deprecated(
|
||||
message = "Use AppPreferencesStore",
|
||||
replaceWith = ReplaceWith(
|
||||
expression = "AppPreferencesStore",
|
||||
imports = arrayOf("com.tangem.datasource.local.preferences.AppPreferencesStore"),
|
||||
),
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
interface UserTokensStore {
|
||||
|
||||
@Deprecated(
|
||||
message = "Use getObject",
|
||||
replaceWith = ReplaceWith(
|
||||
expression = "appPreferencesStore.getObject(userWalletId)",
|
||||
imports = arrayOf("com.tangem.datasource.local.preferences.AppPreferencesStore"),
|
||||
),
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
fun get(key: UserWalletId): Flow<UserTokensResponse>
|
||||
|
||||
@Deprecated(
|
||||
message = "Use getObjectSyncOrNull",
|
||||
replaceWith = ReplaceWith(
|
||||
expression = "appPreferencesStore.getObjectSyncOrNull(userWalletId)",
|
||||
imports = arrayOf("com.tangem.datasource.local.preferences.AppPreferencesStore"),
|
||||
),
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
suspend fun getSyncOrNull(key: UserWalletId): UserTokensResponse?
|
||||
|
||||
@Deprecated(
|
||||
message = "Use storeObject",
|
||||
replaceWith = ReplaceWith(
|
||||
expression = "appPreferencesStore.storeObject(userWalletId, response)",
|
||||
imports = arrayOf("com.tangem.datasource.local.preferences.AppPreferencesStore"),
|
||||
),
|
||||
level = DeprecationLevel.WARNING,
|
||||
)
|
||||
suspend fun store(key: UserWalletId, value: UserTokensResponse)
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
package com.tangem.datasource.local.token
|
||||
|
||||
import androidx.datastore.core.DataMigration
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.adapter
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.datasource.files.FileReader
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
|
||||
import com.tangem.datasource.local.preferences.utils.storeObject
|
||||
|
||||
/**
|
||||
* Migration of saving [UserTokensResponse] from file to [AppPreferencesStore]
|
||||
*
|
||||
* @param userWalletId user wallet id
|
||||
* @param moshi moshi
|
||||
* @property fileReader file reader
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class UserTokensStoreMigration(
|
||||
userWalletId: String,
|
||||
moshi: Moshi,
|
||||
private val fileReader: FileReader,
|
||||
) : DataMigration<AppPreferencesStore> {
|
||||
|
||||
private val legacyFileName = "user_tokens_$userWalletId"
|
||||
private val keyName = PreferencesKeys.getUserTokensKey(userWalletId = userWalletId)
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private val adapter = moshi.adapter<UserTokensResponse>()
|
||||
|
||||
override suspend fun shouldMigrate(currentData: AppPreferencesStore): Boolean = true
|
||||
|
||||
override suspend fun migrate(currentData: AppPreferencesStore): AppPreferencesStore {
|
||||
val currentKey = currentData.getObjectSyncOrNull<UserTokensResponse>(key = keyName)
|
||||
|
||||
if (currentKey != null) return currentData
|
||||
|
||||
val value = runCatching {
|
||||
val json = fileReader.readFile(legacyFileName)
|
||||
adapter.fromJson(json)
|
||||
}.getOrNull()
|
||||
|
||||
if (value != null) {
|
||||
currentData.storeObject(key = keyName, value = value)
|
||||
}
|
||||
|
||||
return currentData
|
||||
}
|
||||
|
||||
override suspend fun cleanUp() {
|
||||
fileReader.removeFile(legacyFileName)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
package com.tangem.datasource.local.token
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.datasource.di.NetworkMoshi
|
||||
import com.tangem.datasource.files.FileReader
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Runner that launch migrations of saving user tokens store
|
||||
*
|
||||
* @property appPreferencesStore application preference store
|
||||
* @property fileReader file reader
|
||||
* @property moshi moshi
|
||||
* @property dispatchers dispatchers
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Singleton
|
||||
class UserTokensStoreMigrationRunner @Inject constructor(
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val fileReader: FileReader,
|
||||
@NetworkMoshi private val moshi: Moshi,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
suspend fun run(ids: List<String>) {
|
||||
ids.forEach { id ->
|
||||
coroutineScope { run(id) }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun run(id: String) {
|
||||
withContext(dispatchers.io) {
|
||||
val migration = UserTokensStoreMigration(
|
||||
userWalletId = id,
|
||||
moshi = moshi,
|
||||
fileReader = fileReader,
|
||||
)
|
||||
|
||||
migration.migrate(appPreferencesStore)
|
||||
|
||||
migration.cleanUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue