Updated on 2026-08-14

This commit is contained in:
Tangem 2024-09-25 19:32:55 +04:00
parent fa056925a0
commit 9617fd5777
19 changed files with 0 additions and 477 deletions

View file

@ -22,14 +22,6 @@ import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
internal object CardDomainModule {
@Provides
@Singleton
fun provideGetBiometricsStatusUseCase(
cardSdkConfigRepository: CardSdkConfigRepository,
): GetBiometricsStatusUseCase {
return GetBiometricsStatusUseCase(cardSdkConfigRepository = cardSdkConfigRepository)
}
@Provides
@Singleton
fun provideSetAccessCodeRequestPolicyUseCase(
@ -38,12 +30,6 @@ internal object CardDomainModule {
return SetAccessCodeRequestPolicyUseCase(cardSdkConfigRepository = cardSdkConfigRepository)
}
@Provides
@Singleton
fun provideWasWalletAlreadySignedHashesConfirmedUseCase(cardRepository: CardRepository): WasCardScannedUseCase {
return WasCardScannedUseCase(cardRepository = cardRepository)
}
@Provides
@Singleton
fun provideSetCardWasScannedUseCase(cardRepository: CardRepository): SetCardWasScannedUseCase {

View file

@ -285,12 +285,6 @@ internal object TokensDomainModule {
)
}
@Provides
@Singleton
fun provideGetCurrenciesUseCase(currenciesRepository: CurrenciesRepository): GetCryptoCurrenciesUseCase {
return GetCryptoCurrenciesUseCase(currenciesRepository = currenciesRepository)
}
@Provides
@Singleton
fun provideIsCryptoCurrencyCoinCouldHideUseCase(
@ -311,46 +305,6 @@ internal object TokensDomainModule {
)
}
@Provides
@Singleton
fun provideHasMissedAddressesCryptoCurrenciesUseCase(
currenciesRepository: CurrenciesRepository,
): GetMissedAddressesCryptoCurrenciesUseCase {
return GetMissedAddressesCryptoCurrenciesUseCase(currenciesRepository = currenciesRepository)
}
@Provides
@Singleton
fun provideCheckTokenCompatibilityUseCase(
networksCompatibilityRepository: NetworksCompatibilityRepository,
): CheckCurrencyCompatibilityUseCase {
return CheckCurrencyCompatibilityUseCase(networksCompatibilityRepository)
}
@Provides
@Singleton
fun provideNeedHardenedDerivationUseCase(
networksCompatibilityRepository: NetworksCompatibilityRepository,
): RequiresHardenedDerivationOnlyUseCase {
return RequiresHardenedDerivationOnlyUseCase(networksCompatibilityRepository)
}
@Provides
@Singleton
fun provideAreTokensSupportedByNetworkUseCase(
repository: NetworksCompatibilityRepository,
): AreTokensSupportedByNetworkUseCase {
return AreTokensSupportedByNetworkUseCase(repository = repository)
}
@Provides
@Singleton
fun provideGetNetworksSupportedByWallet(
repository: NetworksCompatibilityRepository,
): GetNetworksSupportedByWallet {
return GetNetworksSupportedByWallet(repository = repository)
}
@Provides
@Singleton
fun provideGetBalanceNotEnoughForFeeWarningUseCase(

View file

@ -30,12 +30,6 @@ internal class DefaultCardSdkConfigRepository(private val cardSdkProvider: CardS
}
}
override fun isBiometricsRequestPolicy(): Boolean {
return with(sdk.config.userCodeRequestPolicy) {
this is UserCodeRequestPolicy.AlwaysWithBiometrics && codeType == UserCodeType.AccessCode
}
}
override fun resetCardIdDisplayFormat() {
sdk.config.cardIdDisplayFormat = CardIdDisplayFormat.Full
}

View file

@ -93,15 +93,6 @@ internal object TokensDataModule {
return DefaultMarketCryptoCurrencyRepository(expressAssetsStore, coroutineDispatcherProvider)
}
@Provides
@Singleton
fun provideCardNetworksRepository(
userWalletsStore: UserWalletsStore,
dispatchers: CoroutineDispatcherProvider,
): NetworksCompatibilityRepository {
return DefaultNetworksCompatibilityRepository(userWalletsStore = userWalletsStore, dispatchers = dispatchers)
}
@Provides
@Singleton
fun provideCurrencyChecksRepository(walletManagersFacade: WalletManagersFacade): CurrencyChecksRepository {

View file

@ -27,7 +27,6 @@ import com.tangem.datasource.local.preferences.utils.storeObject
import com.tangem.datasource.local.token.ExpressAssetsStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.common.util.hasDerivation
import com.tangem.domain.core.error.DataError
import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.core.lce.lceFlow
@ -376,24 +375,6 @@ internal class DefaultCurrenciesRepository(
}.cancellable()
}
override fun getMissedAddressesCryptoCurrencies(userWalletId: UserWalletId): Flow<List<CryptoCurrency>> {
return channelFlow {
ensureIsCorrectUserWallet(userWalletId, isMultiCurrencyWalletExpected = true)
val userWallet = getUserWallet(userWalletId = userWalletId)
getMultiCurrencyWalletCurrencies(userWallet = userWallet)
.map {
it.filter { currency ->
val blockchain = Blockchain.fromId(id = currency.network.id.value)
val derivationPath = currency.network.derivationPath.value
derivationPath != null && !userWallet.scanResponse.hasDerivation(blockchain, derivationPath)
}
}
.collectLatest(::send)
}
}
override fun isSendBlockedByPendingTransactions(
cryptoCurrencyStatus: CryptoCurrencyStatus,
coinStatus: CryptoCurrencyStatus?,

View file

@ -1,101 +0,0 @@
package com.tangem.data.tokens.repository
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.common.card.EllipticCurve
import com.tangem.data.common.currency.getNetwork
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.common.configs.CardConfig
import com.tangem.domain.common.extensions.*
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.tokens.repository.NetworksCompatibilityRepository
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext
internal class DefaultNetworksCompatibilityRepository(
private val userWalletsStore: UserWalletsStore,
private val dispatchers: CoroutineDispatcherProvider,
) : NetworksCompatibilityRepository {
/**
* @return returns true if either the network is not Solana (check is not relevant) or if it is Solana and
* UserWallet supports tokens on Solana Network
*/
@Throws(IllegalArgumentException::class)
override suspend fun areSolanaTokensSupportedIfRelevant(networkId: String, userWalletId: UserWalletId): Boolean {
return withContext(dispatchers.io) {
val scanResponse = getWalletOrThrow(userWalletId).scanResponse
val blockchain = getBlockchainOrThrow(networkId)
val blockchainsSupportingTokens = scanResponse.card.supportedTokens(scanResponse.cardTypesResolver)
blockchain != Blockchain.Solana || blockchainsSupportingTokens.contains(Blockchain.Solana)
}
}
@Throws(IllegalArgumentException::class)
override suspend fun areTokensSupportedByNetwork(networkId: String, userWalletId: UserWalletId): Boolean {
return withContext(dispatchers.io) {
val scanResponse = getWalletOrThrow(userWalletId).scanResponse
val blockchain = getBlockchainOrThrow(networkId)
val blockchainsSupportingTokens = scanResponse.card.supportedTokens(scanResponse.cardTypesResolver)
scanResponse.card.canHandleToken(
supportedTokens = blockchainsSupportingTokens,
blockchain = blockchain,
cardTypesResolver = scanResponse.cardTypesResolver,
)
}
}
@Throws(IllegalArgumentException::class)
override suspend fun isNetworkSupported(networkId: String, userWalletId: UserWalletId): Boolean {
return withContext(dispatchers.io) {
val scanResponse = getWalletOrThrow(userWalletId).scanResponse
val blockchain = getBlockchainOrThrow(networkId)
scanResponse.card.canHandleBlockchain(
blockchain = blockchain,
cardTypesResolver = scanResponse.cardTypesResolver,
)
}
}
@Throws(IllegalArgumentException::class)
override suspend fun getSupportedNetworks(userWalletId: UserWalletId): List<Network> {
val scanResponse = getWalletOrThrow(userWalletId).scanResponse
return Blockchain.entries
.filter { blockchain ->
scanResponse.card.supportedBlockchains(scanResponse.cardTypesResolver).contains(blockchain)
}
.sortedBy(Blockchain::fullName)
.mapNotNull { blockchain ->
getNetwork(blockchain, null, scanResponse.derivationStyleProvider)
}
}
override suspend fun requiresHardenedDerivationOnly(networkId: String, userWalletId: UserWalletId): Boolean {
val scanResponse = getWalletOrThrow(userWalletId).scanResponse
val config = CardConfig.createConfig(scanResponse.card)
val blockchain = Blockchain.fromNetworkId(networkId) ?: return false
return config.primaryCurve(blockchain) == EllipticCurve.Ed25519Slip0010 &&
scanResponse.cardTypesResolver.isWallet2()
}
override fun areTokensSupportedByNetwork(networkId: String): Boolean {
return Blockchain.fromNetworkId(networkId)?.canHandleTokens() ?: false
}
private suspend fun getWalletOrThrow(userWalletId: UserWalletId): UserWallet {
return requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
"Requested UserWallet not found"
}
}
private fun getBlockchainOrThrow(networkId: String): Blockchain {
return requireNotNull(Blockchain.fromNetworkId(networkId)) {
"Requested network not found"
}
}
}

View file

@ -1,15 +0,0 @@
package com.tangem.domain.card
import com.tangem.domain.card.repository.CardSdkConfigRepository
/**
* Check if config has biometrics request policy
*
* @property cardSdkConfigRepository repository for managing of CardSDK config
*
[REDACTED_AUTHOR]
*/
class GetBiometricsStatusUseCase(private val cardSdkConfigRepository: CardSdkConfigRepository) {
operator fun invoke(): Boolean = cardSdkConfigRepository.isBiometricsRequestPolicy()
}

View file

@ -1,9 +0,0 @@
package com.tangem.domain.card
import com.tangem.domain.card.repository.CardRepository
import kotlinx.coroutines.flow.Flow
class WasCardScannedUseCase(private val cardRepository: CardRepository) {
operator fun invoke(cardId: String): Flow<Boolean> = cardRepository.wasCardScanned(cardId)
}

View file

@ -18,9 +18,6 @@ interface CardSdkConfigRepository {
/** Set access code request policy by [isBiometricsRequestPolicy] */
fun setAccessCodeRequestPolicy(isBiometricsRequestPolicy: Boolean)
/** Check if config has biometrics request policy */
fun isBiometricsRequestPolicy(): Boolean
/** Reset the card ID display format to start value */
fun resetCardIdDisplayFormat()

View file

@ -1,34 +0,0 @@
package com.tangem.domain.tokens
import arrow.core.Either
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.domain.tokens.repository.NetworksCompatibilityRepository
import com.tangem.domain.wallets.models.UserWalletId
class AreTokensSupportedByNetworkUseCase(private val repository: NetworksCompatibilityRepository) {
suspend operator fun invoke(networkId: String, userWalletId: UserWalletId?): Either<Throwable, Boolean> {
return either {
catch(
block = {
if (userWalletId == null) {
repository.areTokensSupportedByNetwork(networkId)
} else {
repository.areTokensSupportedByNetwork(networkId, userWalletId)
}
},
catch = { throwable -> raise(throwable) },
)
}
}
operator fun invoke(networkId: String): Either<Throwable, Boolean> {
return either {
catch(
block = { repository.areTokensSupportedByNetwork(networkId) },
catch = { throwable -> raise(throwable) },
)
}
}
}

View file

@ -1,53 +0,0 @@
package com.tangem.domain.tokens
import arrow.core.Either
import arrow.core.left
import arrow.core.raise.catch
import arrow.core.raise.either
import arrow.core.right
import com.tangem.domain.tokens.repository.NetworksCompatibilityRepository
import com.tangem.domain.wallets.models.UserWalletId
class CheckCurrencyCompatibilityUseCase(private val repository: NetworksCompatibilityRepository) {
suspend operator fun invoke(
networkId: String,
isMainNetwork: Boolean,
userWalletId: UserWalletId,
): Either<CurrencyCompatibilityError, Unit> {
return either {
catch(
block = {
val error = getErrorIfNotSupported(networkId, isMainNetwork, userWalletId)
error?.left() ?: Unit.right()
},
catch = { raise(CurrencyCompatibilityError.UnsupportedBlockchain) },
)
}
}
@Throws(IllegalArgumentException::class)
private suspend fun getErrorIfNotSupported(
networkId: String,
isMainNetwork: Boolean,
userWalletId: UserWalletId,
): CurrencyCompatibilityError? {
if (isMainNetwork) {
val supported = repository.isNetworkSupported(networkId, userWalletId)
if (!supported) return CurrencyCompatibilityError.UnsupportedBlockchain
} else {
val solanaTokensSupportedOrNotSolanaNetwork =
repository.areSolanaTokensSupportedIfRelevant(networkId, userWalletId)
if (!solanaTokensSupportedOrNotSolanaNetwork) return CurrencyCompatibilityError.SolanaTokensUnsupported
val tokensSupported = repository.areTokensSupportedByNetwork(networkId, userWalletId)
if (!tokensSupported) return CurrencyCompatibilityError.UnsupportedCurve
}
return null
}
}
sealed class CurrencyCompatibilityError {
object SolanaTokensUnsupported : CurrencyCompatibilityError()
object UnsupportedCurve : CurrencyCompatibilityError()
object UnsupportedBlockchain : CurrencyCompatibilityError()
}

View file

@ -1,35 +0,0 @@
package com.tangem.domain.tokens
import arrow.core.Either
import arrow.core.left
import arrow.core.raise.catch
import arrow.core.raise.either
import arrow.core.right
import com.tangem.domain.tokens.error.GetCurrenciesError
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
class GetCryptoCurrenciesUseCase(private val currenciesRepository: CurrenciesRepository) {
operator fun invoke(userWalletId: UserWalletId): Flow<Either<GetCurrenciesError, List<CryptoCurrency>>> {
return currenciesRepository.getMultiCurrencyWalletCurrenciesUpdates(userWalletId)
.map<List<CryptoCurrency>, Either<GetCurrenciesError, List<CryptoCurrency>>> { it.right() }
.catch { emit(GetCurrenciesError.DataError(it).left()) }
}
suspend fun getSync(
userWalletId: UserWalletId,
refresh: Boolean = false,
): Either<GetCurrenciesError, List<CryptoCurrency>> {
return either {
catch(
block = { currenciesRepository.getMultiCurrencyWalletCurrenciesSync(userWalletId, refresh) },
catch = { raise(GetCurrenciesError.DataError(it)) },
)
}
}
}

View file

@ -1,48 +0,0 @@
package com.tangem.domain.tokens
import arrow.core.Either
import arrow.core.left
import arrow.core.raise.either
import arrow.core.right
import com.tangem.domain.tokens.error.GetCurrenciesError
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
/**
* Use case for retrieving a list of cryptocurrencies ([CryptoCurrency]) added to a specific wallet and requiring derivation
* (for which address is not available until the public key is derived on a card).
*/
class GetMissedAddressesCryptoCurrenciesUseCase(private val currenciesRepository: CurrenciesRepository) {
/**
* Retrieves a list of cryptocurrencies without an address (requiring derivation) for a given user wallet.
* @param userWalletId: Specifies the wallet by its ID
*/
operator fun invoke(userWalletId: UserWalletId): Flow<Either<GetCurrenciesError, List<CryptoCurrency>>> {
return currenciesRepository.getMissedAddressesCryptoCurrencies(userWalletId)
.map<List<CryptoCurrency>, Either<GetCurrenciesError, List<CryptoCurrency>>>(List<CryptoCurrency>::right)
.catch { emit(GetCurrenciesError.DataError(it).left()) }
}
/**
* Retrieves a map containing lists of cryptocurrencies without an address (requiring derivation) grouped by
* user wallet IDs.
* @param userWalletIds: List of IDs specifying the user wallets
*/
operator fun invoke(
userWalletIds: List<UserWalletId>,
): Flow<Either<GetCurrenciesError, Map<UserWalletId, List<CryptoCurrency>>>> {
return combine(
userWalletIds.map { userWalletId -> invoke(userWalletId) },
) { missedAddressesCryptoCurrenciesResult ->
userWalletIds.zip(missedAddressesCryptoCurrenciesResult).toMap().let { map ->
either { map.bindAll() } // taking out Left if encountered in inner responses
}
}.catch { cause -> emit(GetCurrenciesError.DataError(cause).left()) }
}
}

View file

@ -1,23 +0,0 @@
package com.tangem.domain.tokens
import arrow.core.Either
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.tokens.repository.NetworksCompatibilityRepository
import com.tangem.domain.wallets.models.UserWalletId
class GetNetworksSupportedByWallet(
private val repository: NetworksCompatibilityRepository,
) {
suspend operator fun invoke(userWalletId: UserWalletId): Either<Throwable, List<Network>> {
return either {
catch(
block = {
repository.getSupportedNetworks(userWalletId)
},
catch = { throwable -> raise(throwable) },
)
}
}
}

View file

@ -1,26 +0,0 @@
package com.tangem.domain.tokens
import arrow.core.Either
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.domain.tokens.repository.NetworksCompatibilityRepository
import com.tangem.domain.wallets.models.UserWalletId
/**
* Ed25519Slip0010 requires only hardened derivations on Wallet 2
*/
class RequiresHardenedDerivationOnlyUseCase(
private val repository: NetworksCompatibilityRepository,
) {
suspend operator fun invoke(networkId: String, userWalletId: UserWalletId): Either<Throwable, Boolean> {
return either {
catch(
block = {
repository.requiresHardenedDerivationOnly(networkId, userWalletId)
},
catch = { throwable -> raise(throwable) },
)
}
}
}

View file

@ -1,6 +0,0 @@
package com.tangem.domain.tokens.error
sealed class GetCurrenciesError {
data class DataError(val cause: Throwable) : GetCurrenciesError()
}

View file

@ -204,8 +204,6 @@ interface CurrenciesRepository {
*/
fun isTokensSortedByBalance(userWalletId: UserWalletId): Flow<Boolean>
fun getMissedAddressesCryptoCurrencies(userWalletId: UserWalletId): Flow<List<CryptoCurrency>>
/**
* Determines whether the currency sending is blocked by network pending transaction
*

View file

@ -1,23 +0,0 @@
package com.tangem.domain.tokens.repository
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.wallets.models.UserWalletId
interface NetworksCompatibilityRepository {
@Throws(IllegalArgumentException::class)
suspend fun areSolanaTokensSupportedIfRelevant(networkId: String, userWalletId: UserWalletId): Boolean
@Throws(IllegalArgumentException::class)
suspend fun areTokensSupportedByNetwork(networkId: String, userWalletId: UserWalletId): Boolean
@Throws(IllegalArgumentException::class)
suspend fun isNetworkSupported(networkId: String, userWalletId: UserWalletId): Boolean
@Throws(IllegalArgumentException::class)
suspend fun getSupportedNetworks(userWalletId: UserWalletId): List<Network>
suspend fun requiresHardenedDerivationOnly(networkId: String, userWalletId: UserWalletId): Boolean
fun areTokensSupportedByNetwork(networkId: String): Boolean
}

View file

@ -106,11 +106,6 @@ internal class MockCurrenciesRepository(
return token
}
override fun getMissedAddressesCryptoCurrencies(userWalletId: UserWalletId): Flow<List<CryptoCurrency>> {
/* no-op */
return emptyFlow()
}
override suspend fun getNetworkCoin(
userWalletId: UserWalletId,
networkId: Network.ID,