Updated on 2026-08-14

This commit is contained in:
Tangem 2023-12-01 16:35:36 +02:00
parent 199c2795ad
commit 92ee3c0273
10 changed files with 140 additions and 7 deletions

View file

@ -36,6 +36,8 @@ object PreferencesKeys {
val SWAP_TRANSACTIONS_KEY by lazy { stringPreferencesKey(name = "swapTransactions") }
val WALLETS_SCROLL_PREVIEW_KEY by lazy { booleanPreferencesKey(name = "walletsScrollPreview") }
val LAST_SWAPPED_CRYPTOCURRENCY_ID_KEY by lazy { stringPreferencesKey(name = "lastSwappedCryptoCurrency") }
}
/** Preferences keys set that should be migrated from "PreferencesDataSource" to a new DataStore<Preferences> */

View file

@ -3,9 +3,11 @@ package com.tangem.feature.swap
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectList
import com.tangem.datasource.local.preferences.utils.getObjectListSync
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.swap.domain.SwapTransactionRepository
import com.tangem.feature.swap.domain.models.domain.SavedLastSwappedCryptoCurrency
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModel
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionModel
import com.tangem.utils.extensions.addOrReplace
@ -128,6 +130,38 @@ class DefaultSwapTransactionRepository(
}
}
override suspend fun getLastSwappedCryptoCurrencyId(userWalletId: UserWalletId): String? {
val lastSwappedCurrencies = appPreferencesStore.getObjectListSync<SavedLastSwappedCryptoCurrency>(
key = PreferencesKeys.LAST_SWAPPED_CRYPTOCURRENCY_ID_KEY,
)
return lastSwappedCurrencies.find { userWalletId.stringValue == it.userWalletId }?.cryptoCurrencyId
}
override suspend fun storeLastSwappedCryptoCurrencyId(
userWalletId: UserWalletId,
cryptoCurrencyId: CryptoCurrency.ID,
) {
appPreferencesStore.editData { mutablePreferences ->
val lastSwappedCryptoCurrencies: List<SavedLastSwappedCryptoCurrency>? = mutablePreferences.getObjectList(
key = PreferencesKeys.LAST_SWAPPED_CRYPTOCURRENCY_ID_KEY,
)
val newList = if (lastSwappedCryptoCurrencies != null) {
lastSwappedCryptoCurrencies.filter {
it.userWalletId != userWalletId.stringValue
} + SavedLastSwappedCryptoCurrency(userWalletId.stringValue, cryptoCurrencyId.value)
} else {
listOf(SavedLastSwappedCryptoCurrency(userWalletId.stringValue, cryptoCurrencyId.value))
}
mutablePreferences.setObjectList(
key = PreferencesKeys.LAST_SWAPPED_CRYPTOCURRENCY_ID_KEY,
value = newList,
)
}
}
private fun SavedSwapTransactionListModel.checkId(
checkUserWalletId: UserWalletId,
fromCurrencyId: CryptoCurrency.ID,

View file

@ -0,0 +1,33 @@
package com.tangem.feature.swap.domain
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.feature.swap.domain.models.ui.TokensDataStateExpress
import java.math.BigDecimal
internal class DefaultInitialToCurrencyResolver(
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val swapTransactionRepository: SwapTransactionRepository,
) : InitialToCurrencyResolver {
override suspend fun tryGetFromCache(
initialCryptoCurrency: CryptoCurrency,
state: TokensDataStateExpress,
): CryptoCurrencyStatus? {
val selectedId = getSelectedWalletSyncUseCase().getOrNull() ?: return null
val id = swapTransactionRepository.getLastSwappedCryptoCurrencyId(selectedId.walletId) ?: return null
return if (id != initialCryptoCurrency.id.value) {
state.toGroup.available.find { it.currencyStatus.currency.id.value == id }?.currencyStatus
} else {
null
}
}
override fun tryGetWithMaxAmount(state: TokensDataStateExpress): CryptoCurrencyStatus? {
return state.toGroup.available.maxByOrNull {
it.currencyStatus.value.fiatAmount ?: BigDecimal.ZERO
}?.currencyStatus
}
}

View file

@ -0,0 +1,15 @@
package com.tangem.feature.swap.domain
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.feature.swap.domain.models.ui.TokensDataStateExpress
interface InitialToCurrencyResolver {
suspend fun tryGetFromCache(
initialCryptoCurrency: CryptoCurrency,
state: TokensDataStateExpress,
): CryptoCurrencyStatus?
fun tryGetWithMaxAmount(state: TokensDataStateExpress): CryptoCurrencyStatus?
}

View file

@ -85,4 +85,9 @@ interface SwapInteractor {
fun isAvailableToSwap(networkId: String): Boolean
fun getSelectedWallet(): UserWallet?
suspend fun selectInitialCurrencyToSwap(
initialCryptoCurrency: CryptoCurrency,
state: TokensDataStateExpress,
): CryptoCurrencyStatus?
}

View file

@ -43,7 +43,6 @@ internal class SwapInteractorImpl @Inject constructor(
private val transactionManager: TransactionManager,
private val userWalletManager: UserWalletManager,
private val repository: SwapRepository,
private val swapTransactionRepository: SwapTransactionRepository,
private val allowPermissionsHandler: AllowPermissionsHandler,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val getMultiCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusesSyncUseCase,
@ -51,6 +50,8 @@ internal class SwapInteractorImpl @Inject constructor(
private val sendTransactionUseCase: SendTransactionUseCase,
private val quotesRepository: QuotesRepository,
private val dispatcher: CoroutineDispatcherProvider,
private val swapTransactionRepository: SwapTransactionRepository,
private val initialToCurrencyResolver: InitialToCurrencyResolver,
) : SwapInteractor {
private val getFeeUseCase by lazy(LazyThreadSafetyMode.NONE) {
@ -427,6 +428,7 @@ internal class SwapInteractorImpl @Inject constructor(
)
return when (result) {
is SendTxResult.Success -> {
storeLastCryptoCurrencyId(currencyToGet)
TxState.TxSent(
fromAmount = amountFormatter.formatSwapAmountToUI(
amount,
@ -503,6 +505,7 @@ internal class SwapInteractorImpl @Inject constructor(
swapDataModel = exchangeData.dataModel,
timestamp = timestamp,
)
storeLastCryptoCurrencyId(currencyToGet.currency)
TxState.TxSent(
fromAmount = amountFormatter.formatSwapAmountToUI(
amount,
@ -564,6 +567,13 @@ internal class SwapInteractorImpl @Inject constructor(
)
}
private suspend fun storeLastCryptoCurrencyId(cryptoCurrency: CryptoCurrency) {
swapTransactionRepository.storeLastSwappedCryptoCurrencyId(
UserWalletId(userWalletManager.getWalletId()),
cryptoCurrency.id,
)
}
@Deprecated("used in old swap mechanism")
override fun getTokenBalance(token: CryptoCurrencyStatus): SwapAmount {
return SwapAmount(token.value.amount ?: BigDecimal.ZERO, getTokenDecimals(token.currency))
@ -574,6 +584,15 @@ internal class SwapInteractorImpl @Inject constructor(
return ONE_INCH_SUPPORTED_NETWORKS.contains(networkId)
}
override suspend fun selectInitialCurrencyToSwap(
initialCryptoCurrency: CryptoCurrency,
state: TokensDataStateExpress,
): CryptoCurrencyStatus? {
return initialToCurrencyResolver.tryGetFromCache(initialCryptoCurrency, state)
?: initialToCurrencyResolver.tryGetWithMaxAmount(state)
?: state.toGroup.available.firstOrNull()?.currencyStatus
}
@Deprecated("used in old swap mechanism")
private fun getTangemFee(): Double {
return repository.getTangemFee()

View file

@ -26,4 +26,8 @@ interface SwapTransactionRepository {
toCryptoCurrencyId: CryptoCurrency.ID,
txId: String,
)
suspend fun storeLastSwappedCryptoCurrencyId(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID)
suspend fun getLastSwappedCryptoCurrencyId(userWalletId: UserWalletId): String?
}

View file

@ -40,6 +40,7 @@ class SwapDomainModule {
swapTransactionRepository: SwapTransactionRepository,
walletManagersFacade: WalletManagersFacade,
coroutineDispatcherProvider: CoroutineDispatcherProvider,
initialToCurrencyResolver: InitialToCurrencyResolver,
): SwapInteractor {
return SwapInteractorImpl(
transactionManager = transactionManager,
@ -53,6 +54,7 @@ class SwapDomainModule {
walletManagersFacade = walletManagersFacade,
dispatcher = coroutineDispatcherProvider,
swapTransactionRepository = swapTransactionRepository,
initialToCurrencyResolver = initialToCurrencyResolver,
)
}
@ -124,6 +126,18 @@ class SwapDomainModule {
walletManagersFacade = walletManagersFacade,
)
}
@Provides
@Singleton
fun provideInitialToCurrencyResolver(
@SwapScope getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
swapTransactionRepository: SwapTransactionRepository,
): InitialToCurrencyResolver {
return DefaultInitialToCurrencyResolver(
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
swapTransactionRepository = swapTransactionRepository,
)
}
}
@Qualifier

View file

@ -0,0 +1,6 @@
package com.tangem.feature.swap.domain.models.domain
data class SavedLastSwappedCryptoCurrency(
val userWalletId: String,
val cryptoCurrencyId: String,
)

View file

@ -153,7 +153,13 @@ internal class SwapViewModel @Inject constructor(
swapInteractor.getTokensDataState(initialCryptoCurrency)
}.onSuccess { state ->
updateTokensState(state)
applyInitialTokenChoice(state, selectInitialCurrencyToSwap(state))
applyInitialTokenChoice(
state,
swapInteractor.selectInitialCurrencyToSwap(
initialCryptoCurrency,
state,
),
)
}.onFailure {
Timber.tag(loggingTag).e(it)
}
@ -182,11 +188,6 @@ internal class SwapViewModel @Inject constructor(
}
}
private fun selectInitialCurrencyToSwap(state: TokensDataStateExpress): CryptoCurrencyStatus? {
// todo add algorithm to select initial currency
return state.toGroup.available.firstOrNull()?.currencyStatus
}
private fun updateTokensState(dataState: TokensDataStateExpress) {
val tokensDataState = if (!isOrderReversed) dataState.toGroup else dataState.fromGroup
uiState = stateBuilder.addTokensToState(