diff --git a/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt
index 73c0236567..507a284a76 100644
--- a/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt
+++ b/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt
@@ -58,6 +58,28 @@ internal object TransactionDomainModule {
)
}
+ @Provides
+ @Singleton
+ fun provideRetryTransactionUseCase(
+ cardSdkConfigRepository: CardSdkConfigRepository,
+ walletManagersFacade: WalletManagersFacade,
+ ): RetryIncompleteTransactionUseCase {
+ return RetryIncompleteTransactionUseCase(
+ cardSdkConfigRepository = cardSdkConfigRepository,
+ walletManagersFacade = walletManagersFacade,
+ )
+ }
+
+ @Provides
+ @Singleton
+ fun provideDismissIncompleteTransactionUseCase(
+ walletManagersFacade: WalletManagersFacade,
+ ): DismissIncompleteTransactionUseCase {
+ return DismissIncompleteTransactionUseCase(
+ walletManagersFacade = walletManagersFacade,
+ )
+ }
+
@Provides
@Singleton
fun provideCreateTransactionUseCase(transactionRepository: TransactionRepository): CreateTransactionUseCase {
diff --git a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt
index 9841d58e02..e14d6a9c13 100644
--- a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt
+++ b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt
@@ -185,7 +185,7 @@ object NotificationsFactory {
if (dustValue == null) return
val isExceedsLimit = checkDustLimits(
feeAmount = feeValue,
- receivedAmount = sendingAmount,
+ sendingAmount = sendingAmount,
dustValue = dustValue,
cryptoCurrencyStatus = cryptoCurrencyStatus,
feeCurrencyStatus = feeCurrencyStatus,
@@ -352,7 +352,7 @@ object NotificationsFactory {
private fun checkDustLimits(
feeAmount: BigDecimal,
- receivedAmount: BigDecimal,
+ sendingAmount: BigDecimal,
dustValue: BigDecimal,
cryptoCurrencyStatus: CryptoCurrencyStatus,
feeCurrencyStatus: CryptoCurrencyStatus?,
@@ -360,7 +360,7 @@ object NotificationsFactory {
val change = when (cryptoCurrencyStatus.currency) {
is CryptoCurrency.Coin -> {
val balance = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO
- balance - (feeAmount + receivedAmount)
+ balance - (feeAmount + sendingAmount)
}
is CryptoCurrency.Token -> {
val balance = feeCurrencyStatus?.value?.amount ?: BigDecimal.ZERO
@@ -369,6 +369,9 @@ object NotificationsFactory {
}
val isChangeLowerThanDust = change < dustValue && change > BigDecimal.ZERO
- return receivedAmount < dustValue || isChangeLowerThanDust
+ return when (cryptoCurrencyStatus.currency) {
+ is CryptoCurrency.Coin -> sendingAmount < dustValue || isChangeLowerThanDust
+ is CryptoCurrency.Token -> isChangeLowerThanDust
+ }
}
}
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt
index cd7b4d5852..c18e2c3e71 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/notifications/Notification.kt
@@ -222,13 +222,23 @@ private fun Buttons(state: NotificationButtonsState?, isEnabled: Boolean = true)
@Composable
private fun SingleSecondaryButton(config: NotificationButtonsState.SecondaryButtonConfig, isEnabled: Boolean = true) {
- SecondaryButton(
- text = config.text.resolveReference(),
- onClick = config.onClick,
- modifier = Modifier.fillMaxWidth(),
- size = TangemButtonSize.WideAction,
- enabled = isEnabled,
- )
+ if (config.iconResId != null) {
+ SecondaryButtonIconEnd(
+ text = config.text.resolveReference(),
+ onClick = config.onClick,
+ modifier = Modifier.fillMaxWidth(),
+ iconResId = config.iconResId,
+ enabled = isEnabled,
+ )
+ } else {
+ SecondaryButton(
+ text = config.text.resolveReference(),
+ onClick = config.onClick,
+ modifier = Modifier.fillMaxWidth(),
+ size = TangemButtonSize.WideAction,
+ enabled = isEnabled,
+ )
+ }
}
@Composable
diff --git a/core/ui/src/main/res/drawable/ic_alert_circle_red_20.xml b/core/ui/src/main/res/drawable/ic_alert_circle_red_20.xml
new file mode 100644
index 0000000000..e7528979e2
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_alert_circle_red_20.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt
index ba48dfac71..e146654abd 100644
--- a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt
+++ b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt
@@ -52,6 +52,7 @@ internal class DefaultCustomTokensRepository(
Blockchain.Unknown,
Blockchain.Binance,
Blockchain.BinanceTestnet,
+ Blockchain.Kaspa,
-> true
Blockchain.Cardano -> blockchain.validateContractAddress(contractAddress)
else -> blockchain.validateAddress(contractAddress)
diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrencyChecksRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrencyChecksRepository.kt
index d8a6b44533..f72dea5b6d 100644
--- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrencyChecksRepository.kt
+++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrencyChecksRepository.kt
@@ -7,6 +7,7 @@ import com.tangem.blockchain.common.ReserveAmountProvider
import com.tangem.blockchain.common.UtxoAmountLimitProvider
import com.tangem.data.tokens.converters.UtxoConverter
import com.tangem.domain.staking.model.stakekit.YieldBalance
+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
@@ -24,6 +25,7 @@ internal class DefaultCurrencyChecksRepository(
private val walletManagersFacade: WalletManagersFacade,
private val coroutineDispatchers: CoroutineDispatcherProvider,
) : CurrencyChecksRepository {
+
override suspend fun getExistentialDeposit(userWalletId: UserWalletId, network: Network): BigDecimal? {
val manager = walletManagersFacade.getOrCreateWalletManager(
userWalletId = userWalletId,
@@ -108,6 +110,7 @@ internal class DefaultCurrencyChecksRepository(
override suspend fun checkUtxoAmountLimit(
userWalletId: UserWalletId,
network: Network,
+ currency: CryptoCurrency,
amount: BigDecimal,
fee: BigDecimal,
): UtxoAmountLimit? {
diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt
index fa05b147e8..440e818d8f 100644
--- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt
+++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt
@@ -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(
diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagersFacade.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagersFacade.kt
index 6031b2300b..7eb56b21c8 100644
--- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagersFacade.kt
+++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagersFacade.kt
@@ -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
*
diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/SdkRequirementsConditionConverter.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/SdkRequirementsConditionConverter.kt
index d7512061fa..92b365f3f3 100644
--- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/SdkRequirementsConditionConverter.kt
+++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/SdkRequirementsConditionConverter.kt
@@ -7,13 +7,20 @@ import com.tangem.blockchain.common.trustlines.AssetRequirementsCondition as Sdk
internal class SdkRequirementsConditionConverter : Converter {
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,
+ )
}
}
}
\ No newline at end of file
diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/KaspaWarnings.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/KaspaWarnings.kt
new file mode 100644
index 0000000000..00fca5d410
--- /dev/null
+++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/KaspaWarnings.kt
@@ -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()
+}
\ No newline at end of file
diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyCheckUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyCheckUseCase.kt
index 91ae684bf8..41d994c8c0 100644
--- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyCheckUseCase.kt
+++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyCheckUseCase.kt
@@ -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,
)
diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt
index 82dbe90b92..6f2c349a7c 100644
--- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt
+++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt
@@ -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
}
}
diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrencyChecksRepository.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrencyChecksRepository.kt
index e03d3ed0a7..3a03ecb7fc 100644
--- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrencyChecksRepository.kt
+++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/repository/CurrencyChecksRepository.kt
@@ -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?
diff --git a/domain/transaction/models/src/main/kotlin/com/tangem/domain/transaction/models/AssetRequirementsCondition.kt b/domain/transaction/models/src/main/kotlin/com/tangem/domain/transaction/models/AssetRequirementsCondition.kt
index 3503f354df..2bb5c1d8fb 100644
--- a/domain/transaction/models/src/main/kotlin/com/tangem/domain/transaction/models/AssetRequirementsCondition.kt
+++ b/domain/transaction/models/src/main/kotlin/com/tangem/domain/transaction/models/AssetRequirementsCondition.kt
@@ -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()
}
\ No newline at end of file
diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/error/IncompleteTransactionError.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/error/IncompleteTransactionError.kt
new file mode 100644
index 0000000000..0c80d368c5
--- /dev/null
+++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/error/IncompleteTransactionError.kt
@@ -0,0 +1,5 @@
+package com.tangem.domain.transaction.error
+
+sealed class IncompleteTransactionError {
+ data class DataError(val message: String?) : IncompleteTransactionError()
+}
\ No newline at end of file
diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/AssociateAssetUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/AssociateAssetUseCase.kt
index 72ad169dba..979c1c911d 100644
--- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/AssociateAssetUseCase.kt
+++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/AssociateAssetUseCase.kt
@@ -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
}
diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/DismissIncompleteTransactionUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/DismissIncompleteTransactionUseCase.kt
new file mode 100644
index 0000000000..1b11ad2cfd
--- /dev/null
+++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/DismissIncompleteTransactionUseCase.kt
@@ -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 {
+ 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) },
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/RetryIncompleteTransactionUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/RetryIncompleteTransactionUseCase.kt
new file mode 100644
index 0000000000..fa8fa53c7e
--- /dev/null
+++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/RetryIncompleteTransactionUseCase.kt
@@ -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 {
+ 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) },
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt
index e46cc3f47c..836894e575 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/analytics/TokenDetailsNotificationsAnalyticsSender.kt
@@ -48,6 +48,7 @@ internal class TokenDetailsNotificationsAnalyticsSender(
is TokenDetailsNotification.RentInfo,
is TokenDetailsNotification.NetworkShutdown,
is TokenDetailsNotification.HederaAssociateWarning,
+ is TokenDetailsNotification.KaspaIncompleteTransactionWarning,
is TokenDetailsNotification.KoinosMana,
is TokenDetailsNotification.MigrationMaticToPol,
-> null
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsDialogConfig.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsDialogConfig.kt
index 47949f59c7..ce5a9f3d49 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsDialogConfig.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsDialogConfig.kt
@@ -96,6 +96,27 @@ internal data class TokenDetailsDialogConfig(
)
}
+ data class RemoveIncompleteTransactionConfirmDialogConfig(
+ val onConfirmClick: () -> Unit,
+ val onCancelClick: () -> Unit,
+ ) : DialogContentConfig() {
+ override val title = null
+
+ override val message: TextReference = TextReference.Res(
+ id = R.string.warning_kaspa_unfinished_token_transaction_discard_message,
+ )
+
+ override val cancelButtonConfig: ButtonConfig = ButtonConfig(
+ text = TextReference.Res(R.string.common_cancel),
+ onClick = onCancelClick,
+ )
+
+ override val confirmButtonConfig: ButtonConfig = ButtonConfig(
+ text = TextReference.Res(R.string.common_yes),
+ onClick = onConfirmClick,
+ )
+ }
+
data class ErrorDialogConfig(
val text: TextReference,
val onConfirmClick: () -> Unit,
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt
index 69b5beb389..86db0a1bf3 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/components/TokenDetailsNotification.kt
@@ -19,12 +19,14 @@ internal sealed class TokenDetailsNotification(val config: NotificationConfig) {
subtitle: TextReference,
iconResId: Int = R.drawable.img_attention_20,
buttonsState: NotificationConfig.ButtonsState? = null,
+ onCloseClick: (() -> Unit)? = null,
) : TokenDetailsNotification(
config = NotificationConfig(
title = title,
subtitle = subtitle,
iconResId = iconResId,
buttonsState = buttonsState,
+ onCloseClick = onCloseClick,
),
)
@@ -191,6 +193,27 @@ internal sealed class TokenDetailsNotification(val config: NotificationConfig) {
),
)
+ data class KaspaIncompleteTransactionWarning(
+ private val currency: CryptoCurrency,
+ private val amount: String,
+ private val currencySymbol: String,
+ private val onRetryIncompleteTransactionClick: () -> Unit,
+ private val onDismissIncompleteTransactionClick: () -> Unit,
+ ) : Warning(
+ title = resourceReference(R.string.warning_kaspa_unfinished_token_transaction_title),
+ subtitle = resourceReference(
+ id = R.string.warning_kaspa_unfinished_token_transaction_message,
+ formatArgs = wrappedList(amount, currencySymbol),
+ ),
+ iconResId = R.drawable.ic_alert_circle_red_20,
+ buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
+ text = resourceReference(R.string.alert_button_try_again),
+ onClick = onRetryIncompleteTransactionClick,
+ iconResId = R.drawable.ic_tangem_24,
+ ),
+ onCloseClick = onDismissIncompleteTransactionClick,
+ )
+
data class KoinosMana(
val manaBalanceAmount: String,
val maxManaBalanceAmount: String,
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt
index 86aae8128f..b1435ae301 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsNotificationConverter.kt
@@ -9,6 +9,7 @@ import com.tangem.core.ui.format.bigdecimal.shorted
import com.tangem.domain.tokens.model.CryptoCurrency
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.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification.*
@@ -41,6 +42,14 @@ internal class TokenDetailsNotificationConverter(
return newNotifications.toImmutableList()
}
+ fun removeKaspaIncompleteTransactionWarning(
+ currentState: TokenDetailsState,
+ ): ImmutableList {
+ val newNotifications = currentState.notifications.toMutableList()
+ newNotifications.removeBy { it is KaspaIncompleteTransactionWarning }
+ return newNotifications.toImmutableList()
+ }
+
@Suppress("LongMethod", "CyclomaticComplexMethod")
private fun mapToNotification(warning: CryptoCurrencyWarning): TokenDetailsNotification {
return when (warning) {
@@ -109,6 +118,13 @@ internal class TokenDetailsNotificationConverter(
feeCurrencySymbol = warning.feeCurrencySymbol,
onAssociateClick = clickIntents::onAssociateClick,
)
+ is KaspaWarnings.IncompleteTransaction -> KaspaIncompleteTransactionWarning(
+ currency = warning.currency,
+ amount = warning.amount.format { crypto(symbol = "", decimals = warning.currencyDecimals) },
+ currencySymbol = warning.currencySymbol,
+ onRetryIncompleteTransactionClick = clickIntents::onRetryIncompleteTransactionClick,
+ onDismissIncompleteTransactionClick = clickIntents::onDismissIncompleteTransactionClick,
+ )
is CryptoCurrencyWarning.FeeResourceInfo -> KoinosMana(
manaBalanceAmount = formatMana(warning.amount),
maxManaBalanceAmount = warning.maxAmount?.let {
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt
index 649869ebc8..5e15fa4efc 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt
@@ -199,6 +199,19 @@ internal class TokenDetailsStateFactory(
)
}
+ fun getStateWithDismissIncompleteTransactionConfirmDialog(): TokenDetailsState {
+ return currentStateProvider().copy(
+ dialogConfig = TokenDetailsDialogConfig(
+ isShow = true,
+ onDismissRequest = clickIntents::onDismissDialog,
+ content = TokenDetailsDialogConfig.DialogContentConfig.RemoveIncompleteTransactionConfirmDialogConfig(
+ onConfirmClick = clickIntents::onConfirmDismissIncompleteTransactionClick,
+ onCancelClick = clickIntents::onDismissDialog,
+ ),
+ ),
+ )
+ }
+
fun getStateWithActionButtonErrorDialog(unavailabilityReason: ScenarioUnavailabilityReason): TokenDetailsState {
return currentStateProvider().copy(
dialogConfig = TokenDetailsDialogConfig(
@@ -300,6 +313,14 @@ internal class TokenDetailsStateFactory(
return state.copy(notifications = notificationConverter.removeHederaAssociateWarning(state))
}
+ fun getStateWithRemovedKaspaIncompleteTransactionNotification(): TokenDetailsState {
+ val state = currentStateProvider()
+ return state.copy(
+ notifications = notificationConverter.removeKaspaIncompleteTransactionWarning(state),
+ dialogConfig = state.dialogConfig?.copy(isShow = false),
+ )
+ }
+
fun getStateAndTriggerEvent(
state: TokenDetailsState,
errorMessage: TextReference,
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsClickIntents.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsClickIntents.kt
index 9f150beb95..e4439079b5 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsClickIntents.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsClickIntents.kt
@@ -59,6 +59,12 @@ interface TokenDetailsClickIntents {
fun onAssociateClick()
+ fun onRetryIncompleteTransactionClick()
+
+ fun onDismissIncompleteTransactionClick()
+
+ fun onConfirmDismissIncompleteTransactionClick()
+
fun onStakeBannerClick()
fun onBalanceSelect(config: TokenBalanceSegmentedButtonConfig)
diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt
index f320c748cb..f41620317c 100644
--- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt
+++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt
@@ -50,7 +50,10 @@ import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent.Companion.toReasonAnalyticsText
import com.tangem.domain.tokens.model.analytics.TokenSwapPromoAnalyticsEvent
import com.tangem.domain.transaction.error.AssociateAssetError
+import com.tangem.domain.transaction.error.IncompleteTransactionError
import com.tangem.domain.transaction.usecase.AssociateAssetUseCase
+import com.tangem.domain.transaction.usecase.DismissIncompleteTransactionUseCase
+import com.tangem.domain.transaction.usecase.RetryIncompleteTransactionUseCase
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
@@ -108,6 +111,8 @@ internal class TokenDetailsViewModel @Inject constructor(
private val networkHasDerivationUseCase: NetworkHasDerivationUseCase,
private val isDemoCardUseCase: IsDemoCardUseCase,
private val associateAssetUseCase: AssociateAssetUseCase,
+ private val retryIncompleteTransactionUseCase: RetryIncompleteTransactionUseCase,
+ private val dismissIncompleteTransactionUseCase: DismissIncompleteTransactionUseCase,
private val reduxStateHolder: ReduxStateHolder,
private val analyticsEventsHandler: AnalyticsEventHandler,
private val vibratorHapticManager: VibratorHapticManager,
@@ -861,6 +866,58 @@ internal class TokenDetailsViewModel @Inject constructor(
return resourceReference(R.string.wallet_notification_address_copied)
}
+ override fun onRetryIncompleteTransactionClick() {
+ viewModelScope.launch {
+ retryIncompleteTransactionUseCase(
+ userWalletId = userWalletId,
+ currency = cryptoCurrency,
+ ).fold(
+ ifLeft = { e ->
+ when (e) {
+ is IncompleteTransactionError.DataError -> {
+ internalUiState.value = stateFactory.getStateWithErrorDialog(
+ stringReference(e.message.orEmpty()),
+ )
+ Timber.e(e.message)
+ }
+ }
+ },
+ ifRight = {
+ internalUiState.value = stateFactory.getStateWithRemovedKaspaIncompleteTransactionNotification()
+ },
+ )
+ }
+ }
+
+ override fun onDismissIncompleteTransactionClick() {
+ viewModelScope.launch {
+ internalUiState.value = stateFactory.getStateWithDismissIncompleteTransactionConfirmDialog()
+ }
+ }
+
+ override fun onConfirmDismissIncompleteTransactionClick() {
+ viewModelScope.launch {
+ dismissIncompleteTransactionUseCase(
+ userWalletId = userWalletId,
+ currency = cryptoCurrency,
+ ).fold(
+ ifLeft = { e ->
+ when (e) {
+ is IncompleteTransactionError.DataError -> {
+ internalUiState.value = stateFactory.getStateWithErrorDialog(
+ stringReference(e.message.orEmpty()),
+ )
+ Timber.e(e.message)
+ }
+ }
+ },
+ ifRight = {
+ internalUiState.value = stateFactory.getStateWithRemovedKaspaIncompleteTransactionNotification()
+ },
+ )
+ }
+ }
+
override fun onAssociateClick() {
analyticsEventsHandler.send(
TokenScreenAnalyticsEvent.Associate(
diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml
index b05595b8f7..4fb9818eec 100644
--- a/gradle/dependencies.toml
+++ b/gradle/dependencies.toml
@@ -88,7 +88,7 @@ markdownComposeView = "0.5.4"
# endregion Other libraries
# region Tangem
-tangemBlockchainSdk = "release-app_5.19-881"
+tangemBlockchainSdk = "release-app_5.19-882"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "release-app_5.19-414"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
diff --git a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/datastorage/DefaultBlockchainDataStorage.kt b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/datastorage/DefaultBlockchainDataStorage.kt
index 9122a68be2..6681161851 100644
--- a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/datastorage/DefaultBlockchainDataStorage.kt
+++ b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/datastorage/DefaultBlockchainDataStorage.kt
@@ -21,13 +21,15 @@ internal class DefaultBlockchainDataStorage(
return appPreferencesStore.getSyncOrNull(key = stringPreferencesKey(name = key))
}
- override suspend fun remove(key: String) {
- TODO("Not yet implemented")
- }
-
override suspend fun store(key: String, value: String) {
appPreferencesStore.edit {
it[stringPreferencesKey(key)] = value
}
}
+
+ override suspend fun remove(key: String) {
+ appPreferencesStore.edit {
+ it.remove(stringPreferencesKey(key))
+ }
+ }
}
\ No newline at end of file