Updated on 2026-08-14
This commit is contained in:
parent
0a78db08ec
commit
db358d8014
16 changed files with 303 additions and 8 deletions
|
|
@ -1,6 +1,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 dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -48,6 +49,15 @@ internal object OnrampDomainModule {
|
|||
return CheckOnrampAvailabilityUseCase(onrampRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampStatusUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampStatusUseCase {
|
||||
return GetOnrampStatusUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampCurrencyUseCase(onrampRepository: OnrampRepository): GetOnrampCurrencyUseCase {
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ data class OnrampStatusResponse(
|
|||
@Json(name = "payoutAddress")
|
||||
val payoutAddress: String,
|
||||
|
||||
// @Json(name = "status")
|
||||
// val status: ???
|
||||
@Json(name = "status")
|
||||
val status: Status,
|
||||
|
||||
@Json(name = "failReason")
|
||||
val failReason: String?,
|
||||
|
|
@ -48,14 +48,46 @@ data class OnrampStatusResponse(
|
|||
val toDecimals: String,
|
||||
|
||||
@Json(name = "toAmount")
|
||||
val toAmount: String,
|
||||
val toAmount: String?,
|
||||
|
||||
@Json(name = "toActualAmount")
|
||||
val toActualAmount: String,
|
||||
val toActualAmount: String?,
|
||||
|
||||
@Json(name = "paymentMethod")
|
||||
val paymentMethod: String,
|
||||
|
||||
@Json(name = "countryCode")
|
||||
val countryCode: String,
|
||||
)
|
||||
)
|
||||
|
||||
enum class Status {
|
||||
@Json(name = "created")
|
||||
Created,
|
||||
|
||||
@Json(name = "expired")
|
||||
Expired,
|
||||
|
||||
@Json(name = "waiting-for-payment")
|
||||
WaitingForPayment,
|
||||
|
||||
@Json(name = "payment-processing")
|
||||
PaymentProcessing,
|
||||
|
||||
@Json(name = "verifying")
|
||||
Verifying,
|
||||
|
||||
@Json(name = "failed")
|
||||
Failed,
|
||||
|
||||
@Json(name = "paid")
|
||||
Paid,
|
||||
|
||||
@Json(name = "sending")
|
||||
Sending,
|
||||
|
||||
@Json(name = "finished")
|
||||
Finished,
|
||||
|
||||
@Json(name = "paused")
|
||||
Paused,
|
||||
}
|
||||
|
|
@ -107,6 +107,8 @@ object PreferencesKeys {
|
|||
|
||||
val ONRAMP_DEFAULT_COUNTRY by lazy { stringPreferencesKey(name = "onrampDefaultCountry") }
|
||||
|
||||
val ONRAMP_TRANSACTIONS_STATUSES_KEY by lazy { stringPreferencesKey(name = "onrampTransactionsStatuses") }
|
||||
|
||||
// region Permission
|
||||
fun getShouldShowPermission(permission: String) = booleanPreferencesKey("shouldShowPushPermission_$permission")
|
||||
|
||||
|
|
|
|||
|
|
@ -150,4 +150,12 @@ suspend inline fun <reified T> AppPreferencesStore.getObjectSetSync(key: Prefere
|
|||
?.get(key)
|
||||
?.let(adapter::fromJson)
|
||||
.orEmpty()
|
||||
}
|
||||
|
||||
/** Get flow of set of [T] by string [key], or empty if data is not found */
|
||||
inline fun <reified T> AppPreferencesStore.getObjectSet(key: Preferences.Key<String>): Flow<Set<T>> {
|
||||
val adapter = moshi.adapter<Set<T>>(Types.newParameterizedType(Set::class.java, T::class.java))
|
||||
return data.map {
|
||||
it[key]?.let(adapter::fromJson) ?: emptySet()
|
||||
}
|
||||
}
|
||||
|
|
@ -5,9 +5,9 @@ import com.tangem.datasource.api.common.response.ApiResponseError
|
|||
import com.tangem.domain.onramp.model.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
|
||||
internal class DefaultOnrampErrorResolver(
|
||||
private val onrampErrorConverter: OnrampErrorConverter,
|
||||
) : OnrampErrorResolver {
|
||||
internal class DefaultOnrampErrorResolver : OnrampErrorResolver {
|
||||
|
||||
private val onrampErrorConverter = OnrampErrorConverter()
|
||||
|
||||
override fun resolve(throwable: Throwable): OnrampError {
|
||||
return if (throwable is ApiResponseError.HttpException) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.data.onramp
|
|||
|
||||
import com.tangem.data.onramp.converters.CountryConverter
|
||||
import com.tangem.data.onramp.converters.CurrencyConverter
|
||||
import com.tangem.data.onramp.converters.StatusConverter
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.onramp.OnrampApi
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampCountryDTO
|
||||
|
|
@ -13,6 +14,7 @@ import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
|
|||
import com.tangem.datasource.local.preferences.utils.storeObject
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -27,6 +29,7 @@ internal class DefaultOnrampRepository(
|
|||
|
||||
private val currencyConverter = CurrencyConverter()
|
||||
private val countryConverter = CountryConverter(currencyConverter)
|
||||
private val statusConverter = StatusConverter()
|
||||
|
||||
override suspend fun getCurrencies(): List<OnrampCurrency> = withContext(dispatchers.io) {
|
||||
onrampApi.getCurrencies()
|
||||
|
|
@ -46,6 +49,12 @@ internal class DefaultOnrampRepository(
|
|||
.let(countryConverter::convert)
|
||||
}
|
||||
|
||||
override suspend fun getStatus(txId: String): OnrampStatus = withContext(dispatchers.io) {
|
||||
onrampApi.getStatus(txId)
|
||||
.getOrThrow()
|
||||
.let(statusConverter::convert)
|
||||
}
|
||||
|
||||
override suspend fun saveDefaultCurrency(currency: OnrampCurrency) = withContext(dispatchers.io) {
|
||||
appPreferencesStore.storeObject<OnrampCurrencyDTO>(
|
||||
key = PreferencesKeys.ONRAMP_DEFAULT_CURRENCY,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
package com.tangem.data.onramp
|
||||
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectSet
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectSetSync
|
||||
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 com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
internal class DefaultOnrampTransactionRepository(
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : OnrampTransactionRepository {
|
||||
|
||||
override suspend fun storeTransaction(transaction: OnrampTransaction) {
|
||||
withContext(dispatchers.io) {
|
||||
appPreferencesStore.editData { mutablePreferences ->
|
||||
val stored = mutablePreferences.getObjectSet<OnrampTransaction>(
|
||||
PreferencesKeys.ONRAMP_TRANSACTIONS_STATUSES_KEY,
|
||||
)
|
||||
val updated = stored?.toMutableSet()
|
||||
?.addOrReplace(transaction) { it.txId == transaction.txId }
|
||||
?: mutableSetOf(transaction)
|
||||
|
||||
mutablePreferences.setObjectSet(
|
||||
key = PreferencesKeys.ONRAMP_TRANSACTIONS_STATUSES_KEY,
|
||||
value = updated,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getTransactionById(txId: String): OnrampTransaction? = withContext(dispatchers.io) {
|
||||
val stored = appPreferencesStore.getObjectSetSync<OnrampTransaction>(
|
||||
PreferencesKeys.ONRAMP_TRANSACTIONS_STATUSES_KEY,
|
||||
)
|
||||
|
||||
stored.firstOrNull { it.txId == txId }
|
||||
}
|
||||
|
||||
override fun getTransactions(
|
||||
userWalletId: UserWalletId,
|
||||
toCryptoCurrency: CryptoCurrency.ID,
|
||||
): Flow<List<OnrampTransaction>> = appPreferencesStore
|
||||
.getObjectSet<OnrampTransaction>(PreferencesKeys.ONRAMP_TRANSACTIONS_STATUSES_KEY)
|
||||
.map { transactions ->
|
||||
transactions.filter {
|
||||
it.userWalletId == userWalletId && it.toCurrency.id == toCryptoCurrency
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun removeTransaction(txId: String) {
|
||||
withContext(dispatchers.io) {
|
||||
appPreferencesStore.editData { mutablePreferences ->
|
||||
runCatching {
|
||||
val stored = mutablePreferences.getObjectSet<OnrampTransaction>(
|
||||
PreferencesKeys.ONRAMP_TRANSACTIONS_STATUSES_KEY,
|
||||
)?.toMutableSet()
|
||||
|
||||
stored?.removeIf { it.txId == txId }
|
||||
|
||||
mutablePreferences.setObjectSet(
|
||||
key = PreferencesKeys.ONRAMP_TRANSACTIONS_STATUSES_KEY,
|
||||
value = stored ?: emptySet(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.tangem.data.onramp.converters
|
||||
|
||||
import com.tangem.datasource.api.onramp.models.response.OnrampStatusResponse
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class StatusConverter : Converter<OnrampStatusResponse, OnrampStatus> {
|
||||
override fun convert(value: OnrampStatusResponse): OnrampStatus {
|
||||
return OnrampStatus(
|
||||
txId = value.txId,
|
||||
providerId = value.providerId,
|
||||
payoutAddress = value.payoutAddress,
|
||||
status = OnrampStatus.Status.valueOf(value.status.name),
|
||||
failReason = value.failReason,
|
||||
externalTxId = value.externalTxId,
|
||||
externalTxUrl = value.externalTxUrl,
|
||||
payoutHash = value.payoutHash,
|
||||
createdAt = value.createdAt,
|
||||
fromCurrencyCode = value.fromCurrencyCode,
|
||||
fromAmount = value.fromAmount,
|
||||
toContractAddress = value.toContractAddress,
|
||||
toNetwork = value.toNetwork,
|
||||
toDecimals = value.toDecimals,
|
||||
toAmount = value.toAmount,
|
||||
toActualAmount = value.toActualAmount,
|
||||
paymentMethod = value.paymentMethod,
|
||||
countryCode = value.countryCode,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,13 @@
|
|||
package com.tangem.data.onramp.di
|
||||
|
||||
import com.tangem.data.onramp.DefaultOnrampErrorResolver
|
||||
import com.tangem.data.onramp.DefaultOnrampRepository
|
||||
import com.tangem.data.onramp.DefaultOnrampTransactionRepository
|
||||
import com.tangem.datasource.api.onramp.OnrampApi
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -28,4 +32,22 @@ internal object OnrampDataModule {
|
|||
appPreferencesStore = appPreferencesStore,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampTransactionRepository(
|
||||
appPreferencesStore: AppPreferencesStore,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): OnrampTransactionRepository {
|
||||
return DefaultOnrampTransactionRepository(
|
||||
appPreferencesStore = appPreferencesStore,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampErrorResolver(): OnrampErrorResolver {
|
||||
return DefaultOnrampErrorResolver()
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,8 @@ plugins {
|
|||
|
||||
dependencies {
|
||||
api(projects.domain.onramp.models)
|
||||
api(projects.domain.tokens.models)
|
||||
api(projects.domain.wallets.models)
|
||||
|
||||
api(projects.domain.core)
|
||||
implementation(deps.kotlin.serialization)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ plugins {
|
|||
|
||||
dependencies {
|
||||
implementation(projects.domain.core)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets.models)
|
||||
|
||||
implementation(deps.kotlin.serialization)
|
||||
implementation(deps.jodatime)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.domain.onramp.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class OnrampStatus(
|
||||
val txId: String,
|
||||
val providerId: String,
|
||||
val payoutAddress: String,
|
||||
val status: Status,
|
||||
val failReason: String?,
|
||||
val externalTxId: String,
|
||||
val externalTxUrl: String?,
|
||||
val payoutHash: String?,
|
||||
val createdAt: String,
|
||||
val fromCurrencyCode: String,
|
||||
val fromAmount: String,
|
||||
val toContractAddress: String,
|
||||
val toNetwork: String,
|
||||
val toDecimals: String,
|
||||
val toAmount: String?,
|
||||
val toActualAmount: String?,
|
||||
val paymentMethod: String,
|
||||
val countryCode: String,
|
||||
) {
|
||||
enum class Status {
|
||||
Created,
|
||||
Expired,
|
||||
Paused,
|
||||
WaitingForPayment,
|
||||
PaymentProcessing,
|
||||
Verifying,
|
||||
Failed,
|
||||
Paid,
|
||||
Sending,
|
||||
Finished,
|
||||
}
|
||||
}
|
||||
20
domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/cache/OnrampTransaction.kt
vendored
Normal file
20
domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/cache/OnrampTransaction.kt
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
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
|
||||
|
||||
@Serializable
|
||||
data class OnrampTransaction(
|
||||
val txId: String,
|
||||
val userWalletId: UserWalletId,
|
||||
val fromAmount: SerializedBigDecimal,
|
||||
val fromCurrency: OnrampCurrency,
|
||||
val toAmount: SerializedBigDecimal,
|
||||
val toCurrency: CryptoCurrency,
|
||||
val timestamp: Long,
|
||||
val providerName: String,
|
||||
val providerImageUrl: String,
|
||||
)
|
||||
|
|
@ -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.OnrampStatus
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
class GetOnrampStatusUseCase(
|
||||
private val onrampRepository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(txId: String): Either<OnrampError, OnrampStatus> {
|
||||
return Either.catch {
|
||||
onrampRepository.getStatus(txId)
|
||||
}.mapLeft {
|
||||
errorResolver.resolve(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,17 @@ package com.tangem.domain.onramp.repositories
|
|||
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface OnrampRepository {
|
||||
// api
|
||||
suspend fun getCurrencies(): List<OnrampCurrency>
|
||||
suspend fun getCountries(): List<OnrampCountry>
|
||||
suspend fun getCountryByIp(): OnrampCountry
|
||||
suspend fun getStatus(txId: String): OnrampStatus
|
||||
|
||||
// cache
|
||||
suspend fun saveDefaultCurrency(currency: OnrampCurrency)
|
||||
suspend fun getDefaultCurrencySync(): OnrampCurrency?
|
||||
fun getDefaultCurrency(): Flow<OnrampCurrency?>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.domain.onramp.repositories
|
||||
|
||||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface OnrampTransactionRepository {
|
||||
|
||||
suspend fun storeTransaction(transaction: OnrampTransaction)
|
||||
|
||||
suspend fun getTransactionById(txId: String): OnrampTransaction?
|
||||
|
||||
fun getTransactions(userWalletId: UserWalletId, toCryptoCurrency: CryptoCurrency.ID): Flow<List<OnrampTransaction>>
|
||||
|
||||
suspend fun removeTransaction(txId: String)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue