Updated on 2026-08-14

This commit is contained in:
Tangem 2024-02-02 14:23:45 +03:00
commit 2fd16863a7
10 changed files with 291 additions and 109 deletions

View file

@ -7,7 +7,6 @@ import com.tangem.domain.transaction.error.SendTransactionError
import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState
import com.tangem.features.send.impl.presentation.state.fee.FeeStateFactory
import com.tangem.features.send.impl.presentation.state.fee.FeeType
import com.tangem.features.send.impl.presentation.state.fee.getFee
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
import java.math.BigDecimal
@ -58,7 +57,7 @@ internal class SendEventStateFactory(
}
val newFeeValue = newFee.amount.value ?: BigDecimal.ZERO
val oldFeeValue = feeSelector.getFee().amount.value ?: BigDecimal.ZERO
val oldFeeValue = feeStateFactory.feeConverter.convert(feeSelector).amount.value ?: BigDecimal.ZERO
val updateFeeState = feeStateFactory.onFeeOnLoadedState(fee)
return if (newFeeValue > oldFeeValue) {
updateFeeState.copy(

View file

@ -43,6 +43,7 @@ internal sealed class SendStates {
abstract val isPrimaryButtonEnabled: Boolean
/** Amount state */
@Stable
data class AmountState(
override val type: SendUiStateType = SendUiStateType.Amount,
override val isPrimaryButtonEnabled: Boolean,
@ -54,6 +55,7 @@ internal sealed class SendStates {
) : SendStates()
/** Recipient state */
@Stable
data class RecipientState(
override val type: SendUiStateType = SendUiStateType.Recipient,
override val isPrimaryButtonEnabled: Boolean,
@ -65,6 +67,7 @@ internal sealed class SendStates {
) : SendStates()
/** Fee and speed state */
@Stable
data class FeeState(
override val type: SendUiStateType = SendUiStateType.Fee,
override val isPrimaryButtonEnabled: Boolean = false,
@ -82,6 +85,7 @@ internal sealed class SendStates {
) : SendStates()
/** Send state */
@Stable
data class SendState(
override val type: SendUiStateType = SendUiStateType.Send,
override val isPrimaryButtonEnabled: Boolean = true,

View file

@ -1,8 +1,6 @@
package com.tangem.features.send.impl.presentation.state.fee
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.blockchain.extensions.toBigDecimalOrDefault
import com.tangem.features.send.impl.presentation.state.SendUiState
import java.math.BigDecimal
@ -13,28 +11,4 @@ internal fun calculateReceiveAmount(state: SendUiState, feeAmount: Fee): BigDeci
val amountValue = state.amountState?.amountTextField?.cryptoAmount?.value ?: BigDecimal.ZERO
val fee = feeAmount.amount.value ?: return BigDecimal.ZERO
return amountValue.minus(fee)
}
/**
* Returns fee amount depending on current state
*/
internal fun FeeSelectorState.Content.getFee(): Fee {
return when (fees) {
is TransactionFee.Choosable -> {
when (selectedFee) {
FeeType.SLOW -> fees.minimum
FeeType.MARKET -> fees.normal
FeeType.FAST -> fees.priority
FeeType.CUSTOM -> {
val feeAmount = customValues.firstOrNull()?.value.toBigDecimalOrDefault()
Fee.Common(
fees.normal.amount.copy(
value = feeAmount,
),
)
}
}
}
is TransactionFee.Single -> fees.normal
}
}

View file

@ -0,0 +1,60 @@
package com.tangem.features.send.impl.presentation.state.fee
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
internal class FeeConverter(
private val clickIntents: SendClickIntents,
private val appCurrencyProvider: Provider<AppCurrency>,
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
) : Converter<FeeSelectorState.Content, Fee> {
private val ethereumCustomFeeConverter by lazy {
EthereumCustomFeeConverter(
clickIntents = clickIntents,
appCurrencyProvider = appCurrencyProvider,
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
)
}
override fun convert(value: FeeSelectorState.Content): Fee {
return when (val fees = value.fees) {
is TransactionFee.Choosable -> {
when (value.selectedFee) {
FeeType.SLOW -> fees.minimum
FeeType.MARKET -> fees.normal
FeeType.FAST -> fees.priority
FeeType.CUSTOM -> convertCustom(value, fees)
}
}
is TransactionFee.Single -> fees.normal
}
}
private fun convertCustom(feeSelectorState: FeeSelectorState.Content, fees: TransactionFee): Fee {
val customValues = feeSelectorState.customValues
val normalFee = fees.normal
return if (customValues.isEmpty()) {
normalFee
} else {
when (normalFee) {
is Fee.Ethereum -> ethereumCustomFeeConverter.convertBack(normalFee = normalFee, value = customValues)
else -> {
val customFee = customValues.firstOrNull()
Fee.Common(
normalFee.amount.copy(
value = customFee?.value?.parseToBigDecimal(customFee.decimals),
),
)
}
}
}
}
}

View file

@ -3,6 +3,7 @@ package com.tangem.features.send.impl.presentation.state.fee
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.core.ui.extensions.networkIconResId
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.tokens.GetBalanceNotEnoughForFeeWarningUseCase
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
@ -14,6 +15,7 @@ import com.tangem.features.send.impl.presentation.state.SendUiStateType
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.toFormattedString
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.filter
@ -65,7 +67,8 @@ internal class FeeNotificationFactory(
) {
val multipleFees = transactionFee as? TransactionFee.Choosable ?: return
val minimumValue = multipleFees.minimum.amount.value ?: return
val customValue = customFee.firstOrNull()?.value?.toBigDecimalOrNull() ?: return
val customAmount = customFee.firstOrNull() ?: return
val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals)
if (selectedFee == FeeType.CUSTOM && minimumValue > customValue) {
add(SendFeeNotification.Informational.TooLow)
}
@ -78,10 +81,11 @@ internal class FeeNotificationFactory(
) {
val multipleFees = transactionFee as? TransactionFee.Choosable ?: return
val highValue = multipleFees.priority.amount.value ?: return
val customValue = customFee.firstOrNull()?.value?.toBigDecimalOrNull() ?: return
val customAmount = customFee.firstOrNull() ?: return
val customValue = customAmount.value.parseToBigDecimal(customAmount.decimals)
val diff = customValue / highValue
if (selectedFee == FeeType.CUSTOM && diff > FEE_MAX_DIFF) {
add(SendFeeNotification.Warning.TooHigh(diff.toInt().toString()))
add(SendFeeNotification.Warning.TooHigh(diff.toFormattedString(HIGH_FEE_DIFF_DECIMALS)))
}
}
@ -158,5 +162,6 @@ internal class FeeNotificationFactory(
companion object {
private val FEE_MAX_DIFF = BigDecimal(5)
private const val HIGH_FEE_DIFF_DECIMALS = 0
}
}

View file

@ -2,7 +2,9 @@ package com.tangem.features.send.impl.presentation.state.fee
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.common.extensions.isZero
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase
@ -10,10 +12,8 @@ import com.tangem.features.send.impl.presentation.state.SendStates
import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.isNullOrZero
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import java.math.BigDecimal
/**
@ -31,6 +31,15 @@ internal class FeeStateFactory(
SendFeeCustomFieldConverter(
clickIntents = clickIntents,
appCurrencyProvider = appCurrencyProvider,
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
)
}
val feeConverter by lazy {
FeeConverter(
clickIntents = clickIntents,
appCurrencyProvider = appCurrencyProvider,
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
)
}
@ -58,7 +67,7 @@ internal class FeeStateFactory(
customValues = customFeeFieldConverter.convert(fees.normal),
)
val fee = feeSelectorState.getFee()
val fee = feeConverter.convert(feeSelectorState)
val receivedAmount = calculateReceiveAmount(state, fee)
return state.copy(
feeState = feeState.copy(
@ -83,7 +92,7 @@ internal class FeeStateFactory(
fees = fees,
customValues = customFeeFieldConverter.convert(fees.normal),
)
val fee = updatedFeeSelector.getFee()
val fee = feeConverter.convert(updatedFeeSelector)
val receivedAmount = calculateReceiveAmount(state, fee)
return state.copy(
feeState = feeState.copy(
@ -112,7 +121,7 @@ internal class FeeStateFactory(
val balance = coinCryptoCurrencyStatusProvider().value.amount ?: BigDecimal.ZERO
val updatedFeeSelectorState = feeSelectorState.copy(selectedFee = feeType)
val fee = updatedFeeSelectorState.getFee()
val fee = feeConverter.convert(updatedFeeSelectorState)
val receivedAmount = calculateReceiveAmount(state, fee)
return state.copy(
feeState = feeState.copy(
@ -129,14 +138,10 @@ internal class FeeStateFactory(
val state = currentStateProvider()
val feeState = state.feeState ?: return state
val feeSelectorState = feeState.feeSelectorState as? FeeSelectorState.Content ?: return state
val updatedFeeSelectorState = feeSelectorState.copy(
customValues = feeSelectorState.customValues.toMutableList().apply {
set(index, feeSelectorState.customValues[index].copy(value = value))
}.toImmutableList(),
)
val updatedFeeSelectorState = customFeeFieldConverter.onValueChange(feeSelectorState, index, value)
val balance = coinCryptoCurrencyStatusProvider().value.amount ?: BigDecimal.ZERO
val fee = updatedFeeSelectorState.getFee()
val fee = feeConverter.convert(updatedFeeSelectorState)
val receivedAmount = calculateReceiveAmount(state, fee)
return state.copy(
feeState = feeState.copy(
@ -153,7 +158,7 @@ internal class FeeStateFactory(
val state = currentStateProvider()
val feeState = state.feeState ?: return state
val feeSelectorState = feeState.feeSelectorState as? FeeSelectorState.Content ?: return state
val fee = feeSelectorState.getFee()
val fee = feeConverter.convert(feeSelectorState)
val receivedAmount = calculateReceiveAmount(state, fee)
return state.copy(
feeState = feeState.copy(
@ -181,13 +186,17 @@ internal class FeeStateFactory(
notifications: ImmutableList<SendFeeNotification>,
): Boolean {
val feeSelectorState = feeState.feeSelectorState as? FeeSelectorState.Content ?: return false
val customValue = feeSelectorState.customValues.firstOrNull()?.value?.toBigDecimalOrNull()
val customValue = feeSelectorState.customValues.firstOrNull()
val balance = coinCryptoCurrencyStatusProvider().value.amount ?: BigDecimal.ZERO
val fee = feeSelectorState.getFee()
val fee = feeConverter.convert(feeSelectorState)
val feeValue = fee.amount.value ?: BigDecimal.ZERO
val isNotCustom = feeSelectorState.selectedFee != FeeType.CUSTOM
val isNotEmptyCustom = !customValue.isNullOrZero() && !isNotCustom
val isNotEmptyCustom = if (customValue != null) {
!customValue.value.parseToBigDecimal(customValue.decimals).isZero() && !isNotCustom
} else {
false
}
val noErrors = notifications.none { it is SendFeeNotification.Error }
val isSubtractRequired = when {
!feeState.isSubtractAvailable -> true // current currency is not fee currency

View file

@ -1,79 +1,47 @@
package com.tangem.features.send.impl.presentation.state.fee
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.features.send.impl.R
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import com.tangem.utils.toFormattedString
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
internal class SendFeeCustomFieldConverter(
private val clickIntents: SendClickIntents,
private val appCurrencyProvider: Provider<AppCurrency>,
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
) : Converter<Fee, ImmutableList<SendTextField.CustomFee>> {
private val ethereumCustomFeeConverter by lazy {
EthereumCustomFeeConverter(
clickIntents = clickIntents,
appCurrencyProvider = appCurrencyProvider,
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
)
}
override fun convert(value: Fee): ImmutableList<SendTextField.CustomFee> {
val ethereumFee = value as? Fee.Ethereum ?: return persistentListOf()
val appCurrency = appCurrencyProvider()
val maxFeeFiat = BigDecimalFormatter.formatFiatAmount(
fiatAmount = ethereumFee.amount.value,
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
)
return persistentListOf(
SendTextField.CustomFee(
value = ethereumFee.amount.value?.toFormattedString(ethereumFee.amount.decimals).orEmpty(),
decimals = ethereumFee.amount.decimals,
symbol = ethereumFee.amount.currencySymbol,
onValueChange = { clickIntents.onCustomFeeValueChange(0, it) },
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
keyboardType = KeyboardType.Number,
),
title = resourceReference(R.string.send_max_fee),
footer = resourceReference(R.string.send_max_fee_footer),
label = stringReference(maxFeeFiat),
),
SendTextField.CustomFee(
value = ethereumFee.gasPrice.toString(),
decimals = 0,
symbol = ETHEREUM_UNIT,
title = resourceReference(R.string.send_gas_price),
footer = resourceReference(R.string.send_gas_price_footer),
onValueChange = { clickIntents.onCustomFeeValueChange(1, it) },
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
keyboardType = KeyboardType.Number,
),
),
SendTextField.CustomFee(
value = ethereumFee.gasLimit.toString(),
decimals = 0,
symbol = null,
title = resourceReference(R.string.send_gas_limit),
footer = resourceReference(R.string.send_gas_limit_footer),
onValueChange = { clickIntents.onCustomFeeValueChange(2, it) },
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Done,
keyboardType = KeyboardType.Number,
),
),
)
return when (value) {
is Fee.Ethereum -> {
ethereumCustomFeeConverter.convert(value)
}
else -> persistentListOf()
}
}
companion object {
private const val ETHEREUM_UNIT = "GWEI"
}
fun onValueChange(feeSelectorState: FeeSelectorState.Content, index: Int, value: String) = feeSelectorState.copy(
customValues = when (feeSelectorState.fees.normal) {
is Fee.Ethereum -> ethereumCustomFeeConverter.onValueChange(
customValues = feeSelectorState.customValues,
index = index,
value = value,
)
else -> feeSelectorState.customValues
},
)
}

View file

@ -0,0 +1,159 @@
package com.tangem.features.send.impl.presentation.state.fee.custom
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.impl.R
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import java.math.BigDecimal
import java.math.RoundingMode
internal class EthereumCustomFeeConverter(
private val clickIntents: SendClickIntents,
private val appCurrencyProvider: Provider<AppCurrency>,
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
) : Converter<Fee.Ethereum, ImmutableList<SendTextField.CustomFee>> {
override fun convert(value: Fee.Ethereum): ImmutableList<SendTextField.CustomFee> {
return persistentListOf(
SendTextField.CustomFee(
value = value.amount.value?.parseBigDecimal(value.amount.decimals).orEmpty(),
decimals = value.amount.decimals,
symbol = value.amount.currencySymbol,
onValueChange = { clickIntents.onCustomFeeValueChange(FEE_AMOUNT, it) },
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
keyboardType = KeyboardType.Number,
),
title = resourceReference(R.string.send_max_fee),
footer = resourceReference(R.string.send_max_fee_footer),
label = getFeeFormatted(value.amount.value),
),
SendTextField.CustomFee(
value = value.gasPrice.toString(),
decimals = ETHEREUM_GAS_DECIMALS,
symbol = ETHEREUM_GAS_UNIT,
title = resourceReference(R.string.send_gas_price),
footer = resourceReference(R.string.send_gas_price_footer),
onValueChange = { clickIntents.onCustomFeeValueChange(GAS_PRICE, it) },
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
keyboardType = KeyboardType.Number,
),
),
SendTextField.CustomFee(
value = value.gasLimit.toString(),
decimals = GAS_DECIMALS,
symbol = null,
title = resourceReference(R.string.send_gas_limit),
footer = resourceReference(R.string.send_gas_limit_footer),
onValueChange = { clickIntents.onCustomFeeValueChange(GAS_LIMIT, it) },
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Done,
keyboardType = KeyboardType.Number,
),
),
)
}
fun convertBack(normalFee: Fee.Ethereum, value: ImmutableList<SendTextField.CustomFee>): Fee.Ethereum {
val feeAmount = value[FEE_AMOUNT].value.parseToBigDecimal(value[FEE_AMOUNT].decimals)
val gasPrice = value[GAS_PRICE].value.parseToBigDecimal(GAS_DECIMALS).toBigInteger()
val gasLimit = value[GAS_LIMIT].value.parseToBigDecimal(GAS_DECIMALS).toBigInteger()
return normalFee.copy(
amount = normalFee.amount.copy(value = feeAmount),
gasPrice = gasPrice,
gasLimit = gasLimit,
)
}
fun onValueChange(
customValues: ImmutableList<SendTextField.CustomFee>,
index: Int,
value: String,
): ImmutableList<SendTextField.CustomFee> {
val mutableCustomValues = customValues.toMutableList()
return mutableCustomValues.apply {
val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals)
when (index) {
FEE_AMOUNT -> {
val newFeeAmountDecimal = value.parseToBigDecimal(this[FEE_AMOUNT].decimals)
val newFeeAmount = newFeeAmountDecimal.movePointRight(this[FEE_AMOUNT].decimals)
val newGasPrice = newFeeAmount.divide(gasLimit, GAS_DECIMALS, RoundingMode.HALF_UP)
set(GAS_PRICE, this[GAS_PRICE].copy(value = newGasPrice.parseBigDecimal(GAS_DECIMALS)))
set(
index,
this[index].copy(
value = value,
label = getFeeFormatted(newFeeAmountDecimal),
),
)
}
GAS_PRICE -> {
val newGasPrice = value.parseToBigDecimal(this[GAS_PRICE].decimals)
.movePointLeft(this[GAS_PRICE].decimals)
val newFeeAmount = gasLimit * newGasPrice
set(
FEE_AMOUNT,
this[FEE_AMOUNT].copy(
value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals),
label = getFeeFormatted(newFeeAmount),
),
)
set(index, this[index].copy(value = value))
}
else -> {
val newGasLimit = value.parseToBigDecimal(this[GAS_LIMIT].decimals)
val gasPrice = this[GAS_PRICE].value.parseToBigDecimal(this[GAS_PRICE].decimals)
.movePointLeft(this[FEE_AMOUNT].decimals)
val newFeeAmount = newGasLimit * gasPrice
set(
FEE_AMOUNT,
this[FEE_AMOUNT].copy(
value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals),
label = getFeeFormatted(newFeeAmount),
),
)
set(index, this[index].copy(value = value))
}
}
}.toImmutableList()
}
private fun getFeeFormatted(fee: BigDecimal?): TextReference {
val appCurrency = appCurrencyProvider()
val rate = cryptoCurrencyStatusProvider().value.fiatRate
val fiatFee = rate?.let { fee?.multiply(it) }
return stringReference(
BigDecimalFormatter.formatFiatAmount(
fiatAmount = fiatFee,
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
),
)
}
companion object {
private const val ETHEREUM_GAS_UNIT = "GWEI"
private const val ETHEREUM_GAS_DECIMALS = 18
private const val FEE_AMOUNT = 0
private const val GAS_PRICE = 1
private const val GAS_LIMIT = 2
private const val GAS_DECIMALS = 0
}
}

View file

@ -38,7 +38,10 @@ import com.tangem.features.send.api.navigation.SendRouter
import com.tangem.features.send.impl.navigation.InnerSendRouter
import com.tangem.features.send.impl.presentation.domain.AvailableWallet
import com.tangem.features.send.impl.presentation.state.*
import com.tangem.features.send.impl.presentation.state.fee.*
import com.tangem.features.send.impl.presentation.state.fee.FeeNotificationFactory
import com.tangem.features.send.impl.presentation.state.fee.FeeSelectorState
import com.tangem.features.send.impl.presentation.state.fee.FeeStateFactory
import com.tangem.features.send.impl.presentation.state.fee.FeeType
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.JobHolder
@ -71,7 +74,7 @@ internal class SendViewModel @Inject constructor(
private val walletManagersFacade: WalletManagersFacade,
private val reduxStateHolder: ReduxStateHolder,
private val isAmountSubtractAvailableUseCase: IsAmountSubtractAvailableUseCase,
private val isFeeApproximateUseCase: IsFeeApproximateUseCase,
isFeeApproximateUseCase: IsFeeApproximateUseCase,
getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
validateWalletMemoUseCase: ValidateWalletMemoUseCase,
getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase,
@ -536,7 +539,7 @@ internal class SendViewModel @Inject constructor(
val feeState = uiState.feeState ?: return
val feeSelectorState = feeState.feeSelectorState as? FeeSelectorState.Content ?: return
val memo = uiState.recipientState?.memoTextField?.value
val fee = feeSelectorState.getFee()
val fee = feeStateFactory.feeConverter.convert(feeSelectorState)
val amountValue = uiState.amountState?.amountTextField?.cryptoAmount?.value ?: return
val amountToSend = if (feeState.isSubtract && isAmountSubtractAvailable) {
feeState.receivedAmountValue
@ -555,6 +558,7 @@ internal class SendViewModel @Inject constructor(
).fold(
ifLeft = {
Timber.e(it)
uiState = stateFactory.getSendingStateUpdate(isSending = false)
uiState = eventStateFactory.getGenericErrorState(
error = it,
onConsume = { uiState = eventStateFactory.onConsumeEventState() },

View file

@ -85,7 +85,7 @@ spr-client = "3.6.2"
# endregion Other libraries
# region Tangem
tangemBlockchainSdk = "develop-470"
tangemBlockchainSdk = "develop-471"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-324"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^