Updated on 2026-08-14

This commit is contained in:
Tangem 2024-11-18 18:04:57 +05:00
parent f1eb31f5f4
commit da6ee825ab
13 changed files with 208 additions and 38 deletions

View file

@ -3,6 +3,7 @@ package com.tangem.tap.di.domain
import com.tangem.domain.onramp.*
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
import com.tangem.domain.onramp.repositories.OnrampRepository
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -63,4 +64,36 @@ internal object OnrampDomainModule {
fun provideGetOnrampCurrencyUseCase(onrampRepository: OnrampRepository): GetOnrampCurrencyUseCase {
return GetOnrampCurrencyUseCase(onrampRepository)
}
@Provides
@Singleton
fun provideGetOnrampTransactionsUseCase(
onrampTransactionRepository: OnrampTransactionRepository,
): GetOnrampTransactionsUseCase {
return GetOnrampTransactionsUseCase(onrampTransactionRepository)
}
@Provides
@Singleton
fun provideGetOnrampTransactionUseCase(
onrampTransactionRepository: OnrampTransactionRepository,
): GetOnrampTransactionUseCase {
return GetOnrampTransactionUseCase(onrampTransactionRepository)
}
@Provides
@Singleton
fun provideOnrampRemoveTransactionUseCase(
onrampTransactionRepository: OnrampTransactionRepository,
): OnrampRemoveTransactionUseCase {
return OnrampRemoveTransactionUseCase(onrampTransactionRepository)
}
@Provides
@Singleton
fun provideOnrampSaveTransactionUseCase(
onrampTransactionRepository: OnrampTransactionRepository,
): OnrampSaveTransactionUseCase {
return OnrampSaveTransactionUseCase(onrampTransactionRepository)
}
}

View file

