Updated on 2026-08-14

This commit is contained in:
Tangem 2024-01-19 15:59:14 +03:00
parent 5d69093f1d
commit 7ef0543a78
9 changed files with 91 additions and 32 deletions

View file

@ -479,8 +479,10 @@
<string name="send_notification_exceed_balance_title">Недостаточно средств</string>
<string name="send_notification_exceed_fee_text">Размер комиссии превышает баланс сети. Для продолжения необходимо пополнить баланс сети.</string>
<string name="send_notification_exceed_fee_title">Комиссия превышает баланс</string>
<string name="send_notification_high_fee_text">Комиссия при переводе всего баланса выше. Для того, чтобы снизить комиссию Вы можете оставить 0.01.</string>
<string name="send_notification_high_fee_title">Увеличение комиссии</string>
<string name="send_notification_high_fee_text">Комиссия при переводе всего баланса выше. Для того, чтобы снизить комиссию Вы можете оставить 0.01.</string>
<string name="send_notification_fee_too_high_accept">Оставить %s XTZ</string>
<string name="send_notification_fee_too_high_ignore">Отправить все</string>
<string name="send_notification_fee_too_high_title">Установлена высокая комиссия</string>
<string name="send_notification_fee_too_high_text">Сумма комиссии в %s раз превышает рекомендованную. Убедитесь, что указанная комиссия верна.</string>
<string name="send_notification_invalid_amount_text">Включенная комиссия превышает сумму перевода, что приводит к отрицательному значению</string>

View file

@ -484,8 +484,10 @@
<string name="send_notification_exceed_balance_title">Total exceeds balance</string>
<string name="send_notification_exceed_fee_text">The commission fee exceeds the network balance. To continue, it is necessary to replenish the network balance.</string>
<string name="send_notification_exceed_fee_title">Fee exceeds balance</string>
<string name="send_notification_high_fee_text">The fee for transferring the entire balance is higher. To reduce the commission, you can leave 0.01.</string>
<string name="send_notification_high_fee_title">Fee is increased</string>
<string name="send_notification_high_fee_text">The fee for transferring the entire balance is higher. To reduce the commission, you can leave 0.01.</string>
<string name="send_notification_fee_too_high_accept">Reduce by %s XTZ</string>
<string name="send_notification_fee_too_high_ignore">No, send all</string>
<string name="send_notification_fee_too_high_title">Custom fee is high</string>
<string name="send_notification_fee_too_high_text">The commission amount is %s times the recommended amount. Make sure that the custom settings are correct.</string>
<string name="send_notification_invalid_amount_text">The included commission exceeds the transfer amount, leading to a negative value</string>

View file

