Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-11 13:14:38 +05:00
parent 466b6e578b
commit df4288e70a
27 changed files with 381 additions and 31 deletions

View file

@ -594,7 +594,7 @@ class DefaultWalletManagersFacade(
}
}
override suspend fun associateAsset(
override suspend fun fulfillRequirements(
userWalletId: UserWalletId,
currency: CryptoCurrency,
signer: TransactionSigner,
@ -613,6 +613,21 @@ class DefaultWalletManagersFacade(
}
}
override suspend fun discardRequirements(userWalletId: UserWalletId, currency: CryptoCurrency): SimpleResult {
return withContext(dispatchers.io) {
val walletManager = getOrCreateWalletManager(userWalletId = userWalletId, network = currency.network)
val currencyType = cryptoCurrencyTypeConverter.convert(currency)
if (walletManager !is AssetRequirementsManager) {
return@withContext SimpleResult.Failure(
BlockchainSdkError.CustomError("WalletManager is not implemented AssetRequirementsManager"),
)
}
walletManager.discardRequirements(currencyType)
}
}
override suspend fun checkUtxoConsolidationAvailability(userWalletId: UserWalletId, network: Network): Boolean {
val blockchain = Blockchain.fromId(network.id.value)
val walletManager = getOrCreateWalletManager(

View file

@ -233,12 +233,14 @@ interface WalletManagersFacade {
*/
suspend fun getAssetRequirements(userWalletId: UserWalletId, currency: CryptoCurrency): AssetRequirementsCondition?
suspend fun associateAsset(
suspend fun fulfillRequirements(
userWalletId: UserWalletId,
currency: CryptoCurrency,
signer: TransactionSigner,
): SimpleResult
suspend fun discardRequirements(userWalletId: UserWalletId, currency: CryptoCurrency): SimpleResult
/**
* Indicates UTXO consolidation availability
*

View file

@ -7,13 +7,20 @@ import com.tangem.blockchain.common.trustlines.AssetRequirementsCondition as Sdk
internal class SdkRequirementsConditionConverter : Converter<SdkRequirementsCondition, AssetRequirementsCondition> {
override fun convert(value: SdkRequirementsCondition): AssetRequirementsCondition {
return when (value) {
SdkRequirementsCondition.PaidTransaction -> AssetRequirementsCondition.PaidTransaction
is SdkRequirementsCondition.PaidTransaction -> AssetRequirementsCondition.PaidTransaction
is SdkRequirementsCondition.PaidTransactionWithFee -> AssetRequirementsCondition.PaidTransactionWithFee(
feeAmount = requireNotNull(value.feeAmount.value),
feeCurrencySymbol = value.feeAmount.currencySymbol,
decimals = value.feeAmount.decimals,
)
is SdkRequirementsCondition.IncompleteTransaction -> TODO()
is SdkRequirementsCondition.IncompleteTransaction -> AssetRequirementsCondition.IncompleteTransaction(
amount = requireNotNull(value.amount.value),
currencySymbol = value.amount.currencySymbol,
currencyDecimals = value.amount.decimals,
feeAmount = requireNotNull(value.feeAmount.value),
feeCurrencySymbol = value.feeAmount.currencySymbol,
feeCurrencyDecimals = value.feeAmount.decimals,
)
}
}
}

View file

@ -0,0 +1,16 @@
package com.tangem.domain.tokens.model.warnings
import com.tangem.domain.tokens.model.CryptoCurrency
import java.math.BigDecimal
sealed class KaspaWarnings : CryptoCurrencyWarning() {
abstract val currency: CryptoCurrency
data class IncompleteTransaction(
override val currency: CryptoCurrency,
val amount: BigDecimal,
val currencySymbol: String,
val currencyDecimals: Int,
) : KaspaWarnings()
}

View file

@ -1,5 +1,6 @@
package com.tangem.domain.tokens
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
@ -22,7 +23,8 @@ class GetCurrencyCheckUseCase(
recipientAddress: String? = null,
): CryptoCurrencyCheck {
return withContext(dispatchers.io) {
val network = currencyStatus.currency.network
val currency = currencyStatus.currency
val network = currency.network
val dustValue = currencyChecksRepository.getDustValue(userWalletId, network)
val reserveAmount = currencyChecksRepository.getReserveAmount(userWalletId, network)
val minimumSendAmount = currencyChecksRepository.getMinimumSendAmount(userWalletId, network)
@ -39,10 +41,11 @@ class GetCurrencyCheckUseCase(
recipientAddress,
)
} ?: false
val utxoAmountLimit = if (amount != null && fee != null) {
val utxoAmountLimit = if (currency is CryptoCurrency.Coin && amount != null && fee != null) {
currencyChecksRepository.checkUtxoAmountLimit(
userWalletId = userWalletId,
network = network,
currency = currencyStatus.currency,
amount = amount,
fee = fee,
)

View file

@ -6,6 +6,7 @@ import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.model.*
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.domain.tokens.model.warnings.HederaWarnings
import com.tangem.domain.tokens.model.warnings.KaspaWarnings
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
import com.tangem.domain.tokens.repository.*
import com.tangem.domain.transaction.models.AssetRequirementsCondition
@ -20,7 +21,7 @@ import com.tangem.utils.isNullOrZero
import kotlinx.coroutines.flow.*
import java.math.BigDecimal
@Suppress("LongParameterList")
@Suppress("LongParameterList", "LargeClass")
class GetCurrencyWarningsUseCase(
private val walletManagersFacade: WalletManagersFacade,
private val currenciesRepository: CurrenciesRepository,
@ -79,7 +80,17 @@ class GetCurrencyWarningsUseCase(
getAssetRequirementsWarning(userWalletId = userWalletId, currency = currency),
getMigrationFromMaticToPolWarning(currency),
)
}.flowOn(dispatchers.io)
}
.onEmpty {
setOfNotNull(
getNetworkUnavailableWarning(currencyStatus),
getNetworkNoAccountWarning(currencyStatus),
getBeaconChainShutdownWarning(currency.network.id),
getAssetRequirementsWarning(userWalletId = userWalletId, currency = currency),
getMigrationFromMaticToPolWarning(currency),
)
}
.flowOn(dispatchers.io)
}
private suspend fun getSwapPromoNotificationWarning(
@ -298,12 +309,22 @@ class GetCurrencyWarningsUseCase(
): CryptoCurrencyWarning? {
return when (val requirements = walletManagersFacade.getAssetRequirements(userWalletId, currency)) {
is AssetRequirementsCondition.PaidTransaction -> HederaWarnings.AssociateWarning(currency = currency)
is AssetRequirementsCondition.PaidTransactionWithFee -> HederaWarnings.AssociateWarningWithFee(
currency = currency,
fee = requirements.feeAmount,
feeCurrencySymbol = requirements.feeCurrencySymbol,
feeCurrencyDecimals = requirements.decimals,
)
is AssetRequirementsCondition.PaidTransactionWithFee -> {
HederaWarnings.AssociateWarningWithFee(
currency = currency,
fee = requirements.feeAmount,
feeCurrencySymbol = requirements.feeCurrencySymbol,
feeCurrencyDecimals = requirements.decimals,
)
}
is AssetRequirementsCondition.IncompleteTransaction ->
KaspaWarnings.IncompleteTransaction(
currency = currency,
amount = requirements.amount,
currencySymbol = requirements.currencySymbol,
currencyDecimals = requirements.currencyDecimals,
)
null -> null
}
}

View file

@ -1,5 +1,6 @@
package com.tangem.domain.tokens.repository
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.CurrencyAmount
import com.tangem.domain.tokens.model.Network
@ -38,6 +39,7 @@ interface CurrencyChecksRepository {
suspend fun checkUtxoAmountLimit(
userWalletId: UserWalletId,
network: Network,
currency: CryptoCurrency,
amount: BigDecimal,
fee: BigDecimal,
): UtxoAmountLimit?

View file

@ -17,4 +17,16 @@ sealed class AssetRequirementsCondition {
val feeCurrencySymbol: String,
val decimals: Int,
) : AssetRequirementsCondition()
/**
* The exact value of the fee for this type of condition is stored in `feeAmount`.
*/
data class IncompleteTransaction(
val amount: BigDecimal,
val currencySymbol: String,
val currencyDecimals: Int,
val feeAmount: BigDecimal,
val feeCurrencySymbol: String,
val feeCurrencyDecimals: Int,
) : AssetRequirementsCondition()
}

View file

@ -0,0 +1,5 @@
package com.tangem.domain.transaction.error
sealed class IncompleteTransactionError {
data class DataError(val message: String?) : IncompleteTransactionError()
}

View file

@ -39,7 +39,7 @@ class AssociateAssetUseCase(
catch(
block = {
when (val result = walletManagersFacade.associateAsset(userWalletId, currency, signer)) {
when (val result = walletManagersFacade.fulfillRequirements(userWalletId, currency, signer)) {
is SimpleResult.Failure -> raise(AssociateAssetError.DataError(result.error.customMessage))
SimpleResult.Success -> Unit
}

View file

@ -0,0 +1,34 @@
package com.tangem.domain.transaction.usecase
import arrow.core.Either
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.transaction.error.IncompleteTransactionError
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWalletId
class DismissIncompleteTransactionUseCase(
private val walletManagersFacade: WalletManagersFacade,
) {
suspend operator fun invoke(
userWalletId: UserWalletId,
currency: CryptoCurrency,
): Either<IncompleteTransactionError, Unit> {
return either {
catch(
block = {
when (val result = walletManagersFacade.discardRequirements(userWalletId, currency)) {
is SimpleResult.Failure -> raise(
IncompleteTransactionError.DataError(result.error.customMessage),
)
SimpleResult.Success -> Unit
}
},
catch = { error -> IncompleteTransactionError.DataError(error.message) },
)
}
}
}

View file

@ -0,0 +1,38 @@
package com.tangem.domain.transaction.usecase
import arrow.core.Either
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.transaction.error.IncompleteTransactionError
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWalletId
class RetryIncompleteTransactionUseCase(
private val cardSdkConfigRepository: CardSdkConfigRepository,
private val walletManagersFacade: WalletManagersFacade,
) {
suspend operator fun invoke(
userWalletId: UserWalletId,
currency: CryptoCurrency,
): Either<IncompleteTransactionError, Unit> {
return either {
val signer = cardSdkConfigRepository.getCommonSigner(cardId = null)
catch(
block = {
when (val result = walletManagersFacade.fulfillRequirements(userWalletId, currency, signer)) {
is SimpleResult.Failure -> raise(
IncompleteTransactionError.DataError(result.error.customMessage),
)
SimpleResult.Success -> Unit
}
},
catch = { error -> IncompleteTransactionError.DataError(error.message) },
)
}
}
}