@ -14,15 +14,11 @@ import com.tangem.blockchain.common.Token as SdkToken
class ResponseCryptoCurrenciesFactory {
fun createCurrency(
currencyId: CryptoCurrency.ID,
response: UserTokensResponse,
scanResponse: ScanResponse,
): CryptoCurrency {
fun createCurrency(currencyId: String, response: UserTokensResponse, scanResponse: ScanResponse): CryptoCurrency {
return response.tokens
.asSequence()
.mapNotNull { createCurrency(it, scanResponse) }
.first { it.id == currencyId }
.first { it.id.value == currencyId }
}
fun createCurrencies(response: UserTokensResponse, scanResponse: ScanResponse): List<CryptoCurrency> {

View file

@ -47,12 +47,12 @@ internal class DefaultOnrampTransactionRepository(
override fun getTransactions(
userWalletId: UserWalletId,
toCryptoCurrency: CryptoCurrency.ID,
cryptoCurrencyId: CryptoCurrency.ID,
): Flow<List<OnrampTransaction>> = appPreferencesStore
.getObjectSet<OnrampTransaction>(PreferencesKeys.ONRAMP_TRANSACTIONS_STATUSES_KEY)
.map { transactions ->
transactions.filter {
it.userWalletId == userWalletId && it.toCurrency.id == toCryptoCurrency
it.userWalletId == userWalletId && it.toCurrencyId == cryptoCurrencyId.value
}
}

View file

@ -293,23 +293,28 @@ internal class DefaultCurrenciesRepository(
userWalletId: UserWalletId,
id: CryptoCurrency.ID,
): CryptoCurrency = withContext(dispatchers.io) {
val userWallet = getUserWallet(userWalletId)
ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = true)
val response = requireNotNull(
value = getSavedUserTokensResponseSync(key = userWalletId),
lazyMessage = {
"Unable to find tokens response for user wallet with provided ID: $userWalletId"
},
)
responseCurrenciesFactory.createCurrency(
currencyId = id,
response = response,
scanResponse = userWallet.scanResponse,
)
getMultiCurrencyWalletCurrency(userWalletId, id.value)
}
override suspend fun getMultiCurrencyWalletCurrency(userWalletId: UserWalletId, id: String): CryptoCurrency =
withContext(dispatchers.io) {
val userWallet = getUserWallet(userWalletId)
ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = true)
val response = requireNotNull(
value = getSavedUserTokensResponseSync(key = userWalletId),
lazyMessage = {
"Unable to find tokens response for user wallet with provided ID: $userWalletId"
},
)
responseCurrenciesFactory.createCurrency(
currencyId = id,
response = response,
scanResponse = userWallet.scanResponse,
)
}
override suspend fun getNetworkCoin(
userWalletId: UserWalletId,
networkId: Network.ID,

View file

@ -23,16 +23,32 @@ data class OnrampStatus(
val paymentMethod: String,
val countryCode: String,
) {
enum class Status {
Created,
Expired,
Paused,
WaitingForPayment,
PaymentProcessing,
Verifying,
Failed,
Paid,
Sending,
Finished,
enum class Status(val order: Int) {
Created(order = 1),
Expired(order = 2),
Paused(order = 3),
WaitingForPayment(order = 4),
PaymentProcessing(order = 5),
Verifying(order = 6),
Failed(order = 7),
Paid(order = 8),
Sending(order = 9),
Finished(order = 10),
;
fun isTerminal(): Boolean = when (this) {
Expired,
Failed,
Paused,
Finished,
-> true
Created,
WaitingForPayment,
PaymentProcessing,
Verifying,
Paid,
Sending,
-> false
}
}
}

View file

@ -2,7 +2,6 @@ package com.tangem.domain.onramp.model.cache
import com.tangem.domain.core.serialization.SerializedBigDecimal
import com.tangem.domain.onramp.model.OnrampCurrency
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.serialization.Serializable
@ -13,8 +12,7 @@ data class OnrampTransaction(
val fromAmount: SerializedBigDecimal,
val fromCurrency: OnrampCurrency,
val toAmount: SerializedBigDecimal,
val toCurrency: CryptoCurrency,
val timestamp: Long,
val toCurrencyId: String,
val providerName: String,
val providerImageUrl: String,
)

View file

@ -0,0 +1,21 @@
package com.tangem.domain.onramp
import arrow.core.Either
import com.tangem.domain.onramp.model.OnrampError
import com.tangem.domain.onramp.model.cache.OnrampTransaction
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
class GetOnrampTransactionUseCase(
private val onrampTransactionRepository: OnrampTransactionRepository,
) {
suspend operator fun invoke(txId: String): Either<OnrampError, OnrampTransaction> {
return Either.catch {
requireNotNull(
onrampTransactionRepository.getTransactionById(txId),
)
}.mapLeft {
OnrampError.UnknownError
}
}
}

View file

@ -0,0 +1,28 @@
package com.tangem.domain.onramp
import arrow.core.Either
import com.tangem.domain.onramp.model.OnrampError
import com.tangem.domain.onramp.model.cache.OnrampTransaction
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.flow.Flow
class GetOnrampTransactionsUseCase(
private val onrampTransactionRepository: OnrampTransactionRepository,
) {
operator fun invoke(
userWalletId: UserWalletId,
cryptoCurrencyId: CryptoCurrency.ID,
): Either<OnrampError, Flow<List<OnrampTransaction>>> {
return Either.catch {
onrampTransactionRepository.getTransactions(
userWalletId = userWalletId,
cryptoCurrencyId = cryptoCurrencyId,
)
}.mapLeft {
OnrampError.UnknownError
}
}
}

View file

@ -0,0 +1,18 @@
package com.tangem.domain.onramp
import arrow.core.Either
import com.tangem.domain.onramp.model.OnrampError
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
class OnrampRemoveTransactionUseCase(
private val onrampTransactionRepository: OnrampTransactionRepository,
) {
suspend operator fun invoke(txId: String): Either<OnrampError, Unit> {
return Either.catch {
onrampTransactionRepository.removeTransaction(txId)
}.mapLeft {
OnrampError.UnknownError
}
}
}

View file

@ -0,0 +1,16 @@
package com.tangem.domain.onramp
import arrow.core.Either
import com.tangem.domain.onramp.model.OnrampError
import com.tangem.domain.onramp.model.cache.OnrampTransaction
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
class OnrampSaveTransactionUseCase(
private val onrampTransactionRepository: OnrampTransactionRepository,
) {
suspend operator fun invoke(transaction: OnrampTransaction): Either<OnrampError, Unit> {
return Either.catch { onrampTransactionRepository.storeTransaction(transaction) }
.mapLeft { OnrampError.UnknownError }
}
}

View file

@ -11,7 +11,7 @@ interface OnrampTransactionRepository {
suspend fun getTransactionById(txId: String): OnrampTransaction?
fun getTransactions(userWalletId: UserWalletId, toCryptoCurrency: CryptoCurrency.ID): Flow<List<OnrampTransaction>>
fun getTransactions(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID): Flow<List<OnrampTransaction>>
suspend fun removeTransaction(txId: String)
}

View file

@ -27,6 +27,22 @@ class GetCryptoCurrencyUseCase(
return either { getCurrency(userWalletId, id) }
}
/**
* Returns specific cryptocurrency for a given user wallet.
*
* !!! Important Use only [CryptoCurrency.ID.value] as cryptoCurrencyId
*
* @param userWalletId The ID of the user's wallet.
* @param cryptoCurrencyId String representation of the [CryptoCurrency.ID.value] of the cryptocurrency.
* @return An [Either] representing success (Right) or an error (Left) in fetching the status.
*/
suspend operator fun invoke(
userWalletId: UserWalletId,
cryptoCurrencyId: String,
): Either<CurrencyStatusError, CryptoCurrency> {
return either { getCurrency(userWalletId, cryptoCurrencyId) }
}
/**
* Returns the primary cryptocurrency for a given user wallet.
*
@ -49,6 +65,18 @@ class GetCryptoCurrencyUseCase(
)
}
private suspend fun Raise<CurrencyStatusError>.getCurrency(
userWalletId: UserWalletId,
id: String,
): CryptoCurrency {
return catch(
block = {
currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, id)
},
catch = { raise(CurrencyStatusError.DataError(it)) },
)
}
private suspend fun Raise<CurrencyStatusError>.getPrimaryCurrency(userWalletId: UserWalletId): CryptoCurrency {
return catch(
block = { currenciesRepository.getSingleCurrencyWalletPrimaryCurrency(userWalletId) },

View file

@ -167,6 +167,17 @@ interface CurrenciesRepository {
*/
suspend fun getMultiCurrencyWalletCurrency(userWalletId: UserWalletId, id: CryptoCurrency.ID): CryptoCurrency
/**
* Retrieves the cryptocurrency for a specific multi-currency user wallet.
*
* @param userWalletId The unique identifier of the user wallet.
* @param id The unique identifier of the cryptocurrency to be retrieved.
* @return The cryptocurrency associated with the user wallet and ID.
* @throws DataError.UserWalletError.WrongUserWallet If single-currency user wallet
* ID provided.
*/
suspend fun getMultiCurrencyWalletCurrency(userWalletId: UserWalletId, id: String): CryptoCurrency
/**
* Get the coin for a specific network.
*