@ -2,17 +2,13 @@ package com.tangem.domain.transaction.usecase
import arrow.core.Either
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.transaction.TransactionRepository
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.withContext
class CreateTransactionUseCase(
private val transactionRepository: TransactionRepository,
private val dispatchers: CoroutineDispatcherProvider,
) {
/**
@ -26,18 +22,16 @@ class CreateTransactionUseCase(
destination: String,
userWalletId: UserWalletId,
network: Network,
): Either<Throwable, TransactionData> = withContext(dispatchers.io) {
Either.catch {
requireNotNull(
transactionRepository.createTransaction(
amount = amount,
fee = fee,
memo = memo,
destination = destination,
userWalletId = userWalletId,
network = network,
),
) { "Failed to create transaction" }
}
) = Either.catch {
requireNotNull(
transactionRepository.createTransaction(
amount = amount,
fee = fee,
memo = memo,
destination = destination,
userWalletId = userWalletId,
network = network,
),
) { "Failed to create transaction" }
}
}

View file

@ -57,16 +57,28 @@ internal sealed class SendNotification(val config: NotificationConfig) {
sealed class Warning(
title: TextReference,
subtitle: TextReference,
buttonsState: NotificationConfig.ButtonsState? = null,
) : SendNotification(
config = NotificationConfig(
title = title,
subtitle = subtitle,
iconResId = R.drawable.img_attention_20,
buttonsState = buttonsState,
),
) {
data class HighFeeError(val amount: String) : Warning(
data class HighFeeError(
val amount: String,
val onConfirmClick: () -> Unit,
val onDismissClick: () -> Unit,
) : Warning(
title = resourceReference(R.string.send_notification_high_fee_title),
subtitle = resourceReference(R.string.send_notification_high_fee_text, wrappedList(amount)),
buttonsState = NotificationConfig.ButtonsState.PairButtonsConfig(
primaryText = resourceReference(R.string.send_notification_fee_too_high_accept, wrappedList(amount)),
onPrimaryClick = onConfirmClick,
secondaryText = resourceReference(R.string.send_notification_fee_too_high_ignore),
onSecondaryClick = onDismissClick,
),
)
data class ExistentialDeposit(val deposit: String) : Warning(

View file

@ -6,6 +6,7 @@ import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@ -21,6 +22,7 @@ internal class SendNotificationFactory(
private val currentStateProvider: Provider<SendUiState>,
private val userWalletProvider: Provider<UserWallet>,
private val walletManagersFacade: WalletManagersFacade,
private val clickIntents: SendClickIntents,
) {
fun create(): Flow<ImmutableList<SendNotification>> = currentStateProvider().currentState
@ -30,19 +32,33 @@ internal class SendNotificationFactory(
val feeState = state.feeState ?: return@map persistentListOf()
val recipientState = state.recipientState ?: return@map persistentListOf()
val feeAmount = feeState.fee?.amount?.value ?: BigDecimal.ZERO
val amountValue = state.amountState?.amountTextField?.value?.toBigDecimalOrNull() ?: BigDecimal.ZERO
val sendAmount = if (feeState.isSubtract) feeState.receivedAmountValue else amountValue
buildList {
// errors
addExceedBalanceNotification(feeAmount, feeState.receivedAmountValue)
addInvalidAmountNotification(feeState.isSubtract, feeState.receivedAmountValue)
addMinimumAmountErrorNotification(feeAmount, feeState.receivedAmountValue)
addExceedBalanceNotification(feeAmount, sendAmount)
addInvalidAmountNotification(feeState.isSubtract, sendAmount)
addMinimumAmountErrorNotification(feeAmount, sendAmount)
addReserveAmountErrorNotification(recipientState.addressTextField.value)
addTransactionLimitErrorNotification(feeAmount, feeState.receivedAmountValue)
addTransactionLimitErrorNotification(feeAmount, sendAmount)
// warnings
addExistentialWarningNotification(feeAmount, feeState.receivedAmountValue)
addHighFeeWarningNotification()
addExistentialWarningNotification(feeAmount, sendAmount)
addHighFeeWarningNotification(amountValue, state.sendState.ignoreAmountReduce)
}.toImmutableList()
}
fun dismissHighFeeWarningState(): SendUiState {
val state = currentStateProvider()
val sendState = state.sendState
val updatedNotifications = sendState.notifications.filterNot { it is SendNotification.Warning.HighFeeError }
return state.copy(
sendState = sendState.copy(
ignoreAmountReduce = true,
notifications = updatedNotifications.toImmutableList(),
),
)
}
private fun MutableList<SendNotification>.addExceedBalanceNotification(
feeAmount: BigDecimal,
receivedAmount: BigDecimal,
@ -173,16 +189,30 @@ internal class SendNotificationFactory(
}
}
private fun MutableList<SendNotification>.addHighFeeWarningNotification() {
// TODO Move Blockchain check elsewhere
if (cryptoCurrencyStatusProvider().currency.network.id.value == Blockchain.Tezos.id) {
add(SendNotification.Warning.HighFeeError(TEZOS_FEE_THRESHOLD))
private fun MutableList<SendNotification>.addHighFeeWarningNotification(
sendAmount: BigDecimal,
ignoreAmountReduce: Boolean,
) {
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
val balance = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO
val isTezos = cryptoCurrencyStatus.currency.network.id.value == Blockchain.Tezos.id
if (!ignoreAmountReduce && sendAmount == balance && isTezos) {
add(
SendNotification.Warning.HighFeeError(
amount = TEZOS_FEE_THRESHOLD.toPlainString(),
onConfirmClick = {
val reduceTo = sendAmount.minus(TEZOS_FEE_THRESHOLD).toPlainString()
clickIntents.onAmountReduceClick(reduceTo)
},
onDismissClick = clickIntents::onAmountReduceIgnoreClick,
),
)
}
}
companion object {
private const val CARDANO_MINIMUM = "1"
private const val DOGECOIN_MINIMUM = "0.01"
private const val TEZOS_FEE_THRESHOLD = "0.01"
private val TEZOS_FEE_THRESHOLD = BigDecimal("0.01")
}
}

View file

@ -88,6 +88,7 @@ internal sealed class SendStates {
val isSuccess: Boolean = false,
val transactionDate: Long = 0L,
val txUrl: String = "",
val ignoreAmountReduce: Boolean = false,
val notifications: ImmutableList<SendNotification> = persistentListOf(),
) : SendStates()
}

View file

@ -197,7 +197,10 @@ internal fun LazyListScope.notifications(configs: ImmutableList<SendNotification
Notification(
config = it.config,
modifier = modifier.animateItemPlacement(),
containerColor = TangemTheme.colors.button.disabled,
containerColor = when (it) {
is SendNotification.Warning.HighFeeError -> TangemTheme.colors.background.action
else -> TangemTheme.colors.button.disabled
},
iconTint = when (it) {
is SendNotification.Error -> TangemTheme.colors.icon.warning
is SendNotification.Warning -> null

View file

@ -53,5 +53,9 @@ interface SendClickIntents {
fun showFee()
fun onExploreClick(txUrl: String)
fun onAmountReduceClick(reducedAmount: String)
fun onAmountReduceIgnoreClick()
// endregion
}

View file

@ -109,6 +109,7 @@ internal class SendViewModel @Inject constructor(
currentStateProvider = Provider { uiState },
userWalletProvider = Provider { userWallet },
walletManagersFacade = walletManagersFacade,
clickIntents = this,
)
// todo convert to StateFlow
@ -457,6 +458,16 @@ internal class SendViewModel @Inject constructor(
override fun onExploreClick(txUrl: String) = innerRouter.openUrl(txUrl)
override fun onAmountReduceClick(reducedAmount: String) {
uiState = stateFactory.getOnAmountValueChange(reducedAmount)
uiState = sendNotificationFactory.dismissHighFeeWarningState()
getFee()
}
override fun onAmountReduceIgnoreClick() {
uiState = sendNotificationFactory.dismissHighFeeWarningState()
}
private fun verifyAndSendTransaction() {
val recipient = uiState.recipientState?.addressTextField?.value ?: return
val feeState = uiState.feeState ?: return