Updated on 2026-08-14
This commit is contained in:
parent
1cdece6ae7
commit
d7a120fc86
24 changed files with 486 additions and 160 deletions
|
|
@ -2,6 +2,9 @@ package com.tangem.tap.data
|
|||
|
||||
import android.content.Context
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.data.pay.entity.WithdrawStoreData
|
||||
import com.tangem.data.pay.util.WithdrawStateConverter
|
||||
import com.tangem.data.pay.util.WithdrawStoreDataConverter
|
||||
import com.tangem.datasource.di.NetworkMoshi
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
|
|
@ -11,6 +14,7 @@ import com.tangem.datasource.local.preferences.utils.getSyncOrNull
|
|||
import com.tangem.datasource.local.preferences.utils.store
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayWithdrawState
|
||||
import com.tangem.domain.visa.model.TangemPayAuthTokens
|
||||
import com.tangem.sdk.storage.AndroidSecureStorageV2
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -41,6 +45,8 @@ internal class DefaultTangemPayStorage @Inject constructor(
|
|||
}
|
||||
|
||||
private val tokensAdapter by lazy { moshi.adapter(TangemPayAuthTokens::class.java) }
|
||||
private val withdrawStoreDataConverter by lazy { WithdrawStoreDataConverter() }
|
||||
private val withdrawStateConverter by lazy { WithdrawStateConverter() }
|
||||
|
||||
override suspend fun storeCustomerWalletAddress(userWalletId: UserWalletId, customerWalletAddress: String) {
|
||||
withContext(dispatcherProvider.io) {
|
||||
|
|
@ -131,10 +137,12 @@ internal class DefaultTangemPayStorage @Inject constructor(
|
|||
return appPreferencesStore.getSyncOrNull(PreferencesKeys.getTangemPayCheckCustomerByWalletId(userWalletId))
|
||||
}
|
||||
|
||||
override suspend fun storeWithdrawOrder(userWalletId: UserWalletId, orderId: String) {
|
||||
override suspend fun storeWithdrawOrder(userWalletId: UserWalletId, data: TangemPayWithdrawState) {
|
||||
appPreferencesStore.editData { mutablePreferences ->
|
||||
val orders = mutablePreferences.getObjectMap<String>(PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY)
|
||||
.plus(createWithdrawOrderIdKey(userWalletId) to orderId)
|
||||
val orders = mutablePreferences.getObjectMap<TangemPayWithdrawState>(
|
||||
PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY,
|
||||
)
|
||||
.plus(createWithdrawOrderIdKey(userWalletId) to withdrawStoreDataConverter.convert(data))
|
||||
mutablePreferences.setObjectMap(
|
||||
key = PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY,
|
||||
value = orders,
|
||||
|
|
@ -142,14 +150,19 @@ internal class DefaultTangemPayStorage @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getWithdrawOrderId(userWalletId: UserWalletId): String? {
|
||||
val orders = appPreferencesStore.getObjectMapSync<String>(PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY)
|
||||
return orders[createWithdrawOrderIdKey(userWalletId)]
|
||||
override suspend fun getWithdrawOrder(userWalletId: UserWalletId): TangemPayWithdrawState? {
|
||||
val orders = appPreferencesStore.getObjectMapSync<WithdrawStoreData>(
|
||||
PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY,
|
||||
)
|
||||
val data = orders[createWithdrawOrderIdKey(userWalletId)] ?: return null
|
||||
return withdrawStateConverter.convert(data)
|
||||
}
|
||||
|
||||
override suspend fun deleteWithdrawOrder(userWalletId: UserWalletId) {
|
||||
appPreferencesStore.editData { mutablePreferences ->
|
||||
val orders = mutablePreferences.getObjectMap<String>(PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY)
|
||||
val orders = mutablePreferences.getObjectMap<WithdrawStoreData>(
|
||||
PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY,
|
||||
)
|
||||
.minus(createWithdrawOrderIdKey(userWalletId))
|
||||
mutablePreferences.setObjectMap(
|
||||
key = PreferencesKeys.TANGEM_PAY_WITHDRAW_ORDERS_KEY,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ data class OrderResponse(
|
|||
@Json(name = "emboss_name") val embossName: String?,
|
||||
@Json(name = "product_instance_id") val productInstanceId: String?,
|
||||
@Json(name = "payment_account_id") val paymentAccountId: String?,
|
||||
@Json(name = "transaction_hash") val transactionHash: String?,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.datasource.local.visa
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayWithdrawState
|
||||
import com.tangem.domain.visa.model.TangemPayAuthTokens
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
|
|
@ -28,9 +29,9 @@ interface TangemPayStorage {
|
|||
suspend fun storeCheckCustomerWalletResult(userWalletId: UserWalletId, isPaeraCustomer: Boolean)
|
||||
suspend fun checkCustomerWalletResult(userWalletId: UserWalletId): Boolean?
|
||||
|
||||
suspend fun storeWithdrawOrder(userWalletId: UserWalletId, orderId: String)
|
||||
suspend fun storeWithdrawOrder(userWalletId: UserWalletId, data: TangemPayWithdrawState)
|
||||
|
||||
suspend fun getWithdrawOrderId(userWalletId: UserWalletId): String?
|
||||
suspend fun getWithdrawOrder(userWalletId: UserWalletId): TangemPayWithdrawState?
|
||||
|
||||
suspend fun deleteWithdrawOrder(userWalletId: UserWalletId)
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ dependencies {
|
|||
implementation(projects.domain.walletManager)
|
||||
implementation(projects.domain.quotes)
|
||||
implementation(projects.domain.common)
|
||||
implementation(projects.features.swap.domain)
|
||||
|
||||
/** Feature API - remove after removing [HotWalletFeatureToggles] */
|
||||
implementation(projects.features.hotWallet.api)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ internal interface TangemPayDataModule {
|
|||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindTangemPaySwapRepository(repository: DefaultTangemPaySwapRepository): TangemPaySwapRepository
|
||||
fun bindTangemPaySwapRepository(repository: DefaultTangemPayWithdrawRepository): TangemPayWithdrawRepository
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.data.pay.entity
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = false)
|
||||
data class WithdrawStoreData(
|
||||
@Json(name = "orderId") val orderId: String,
|
||||
@Json(name = "exchangeData") val exchangeData: ExchangeStoreData?,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = false)
|
||||
data class ExchangeStoreData(
|
||||
@Json(name = "txId") val txId: String,
|
||||
@Json(name = "fromNetwork") val fromNetwork: String,
|
||||
@Json(name = "fromAddress") val fromAddress: String,
|
||||
@Json(name = "payInAddress") val payInAddress: String,
|
||||
@Json(name = "payInExtraId") val payInExtraId: String?,
|
||||
)
|
||||
|
|
@ -2,8 +2,8 @@ package com.tangem.data.pay.repository
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.datasource.api.pay.TangemPayApi
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.OrderData
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.pay.repository.CustomerOrderRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
|
|
@ -12,35 +12,23 @@ import javax.inject.Inject
|
|||
internal class DefaultCustomerOrderRepository @Inject constructor(
|
||||
private val tangemPayApi: TangemPayApi,
|
||||
private val requestHelper: TangemPayRequestPerformer,
|
||||
private val tangemPayStorage: TangemPayStorage,
|
||||
) : CustomerOrderRepository {
|
||||
|
||||
override suspend fun getOrderStatus(
|
||||
userWalletId: UserWalletId,
|
||||
orderId: String,
|
||||
): Either<VisaApiError, OrderStatus> {
|
||||
override suspend fun getOrderData(userWalletId: UserWalletId, orderId: String): Either<VisaApiError, OrderData> {
|
||||
return requestHelper.performRequest(userWalletId) { authHeader ->
|
||||
tangemPayApi.getOrder(authHeader = authHeader, orderId = orderId)
|
||||
}.map { response ->
|
||||
when (response.result?.status) {
|
||||
val status = when (response.result?.status) {
|
||||
null -> OrderStatus.UNKNOWN
|
||||
OrderStatus.NEW.apiName -> OrderStatus.NEW
|
||||
OrderStatus.PROCESSING.apiName -> OrderStatus.PROCESSING
|
||||
OrderStatus.COMPLETED.apiName -> OrderStatus.COMPLETED
|
||||
else -> OrderStatus.CANCELED
|
||||
}
|
||||
OrderData(
|
||||
status = status,
|
||||
withdrawTxHash = response.result?.data?.transactionHash?.ifEmpty { null },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun hasWithdrawOrder(userWalletId: UserWalletId): Boolean {
|
||||
val orderId = tangemPayStorage.getWithdrawOrderId(userWalletId)
|
||||
if (orderId == null) return false
|
||||
|
||||
val status = getOrderStatus(userWalletId, orderId).getOrNull()
|
||||
|
||||
val hasActiveOrder = status == OrderStatus.NEW || status == OrderStatus.PROCESSING
|
||||
if (!hasActiveOrder) tangemPayStorage.deleteWithdrawOrder(userWalletId)
|
||||
|
||||
return hasActiveOrder
|
||||
}
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
package com.tangem.data.pay.repository
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.data.common.quote.QuotesFetcher
|
||||
import com.tangem.datasource.api.pay.TangemPayApi
|
||||
import com.tangem.datasource.api.pay.models.request.WithdrawDataRequest
|
||||
import com.tangem.datasource.api.pay.models.request.WithdrawRequest
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.pay.WithdrawalResult
|
||||
import com.tangem.domain.pay.WithdrawalSignatureResult
|
||||
import com.tangem.domain.pay.datasource.TangemPayAuthDataSource
|
||||
import com.tangem.domain.pay.repository.TangemPaySwapRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.utils.extensions.addHexPrefix
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import java.util.Currency
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultTangemPaySwapRepository @Inject constructor(
|
||||
private val tangemPayApi: TangemPayApi,
|
||||
private val requestHelper: TangemPayRequestPerformer,
|
||||
private val authDataSource: TangemPayAuthDataSource,
|
||||
private val quotesFetcher: QuotesFetcher,
|
||||
private val tangemPayStorage: TangemPayStorage,
|
||||
) : TangemPaySwapRepository {
|
||||
|
||||
override suspend fun withdraw(
|
||||
userWallet: UserWallet,
|
||||
receiverAddress: String,
|
||||
cryptoAmount: BigDecimal,
|
||||
cryptoCurrencyId: CryptoCurrency.RawID,
|
||||
): Either<UniversalError, WithdrawalResult> {
|
||||
val amountInCents = getAmountInCents(cryptoAmount, cryptoCurrencyId)
|
||||
if (amountInCents.isNullOrEmpty()) return Either.Left(VisaApiError.WithdrawalDataError)
|
||||
return requestHelper.performRequest(userWallet.walletId) { authHeader ->
|
||||
val request = WithdrawDataRequest(amountInCents = amountInCents, recipientAddress = receiverAddress)
|
||||
tangemPayApi.getWithdrawData(authHeader = authHeader, body = request)
|
||||
}.map { data ->
|
||||
val result = data.result ?: return VisaApiError.WithdrawalDataError.left()
|
||||
val signatureResult = authDataSource.getWithdrawalSignature(
|
||||
userWallet = userWallet,
|
||||
hash = result.hash,
|
||||
).getOrNull()
|
||||
|
||||
return when (signatureResult) {
|
||||
is WithdrawalSignatureResult.Cancelled -> {
|
||||
Either.Right(WithdrawalResult.Cancelled)
|
||||
}
|
||||
is WithdrawalSignatureResult.Success -> {
|
||||
requestHelper.performRequest(userWallet.walletId) { authHeader ->
|
||||
val request = WithdrawRequest(
|
||||
amountInCents = amountInCents,
|
||||
recipientAddress = receiverAddress,
|
||||
adminSalt = result.salt,
|
||||
senderAddress = result.senderAddress,
|
||||
adminSignature = signatureResult.signature.addHexPrefix(),
|
||||
)
|
||||
tangemPayApi.withdraw(authHeader = authHeader, body = request)
|
||||
}
|
||||
.mapLeft { return Either.Left(VisaApiError.WithdrawError) }
|
||||
.map { response ->
|
||||
val orderId = response.result?.orderId
|
||||
if (orderId != null) tangemPayStorage.storeWithdrawOrder(userWallet.walletId, orderId)
|
||||
WithdrawalResult.Success
|
||||
}
|
||||
}
|
||||
null -> return Either.Left(VisaApiError.SignWithdrawError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getAmountInCents(cryptoAmount: BigDecimal, cryptoCurrencyId: CryptoCurrency.RawID): String? {
|
||||
val fiatRate = getFiatRate(cryptoCurrencyId) ?: return null
|
||||
val amountInDollars = cryptoAmount.multiply(fiatRate)
|
||||
val defaultFractionDigits = Currency.getInstance(Locale.US).defaultFractionDigits
|
||||
return amountInDollars
|
||||
.setScale(defaultFractionDigits, RoundingMode.HALF_UP)
|
||||
.movePointRight(defaultFractionDigits)
|
||||
.longValueExact()
|
||||
.toString()
|
||||
}
|
||||
|
||||
private suspend fun getFiatRate(cryptoCurrencyId: CryptoCurrency.RawID): BigDecimal? {
|
||||
val quotes = quotesFetcher.fetch(
|
||||
fiatCurrencyId = Currency.getInstance(Locale.US).currencyCode,
|
||||
currencyId = cryptoCurrencyId.value,
|
||||
field = QuotesFetcher.Field.PRICE,
|
||||
).getOrNull()
|
||||
|
||||
return quotes?.quotes[cryptoCurrencyId.value]?.price
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,301 @@
|
|||
package com.tangem.data.pay.repository
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.data.common.quote.QuotesFetcher
|
||||
import com.tangem.datasource.api.pay.TangemPayApi
|
||||
import com.tangem.datasource.api.pay.models.request.WithdrawDataRequest
|
||||
import com.tangem.datasource.api.pay.models.request.WithdrawRequest
|
||||
import com.tangem.datasource.api.pay.models.response.WithdrawResponse
|
||||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.pay.TangemPayWithdrawExchangeState
|
||||
import com.tangem.domain.pay.TangemPayWithdrawState
|
||||
import com.tangem.domain.pay.WithdrawalResult
|
||||
import com.tangem.domain.pay.WithdrawalSignatureResult
|
||||
import com.tangem.domain.pay.datasource.TangemPayAuthDataSource
|
||||
import com.tangem.domain.pay.model.OrderData
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.pay.repository.CustomerOrderRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayWithdrawRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.feature.swap.domain.api.SwapRepository
|
||||
import com.tangem.feature.swap.domain.models.ExpressDataError
|
||||
import com.tangem.utils.extensions.addHexPrefix
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import java.util.Currency
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.set
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
private const val TAG = "TangemPaySwapRepository"
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultTangemPayWithdrawRepository @Inject constructor(
|
||||
private val tangemPayApi: TangemPayApi,
|
||||
private val requestHelper: TangemPayRequestPerformer,
|
||||
private val authDataSource: TangemPayAuthDataSource,
|
||||
private val quotesFetcher: QuotesFetcher,
|
||||
private val tangemPayStorage: TangemPayStorage,
|
||||
private val swapRepository: SwapRepository,
|
||||
private val orderRepository: CustomerOrderRepository,
|
||||
) : TangemPayWithdrawRepository {
|
||||
|
||||
private val withdrawPollingScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
private val withdrawPollingJobs = mutableMapOf<String, Job>()
|
||||
private val withdrawPollingMutex = Mutex()
|
||||
|
||||
override suspend fun withdraw(
|
||||
userWallet: UserWallet,
|
||||
receiverAddress: String,
|
||||
cryptoAmount: BigDecimal,
|
||||
cryptoCurrencyId: CryptoCurrency.RawID,
|
||||
exchangeData: TangemPayWithdrawExchangeState,
|
||||
): Either<UniversalError, WithdrawalResult> {
|
||||
val amountInCents = getAmountInCents(cryptoAmount, cryptoCurrencyId)
|
||||
if (amountInCents.isNullOrEmpty()) return Either.Left(VisaApiError.WithdrawalDataError)
|
||||
return requestHelper.performRequest(userWallet.walletId) { authHeader ->
|
||||
val request = WithdrawDataRequest(amountInCents = amountInCents, recipientAddress = receiverAddress)
|
||||
tangemPayApi.getWithdrawData(authHeader = authHeader, body = request)
|
||||
}.map { data ->
|
||||
val result = data.result ?: return VisaApiError.WithdrawalDataError.left()
|
||||
val signatureResult = authDataSource.getWithdrawalSignature(
|
||||
userWallet = userWallet,
|
||||
hash = result.hash,
|
||||
).getOrNull()
|
||||
|
||||
return when (signatureResult) {
|
||||
is WithdrawalSignatureResult.Cancelled -> {
|
||||
Either.Right(WithdrawalResult.Cancelled)
|
||||
}
|
||||
is WithdrawalSignatureResult.Success -> {
|
||||
requestHelper.performRequest(userWallet.walletId) { authHeader ->
|
||||
val request = WithdrawRequest(
|
||||
amountInCents = amountInCents,
|
||||
recipientAddress = receiverAddress,
|
||||
adminSalt = result.salt,
|
||||
senderAddress = result.senderAddress,
|
||||
adminSignature = signatureResult.signature.addHexPrefix(),
|
||||
)
|
||||
tangemPayApi.withdraw(authHeader = authHeader, body = request)
|
||||
}
|
||||
.mapLeft { return Either.Left(VisaApiError.WithdrawError) }
|
||||
.map { response ->
|
||||
processWithdrawResult(response, userWallet, exchangeData)
|
||||
WithdrawalResult.Success
|
||||
}
|
||||
}
|
||||
null -> return Either.Left(VisaApiError.SignWithdrawError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun processWithdrawResult(
|
||||
response: WithdrawResponse,
|
||||
userWallet: UserWallet,
|
||||
exchangeData: TangemPayWithdrawExchangeState,
|
||||
) {
|
||||
val orderId = response.result?.orderId
|
||||
if (orderId != null) {
|
||||
val orderData = orderRepository
|
||||
.getOrderData(userWalletId = userWallet.walletId, orderId = orderId).getOrNull()
|
||||
val withdrawTxHash = orderData?.withdrawTxHash
|
||||
val storeData = TangemPayWithdrawState(
|
||||
orderId = orderId,
|
||||
exchangeData = exchangeData,
|
||||
)
|
||||
if (orderData != null && !withdrawTxHash.isNullOrEmpty()) {
|
||||
finalizeWithdraw(
|
||||
userWallet = userWallet,
|
||||
withdrawTxHash = withdrawTxHash,
|
||||
orderId = orderId,
|
||||
exchangeData = exchangeData,
|
||||
order = orderData,
|
||||
).onLeft {
|
||||
tangemPayStorage.storeWithdrawOrder(userWalletId = userWallet.walletId, data = storeData)
|
||||
}
|
||||
} else {
|
||||
tangemPayStorage.storeWithdrawOrder(userWalletId = userWallet.walletId, data = storeData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun finalizeWithdraw(
|
||||
userWallet: UserWallet,
|
||||
withdrawTxHash: String,
|
||||
orderId: String,
|
||||
exchangeData: TangemPayWithdrawExchangeState,
|
||||
order: OrderData,
|
||||
): Either<ExpressDataError, Unit> {
|
||||
return swapRepository.exchangeSent(
|
||||
userWallet = userWallet,
|
||||
txId = exchangeData.txId,
|
||||
fromNetwork = exchangeData.fromNetwork,
|
||||
fromAddress = exchangeData.fromAddress,
|
||||
payInAddress = exchangeData.payInAddress,
|
||||
txHash = withdrawTxHash,
|
||||
payInExtraId = exchangeData.payInExtraId,
|
||||
)
|
||||
.onRight {
|
||||
val isActive = order.status == OrderStatus.NEW || order.status == OrderStatus.PROCESSING
|
||||
if (!isActive) {
|
||||
tangemPayStorage.deleteWithdrawOrder(userWalletId = userWallet.walletId)
|
||||
} else {
|
||||
tangemPayStorage.storeWithdrawOrder(
|
||||
userWalletId = userWallet.walletId,
|
||||
data = TangemPayWithdrawState(orderId = orderId, exchangeData = null),
|
||||
)
|
||||
}
|
||||
}
|
||||
.onLeft { error ->
|
||||
Timber.tag(TAG).e(error.toString())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun hasWithdrawOrder(userWallet: UserWallet): Boolean {
|
||||
val orderExchangeData = tangemPayStorage.getWithdrawOrder(userWallet.walletId)
|
||||
if (orderExchangeData == null) return false
|
||||
|
||||
val exchangeData = orderExchangeData.exchangeData
|
||||
val orderData = orderRepository
|
||||
.getOrderData(userWallet.walletId, orderId = orderExchangeData.orderId).getOrNull()
|
||||
val withdrawTxHash = orderData?.withdrawTxHash
|
||||
|
||||
if (exchangeData != null && orderData != null && withdrawTxHash != null) {
|
||||
finalizeWithdraw(
|
||||
userWallet = userWallet,
|
||||
withdrawTxHash = withdrawTxHash,
|
||||
orderId = orderExchangeData.orderId,
|
||||
exchangeData = exchangeData,
|
||||
order = orderData,
|
||||
)
|
||||
}
|
||||
|
||||
return orderData?.status == OrderStatus.NEW || orderData?.status == OrderStatus.PROCESSING
|
||||
}
|
||||
|
||||
override suspend fun pollWithdrawOrderIfNeeds(userWallet: UserWallet): Either<VisaApiError, Unit> {
|
||||
val storeData = tangemPayStorage.getWithdrawOrder(userWallet.walletId) ?: return Unit.right()
|
||||
val exchangeData = storeData.exchangeData ?: return Unit.right()
|
||||
|
||||
val orderId = storeData.orderId
|
||||
val order = orderRepository
|
||||
.getOrderData(userWalletId = userWallet.walletId, orderId = orderId).getOrNull()
|
||||
?: return Unit.right()
|
||||
|
||||
val txHash = order.withdrawTxHash
|
||||
|
||||
if (!txHash.isNullOrEmpty()) {
|
||||
finalizeWithdraw(
|
||||
userWallet = userWallet,
|
||||
withdrawTxHash = txHash,
|
||||
orderId = storeData.orderId,
|
||||
exchangeData = exchangeData,
|
||||
order = order,
|
||||
).onLeft {
|
||||
startWithdrawOrderPolling(
|
||||
userWallet = userWallet,
|
||||
orderId = orderId,
|
||||
storeData = storeData,
|
||||
exchangeData = exchangeData,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
startWithdrawOrderPolling(
|
||||
userWallet = userWallet,
|
||||
orderId = orderId,
|
||||
storeData = storeData,
|
||||
exchangeData = exchangeData,
|
||||
)
|
||||
}
|
||||
|
||||
return Unit.right()
|
||||
}
|
||||
|
||||
private suspend fun startWithdrawOrderPolling(
|
||||
userWallet: UserWallet,
|
||||
orderId: String,
|
||||
storeData: TangemPayWithdrawState,
|
||||
exchangeData: TangemPayWithdrawExchangeState,
|
||||
) {
|
||||
withdrawPollingMutex.withLock {
|
||||
if (withdrawPollingJobs.containsKey(orderId)) return
|
||||
|
||||
val pollingJob = withdrawPollingScope.launch {
|
||||
try {
|
||||
while (isActive && withdrawPollingJobs.containsKey(orderId)) {
|
||||
delay(duration = 5.seconds)
|
||||
|
||||
val orderData = orderRepository
|
||||
.getOrderData(userWalletId = userWallet.walletId, orderId = orderId)
|
||||
orderData.onRight { order ->
|
||||
if (order.status != OrderStatus.NEW && order.status != OrderStatus.PROCESSING) {
|
||||
tangemPayStorage.deleteWithdrawOrder(userWallet.walletId)
|
||||
withdrawPollingJobs.remove(key = orderId)
|
||||
return@launch
|
||||
}
|
||||
val txHash = order.withdrawTxHash
|
||||
if (!txHash.isNullOrEmpty()) {
|
||||
finalizeWithdraw(
|
||||
userWallet = userWallet,
|
||||
withdrawTxHash = txHash,
|
||||
orderId = storeData.orderId,
|
||||
exchangeData = exchangeData,
|
||||
order = order,
|
||||
).onRight {
|
||||
withdrawPollingJobs.remove(key = orderId)
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
}.onLeft { error ->
|
||||
Timber.tag(TAG).e("error ${error.errorCode}")
|
||||
}
|
||||
}
|
||||
} catch (exception: CancellationException) {
|
||||
throw exception
|
||||
} catch (exception: Exception) {
|
||||
Timber.tag(TAG).e(exception)
|
||||
withdrawPollingMutex.withLock { withdrawPollingJobs.remove(orderId) }
|
||||
}
|
||||
}
|
||||
withdrawPollingJobs[orderId] = pollingJob
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getAmountInCents(cryptoAmount: BigDecimal, cryptoCurrencyId: CryptoCurrency.RawID): String? {
|
||||
val fiatRate = getFiatRate(cryptoCurrencyId) ?: return null
|
||||
val amountInDollars = cryptoAmount.multiply(fiatRate)
|
||||
val defaultFractionDigits = Currency.getInstance(Locale.US).defaultFractionDigits
|
||||
return amountInDollars
|
||||
.setScale(defaultFractionDigits, RoundingMode.HALF_UP)
|
||||
.movePointRight(defaultFractionDigits)
|
||||
.longValueExact()
|
||||
.toString()
|
||||
}
|
||||
|
||||
private suspend fun getFiatRate(cryptoCurrencyId: CryptoCurrency.RawID): BigDecimal? {
|
||||
val quotes = quotesFetcher.fetch(
|
||||
fiatCurrencyId = Currency.getInstance(Locale.US).currencyCode,
|
||||
currencyId = cryptoCurrencyId.value,
|
||||
field = QuotesFetcher.Field.PRICE,
|
||||
).getOrNull()
|
||||
|
||||
return quotes?.quotes[cryptoCurrencyId.value]?.price
|
||||
}
|
||||
}
|
||||
|
|
@ -4,14 +4,15 @@ import arrow.core.Either
|
|||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.pay.TangemPayWithdrawExchangeState
|
||||
import com.tangem.domain.pay.WithdrawalResult
|
||||
import com.tangem.domain.pay.repository.TangemPaySwapRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayWithdrawRepository
|
||||
import com.tangem.domain.tangempay.TangemPayWithdrawUseCase
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultTangemPayWithdrawUseCase @Inject constructor(
|
||||
private val repository: TangemPaySwapRepository,
|
||||
private val repository: TangemPayWithdrawRepository,
|
||||
) : TangemPayWithdrawUseCase {
|
||||
|
||||
override suspend fun invoke(
|
||||
|
|
@ -19,12 +20,14 @@ internal class DefaultTangemPayWithdrawUseCase @Inject constructor(
|
|||
cryptoAmount: BigDecimal,
|
||||
cryptoCurrencyId: CryptoCurrency.RawID,
|
||||
receiverCexAddress: String,
|
||||
exchangeData: TangemPayWithdrawExchangeState,
|
||||
): Either<UniversalError, WithdrawalResult> {
|
||||
return repository.withdraw(
|
||||
userWallet = userWallet,
|
||||
cryptoAmount = cryptoAmount,
|
||||
receiverAddress = receiverCexAddress,
|
||||
cryptoCurrencyId = cryptoCurrencyId,
|
||||
exchangeData = exchangeData,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.data.pay.util
|
||||
|
||||
import com.tangem.data.pay.entity.WithdrawStoreData
|
||||
import com.tangem.domain.pay.TangemPayWithdrawExchangeState
|
||||
import com.tangem.domain.pay.TangemPayWithdrawState
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
class WithdrawStateConverter : Converter<WithdrawStoreData, TangemPayWithdrawState> {
|
||||
|
||||
override fun convert(value: WithdrawStoreData): TangemPayWithdrawState = TangemPayWithdrawState(
|
||||
orderId = value.orderId,
|
||||
exchangeData = value.exchangeData?.let { exchangeData ->
|
||||
TangemPayWithdrawExchangeState(
|
||||
txId = exchangeData.txId,
|
||||
fromNetwork = exchangeData.fromNetwork,
|
||||
fromAddress = exchangeData.fromAddress,
|
||||
payInAddress = exchangeData.payInAddress,
|
||||
payInExtraId = exchangeData.payInExtraId,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.data.pay.util
|
||||
|
||||
import com.tangem.data.pay.entity.ExchangeStoreData
|
||||
import com.tangem.data.pay.entity.WithdrawStoreData
|
||||
import com.tangem.domain.pay.TangemPayWithdrawState
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
class WithdrawStoreDataConverter : Converter<TangemPayWithdrawState, WithdrawStoreData> {
|
||||
|
||||
override fun convert(value: TangemPayWithdrawState): WithdrawStoreData = WithdrawStoreData(
|
||||
orderId = value.orderId,
|
||||
exchangeData = value.exchangeData?.let { exchangeData ->
|
||||
ExchangeStoreData(
|
||||
txId = exchangeData.txId,
|
||||
fromNetwork = exchangeData.fromNetwork,
|
||||
fromAddress = exchangeData.fromAddress,
|
||||
payInAddress = exchangeData.payInAddress,
|
||||
payInExtraId = exchangeData.payInExtraId,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ dependencies {
|
|||
implementation(projects.domain.core)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets.models)
|
||||
implementation(projects.features.swap.domain)
|
||||
|
||||
/** Feature API - remove after removing [TangemPayFeatureToggles] */
|
||||
implementation(projects.features.tangempay.details.api)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.domain.pay
|
||||
|
||||
data class TangemPayWithdrawState(
|
||||
val orderId: String,
|
||||
val exchangeData: TangemPayWithdrawExchangeState?,
|
||||
)
|
||||
|
||||
data class TangemPayWithdrawExchangeState(
|
||||
val txId: String,
|
||||
val fromNetwork: String,
|
||||
val fromAddress: String,
|
||||
val payInAddress: String,
|
||||
val payInExtraId: String?,
|
||||
)
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.tangem.domain.pay.model
|
||||
|
||||
data class OrderData(
|
||||
val status: OrderStatus,
|
||||
val withdrawTxHash: String?,
|
||||
)
|
||||
|
|
@ -2,12 +2,10 @@ package com.tangem.domain.pay.repository
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.pay.model.OrderData
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
|
||||
interface CustomerOrderRepository {
|
||||
|
||||
suspend fun getOrderStatus(userWalletId: UserWalletId, orderId: String): Either<VisaApiError, OrderStatus>
|
||||
|
||||
suspend fun hasWithdrawOrder(userWalletId: UserWalletId): Boolean
|
||||
suspend fun getOrderData(userWalletId: UserWalletId, orderId: String): Either<VisaApiError, OrderData>
|
||||
}
|
||||
|
|
@ -4,15 +4,22 @@ import arrow.core.Either
|
|||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.pay.TangemPayWithdrawExchangeState
|
||||
import com.tangem.domain.pay.WithdrawalResult
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import java.math.BigDecimal
|
||||
|
||||
interface TangemPaySwapRepository {
|
||||
interface TangemPayWithdrawRepository {
|
||||
|
||||
suspend fun withdraw(
|
||||
userWallet: UserWallet,
|
||||
receiverAddress: String,
|
||||
cryptoAmount: BigDecimal,
|
||||
cryptoCurrencyId: CryptoCurrency.RawID,
|
||||
exchangeData: TangemPayWithdrawExchangeState,
|
||||
): Either<UniversalError, WithdrawalResult>
|
||||
|
||||
suspend fun hasWithdrawOrder(userWallet: UserWallet): Boolean
|
||||
|
||||
suspend fun pollWithdrawOrderIfNeeds(userWallet: UserWallet): Either<VisaApiError, Unit>
|
||||
}
|
||||
|
|
@ -137,13 +137,13 @@ class TangemPayMainScreenCustomerInfoUseCase(
|
|||
userWalletId: UserWalletId,
|
||||
orderId: String,
|
||||
): Either<TangemPayCustomerInfoError, MainScreenCustomerInfo> {
|
||||
return customerOrderRepository.getOrderStatus(userWalletId, orderId = orderId)
|
||||
return customerOrderRepository.getOrderData(userWalletId, orderId = orderId)
|
||||
.fold(
|
||||
ifLeft = { error ->
|
||||
error.mapErrorForCustomer().left()
|
||||
},
|
||||
ifRight = { orderStatus ->
|
||||
when (orderStatus) {
|
||||
ifRight = { orderData ->
|
||||
when (orderData.status) {
|
||||
// Kyc is passed and user waits for order creation -> no need to get customer info
|
||||
OrderStatus.NEW,
|
||||
OrderStatus.PROCESSING,
|
||||
|
|
@ -154,7 +154,7 @@ class TangemPayMainScreenCustomerInfoUseCase(
|
|||
kycStatus = CustomerInfo.KycStatus.APPROVED,
|
||||
cardInfo = null,
|
||||
),
|
||||
orderStatus = orderStatus,
|
||||
orderStatus = orderData.status,
|
||||
).right()
|
||||
|
||||
// Order was created/cancelled -> clear order id and get customer info
|
||||
|
|
@ -164,11 +164,11 @@ class TangemPayMainScreenCustomerInfoUseCase(
|
|||
-> {
|
||||
onboardingRepository.clearOrderId(userWalletId)
|
||||
// If order was cancelled -> start order creation
|
||||
if (orderStatus == OrderStatus.CANCELED) onboardingRepository.createOrder(userWalletId)
|
||||
if (orderData.status == OrderStatus.CANCELED) onboardingRepository.createOrder(userWalletId)
|
||||
onboardingRepository.getCustomerInfo(userWalletId = userWalletId)
|
||||
.mapLeft { it.mapErrorForCustomer() }
|
||||
.map { customerInfo ->
|
||||
MainScreenCustomerInfo(info = customerInfo, orderStatus = orderStatus)
|
||||
MainScreenCustomerInfo(info = customerInfo, orderStatus = orderData.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import arrow.core.Either
|
|||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.pay.TangemPayWithdrawExchangeState
|
||||
import com.tangem.domain.pay.WithdrawalResult
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -14,5 +15,6 @@ interface TangemPayWithdrawUseCase {
|
|||
cryptoAmount: BigDecimal,
|
||||
cryptoCurrencyId: CryptoCurrency.RawID,
|
||||
receiverCexAddress: String,
|
||||
exchangeData: TangemPayWithdrawExchangeState,
|
||||
): Either<UniversalError, WithdrawalResult>
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ dependencies {
|
|||
implementation(projects.domain.express.models)
|
||||
implementation(projects.domain.account)
|
||||
implementation(projects.domain.account.status)
|
||||
implementation(projects.domain.visa.models)
|
||||
|
||||
implementation(projects.features.swap.domain.api)
|
||||
implementation(projects.features.swap.domain.models)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import com.tangem.domain.models.network.Network
|
|||
import com.tangem.domain.models.quote.QuoteStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayWithdrawExchangeState
|
||||
import com.tangem.domain.quotes.QuotesRepository
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.tokens.*
|
||||
|
|
@ -1030,6 +1031,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
|
|||
exchangeData.transaction as? ExpressTransactionModel.CEX ?: return SwapTransactionState.Error.UnknownError
|
||||
|
||||
if (isTangemPayWithdrawal) {
|
||||
val networkAddress = currencyToSend.value.networkAddress
|
||||
return SwapTransactionState.TangemPayWithdrawalData(
|
||||
cryptoAmount = amount.value,
|
||||
cryptoCurrencyId = requireNotNull(currencyToSend.currency.id.rawCurrencyId),
|
||||
|
|
@ -1056,6 +1058,13 @@ internal class SwapInteractorImpl @AssistedInject constructor(
|
|||
txExternalId = exchangeDataCex.externalTxId,
|
||||
averageDuration = null,
|
||||
),
|
||||
exchangeData = TangemPayWithdrawExchangeState(
|
||||
txId = exchangeDataCex.txId,
|
||||
fromNetwork = currencyToSend.currency.network.backendId,
|
||||
fromAddress = networkAddress?.defaultAddress?.value.orEmpty(),
|
||||
payInAddress = exchangeData.transaction.txTo,
|
||||
payInExtraId = exchangeDataCex.txExtraId,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.feature.swap.domain.models.ui
|
|||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.pay.TangemPayWithdrawExchangeState
|
||||
import com.tangem.domain.transaction.error.SendTransactionError
|
||||
import com.tangem.feature.swap.domain.models.ExpressDataError
|
||||
import com.tangem.feature.swap.domain.models.SwapAmount
|
||||
|
|
@ -31,6 +32,7 @@ sealed class SwapTransactionState {
|
|||
val toAmount: String?,
|
||||
val toAmountValue: BigDecimal?,
|
||||
val storeData: StoreTransactionData,
|
||||
val exchangeData: TangemPayWithdrawExchangeState,
|
||||
) : SwapTransactionState() {
|
||||
|
||||
data class StoreTransactionData(
|
||||
|
|
|
|||
|
|
@ -1136,6 +1136,7 @@ internal class SwapModel @Inject constructor(
|
|||
cryptoAmount = swapTransactionState.cryptoAmount,
|
||||
cryptoCurrencyId = swapTransactionState.cryptoCurrencyId,
|
||||
receiverCexAddress = swapTransactionState.cexAddress,
|
||||
exchangeData = swapTransactionState.exchangeData,
|
||||
)
|
||||
.onLeft {
|
||||
startLoadingQuotesFromLastState()
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ import com.tangem.domain.models.wallet.UserWallet
|
|||
import com.tangem.domain.pay.TangemPayCryptoCurrencyFactory
|
||||
import com.tangem.domain.pay.model.TangemPayCardBalance
|
||||
import com.tangem.domain.pay.model.TangemPayTopUpData
|
||||
import com.tangem.domain.pay.repository.CustomerOrderRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayWithdrawRepository
|
||||
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import com.tangem.domain.visa.model.TangemPayTxHistoryItem
|
||||
|
|
@ -79,7 +79,7 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
private val cardDetailsEventListener: CardDetailsEventListener,
|
||||
private val txHistoryUpdateListener: TangemPayTxHistoryUpdateListener,
|
||||
private val tangemPayCryptoCurrencyFactory: TangemPayCryptoCurrencyFactory,
|
||||
private val orderRepository: CustomerOrderRepository,
|
||||
private val tangemPayWithdrawRepository: TangemPayWithdrawRepository,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val expressTransactionsEventListener: ExpressTransactionsEventListener,
|
||||
|
|
@ -124,6 +124,7 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
modelScope.launch {
|
||||
expressTransactionsEventListener.send(ExpressTransactionsEvent.Update)
|
||||
}
|
||||
subscribeToWithdrawOrder()
|
||||
}
|
||||
|
||||
fun onPause() {
|
||||
|
|
@ -148,6 +149,14 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun subscribeToWithdrawOrder() {
|
||||
modelScope.launch {
|
||||
val userWallet = userWallet ?: getUserWalletUseCase(params.userWalletId).getOrNull()
|
||||
?: return@launch
|
||||
tangemPayWithdrawRepository.pollWithdrawOrderIfNeeds(userWallet)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClickPinCode() {
|
||||
analytics.send(TangemPayAnalyticsEvents.PinCodeClicked())
|
||||
if (!params.config.isPinSet) {
|
||||
|
|
@ -278,24 +287,28 @@ internal class TangemPayDetailsModel @Inject constructor(
|
|||
if (currentBalance == null || depositAddress == null) {
|
||||
showBottomSheetError(TangemPayDetailsErrorType.Withdraw)
|
||||
} else {
|
||||
modelScope.launch {
|
||||
val hasActiveWithdrawal = orderRepository.hasWithdrawOrder(userWalletId = params.userWalletId)
|
||||
if (hasActiveWithdrawal) {
|
||||
showBottomSheetError(TangemPayDetailsErrorType.WithdrawInProgress)
|
||||
} else {
|
||||
val userWallet = userWallet ?: getUserWalletUseCase(params.userWalletId).getOrNull()
|
||||
val currency = cryptoCurrency ?: userWallet?.let {
|
||||
tangemPayCryptoCurrencyFactory.create(userWallet = userWallet, chainId = params.config.chainId)
|
||||
.getOrNull()
|
||||
}
|
||||
if (currency != null) {
|
||||
uiMessageSender.send(
|
||||
message = TangemPayMessagesFactory.createWithdrawWarning(
|
||||
onGotItClick = { onConfirmWithdrawal(currency, currentBalance, depositAddress) },
|
||||
),
|
||||
)
|
||||
val userWallet = userWallet ?: getUserWalletUseCase(params.userWalletId).getOrNull()
|
||||
if (userWallet == null) {
|
||||
showBottomSheetError(TangemPayDetailsErrorType.Withdraw)
|
||||
} else {
|
||||
modelScope.launch {
|
||||
val hasActiveWithdrawal = tangemPayWithdrawRepository.hasWithdrawOrder(userWallet = userWallet)
|
||||
if (hasActiveWithdrawal) {
|
||||
showBottomSheetError(TangemPayDetailsErrorType.WithdrawInProgress)
|
||||
} else {
|
||||
showBottomSheetError(TangemPayDetailsErrorType.Withdraw)
|
||||
val currency = cryptoCurrency ?: tangemPayCryptoCurrencyFactory.create(
|
||||
userWallet = userWallet,
|
||||
chainId = params.config.chainId,
|
||||
).getOrNull()
|
||||
if (currency != null) {
|
||||
uiMessageSender.send(
|
||||
message = TangemPayMessagesFactory.createWithdrawWarning(
|
||||
onGotItClick = { onConfirmWithdrawal(currency, currentBalance, depositAddress) },
|
||||
),
|
||||
)
|
||||
} else {
|
||||
showBottomSheetError(TangemPayDetailsErrorType.Withdraw)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue