Updated on 2026-08-14
This commit is contained in:
parent
2313831fc1
commit
f2a3003f0c
6 changed files with 409 additions and 180 deletions
|
|
@ -72,10 +72,7 @@ internal class FeeConverter(
|
|||
normalFee
|
||||
} else {
|
||||
when (normalFee) {
|
||||
is Fee.Ethereum.Legacy -> ethereumCustomFeeConverter.convertBack(
|
||||
normalFee = normalFee,
|
||||
value = customValues,
|
||||
)
|
||||
is Fee.Ethereum -> ethereumCustomFeeConverter.convertBack(normalFee = normalFee, value = customValues)
|
||||
is Fee.Bitcoin -> bitcoinCustomFeeConverter.convertBack(normalFee = normalFee, value = customValues)
|
||||
is Fee.Kaspa -> kaspaCustomFeeConverter.convertBack(normalFee = normalFee, value = customValues)
|
||||
else -> {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ internal class SendFeeCustomFieldConverter(
|
|||
|
||||
override fun convert(value: Fee): ImmutableList<SendTextField.CustomFee> {
|
||||
return when (value) {
|
||||
is Fee.Ethereum.Legacy -> ethereumCustomFeeConverter.convert(value)
|
||||
is Fee.Ethereum -> ethereumCustomFeeConverter.convert(value)
|
||||
is Fee.Bitcoin -> bitcoinCustomFeeConverter.convert(value)
|
||||
is Fee.Kaspa -> kaspaCustomFeeConverter.convert(value)
|
||||
else -> persistentListOf()
|
||||
|
|
@ -59,6 +59,7 @@ internal class SendFeeCustomFieldConverter(
|
|||
fun onValueChange(feeSelectorState: FeeSelectorState.Content, index: Int, value: String) = feeSelectorState.copy(
|
||||
customValues = when (val fee = feeSelectorState.fees.normal) {
|
||||
is Fee.Ethereum -> ethereumCustomFeeConverter.onValueChange(
|
||||
feeValue = fee,
|
||||
customValues = feeSelectorState.customValues,
|
||||
index = index,
|
||||
value = value,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.features.send.impl.presentation.state.fee.custom
|
||||
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
/**
|
||||
* Base ethereum custom fee converter
|
||||
*
|
||||
* @param T subtype of [Fee.Ethereum]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal interface BaseEthereumCustomFeeConverter<T : Fee.Ethereum> : CustomFeeConverter<T> {
|
||||
|
||||
fun getGasLimitIndex(feeValue: T): Int
|
||||
|
||||
fun onValueChange(
|
||||
feeValue: T,
|
||||
customValues: ImmutableList<SendTextField.CustomFee>,
|
||||
index: Int,
|
||||
value: String,
|
||||
): ImmutableList<SendTextField.CustomFee>
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import com.tangem.blockchain.common.transaction.Fee
|
|||
import com.tangem.common.ui.amountScreen.utils.getFiatReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
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
|
||||
|
|
@ -18,203 +17,115 @@ 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 kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.math.RoundingMode
|
||||
|
||||
internal class EthereumCustomFeeConverter(
|
||||
private val clickIntents: SendClickIntents,
|
||||
private val stateRouterProvider: Provider<StateRouter>,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val feeCryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
) : CustomFeeConverter<Fee.Ethereum.Legacy> {
|
||||
) : BaseEthereumCustomFeeConverter<Fee.Ethereum> {
|
||||
|
||||
override fun convert(value: Fee.Ethereum.Legacy): ImmutableList<SendTextField.CustomFee> {
|
||||
val feeValue = value.amount.value
|
||||
val feeCurrency = feeCryptoCurrencyStatusProvider()?.value
|
||||
return persistentListOf(
|
||||
SendTextField.CustomFee(
|
||||
value = feeValue?.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_custom_amount_fee_footer),
|
||||
label = getFiatReference(
|
||||
rate = feeCurrency?.fiatRate,
|
||||
value = feeValue,
|
||||
appCurrency = appCurrencyProvider(),
|
||||
),
|
||||
keyboardActions = KeyboardActions(),
|
||||
),
|
||||
SendTextField.CustomFee(
|
||||
value = value.gasPrice.toBigDecimal().movePointLeft(GIGA_DECIMALS).parseBigDecimal(GIGA_DECIMALS),
|
||||
decimals = GIGA_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,
|
||||
),
|
||||
keyboardActions = KeyboardActions(),
|
||||
),
|
||||
SendTextField.CustomFee(
|
||||
value = value.gasLimit.toString(),
|
||||
decimals = GAS_DECIMALS,
|
||||
symbol = "",
|
||||
title = resourceReference(R.string.send_gas_limit),
|
||||
footer = resourceReference(R.string.send_gas_limit_footer),
|
||||
onValueChange = { clickIntents.onCustomFeeValueChange(GAS_LIMIT, it) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = if (
|
||||
checkExceedBalance(
|
||||
feeBalance = feeCurrency?.amount,
|
||||
feeAmount = feeValue,
|
||||
)
|
||||
) {
|
||||
ImeAction.None
|
||||
} else {
|
||||
ImeAction.Done
|
||||
},
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = { clickIntents.onNextClick(stateRouterProvider().isEditState) },
|
||||
),
|
||||
),
|
||||
)
|
||||
private val feeCurrency: CryptoCurrencyStatus.Value?
|
||||
get() = feeCryptoCurrencyStatusProvider()?.value
|
||||
|
||||
private val legacyFeeConverter = EthereumLegacyCustomFeeConverter(
|
||||
clickIntents = clickIntents,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
feeCryptoCurrencyStatusProvider = feeCryptoCurrencyStatusProvider,
|
||||
)
|
||||
|
||||
private val eipFeeConverter = EthereumEIPCustomFeeConverter(
|
||||
clickIntents = clickIntents,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
feeCryptoCurrencyStatusProvider = feeCryptoCurrencyStatusProvider,
|
||||
)
|
||||
|
||||
override fun convert(value: Fee.Ethereum): ImmutableList<SendTextField.CustomFee> {
|
||||
return buildList {
|
||||
convertFeeValue(value).let(::add)
|
||||
|
||||
when (value) {
|
||||
is Fee.Ethereum.EIP1559 -> eipFeeConverter.convert(value)
|
||||
is Fee.Ethereum.Legacy -> legacyFeeConverter.convert(value)
|
||||
}
|
||||
.let(::addAll)
|
||||
|
||||
convertGasLimitValue(value).let(::add)
|
||||
}
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
override fun convertBack(
|
||||
normalFee: Fee.Ethereum.Legacy,
|
||||
value: ImmutableList<SendTextField.CustomFee>,
|
||||
): Fee.Ethereum.Legacy {
|
||||
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,
|
||||
)
|
||||
override fun convertBack(normalFee: Fee.Ethereum, value: ImmutableList<SendTextField.CustomFee>): Fee.Ethereum {
|
||||
return when (normalFee) {
|
||||
is Fee.Ethereum.EIP1559 -> eipFeeConverter.convertBack(normalFee = normalFee, value = value)
|
||||
is Fee.Ethereum.Legacy -> legacyFeeConverter.convertBack(normalFee = normalFee, value = value)
|
||||
}
|
||||
}
|
||||
|
||||
fun onValueChange(
|
||||
override fun getGasLimitIndex(feeValue: Fee.Ethereum): Int {
|
||||
return when (feeValue) {
|
||||
is Fee.Ethereum.EIP1559 -> eipFeeConverter.getGasLimitIndex(feeValue)
|
||||
is Fee.Ethereum.Legacy -> legacyFeeConverter.getGasLimitIndex(feeValue)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onValueChange(
|
||||
feeValue: Fee.Ethereum,
|
||||
customValues: ImmutableList<SendTextField.CustomFee>,
|
||||
index: Int,
|
||||
value: String,
|
||||
): ImmutableList<SendTextField.CustomFee> {
|
||||
val mutableCustomValues = customValues.toMutableList()
|
||||
return mutableCustomValues.apply {
|
||||
when (index) {
|
||||
FEE_AMOUNT -> setOnAmountChange(value, index)
|
||||
GAS_PRICE -> setOnGasPriceChange(value, index)
|
||||
else -> setOnGasLimitChange(value, index)
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
||||
private fun MutableList<SendTextField.CustomFee>.setEmpty(index: Int) {
|
||||
set(index, this[index].copy(value = ""))
|
||||
}
|
||||
|
||||
private fun MutableList<SendTextField.CustomFee>.setOnAmountChange(value: String, index: Int) {
|
||||
val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals)
|
||||
if (value.isBlank()) {
|
||||
setEmpty(FEE_AMOUNT)
|
||||
setEmpty(GAS_PRICE)
|
||||
} else {
|
||||
val newFeeAmountDecimal = value.parseToBigDecimal(this[FEE_AMOUNT].decimals)
|
||||
val newFeeAmount = newFeeAmountDecimal.movePointRight(this[GAS_PRICE].decimals) // from ETH to GWEI
|
||||
val newGasPrice = newFeeAmount.divide(gasLimit, this[GAS_PRICE].decimals, RoundingMode.HALF_UP)
|
||||
set(GAS_PRICE, this[GAS_PRICE].copy(value = newGasPrice.parseBigDecimal(this[GAS_PRICE].decimals)))
|
||||
set(
|
||||
index,
|
||||
this[index].copy(
|
||||
value = value,
|
||||
label = getFiatReference(
|
||||
rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
|
||||
value = newFeeAmountDecimal,
|
||||
appCurrency = appCurrencyProvider(),
|
||||
),
|
||||
),
|
||||
)
|
||||
return when (feeValue) {
|
||||
is Fee.Ethereum.EIP1559 -> eipFeeConverter.onValueChange(feeValue, customValues, index, value)
|
||||
is Fee.Ethereum.Legacy -> legacyFeeConverter.onValueChange(feeValue, customValues, index, value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<SendTextField.CustomFee>.setOnGasPriceChange(value: String, index: Int) {
|
||||
val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals)
|
||||
if (value.isBlank()) {
|
||||
setEmpty(FEE_AMOUNT)
|
||||
setEmpty(GAS_PRICE)
|
||||
} else {
|
||||
val newGasPrice = value.parseToBigDecimal(this[GAS_PRICE].decimals)
|
||||
.movePointLeft(this[GAS_PRICE].decimals) // from GWEI to ETH
|
||||
val newFeeAmount = gasLimit * newGasPrice
|
||||
set(
|
||||
FEE_AMOUNT,
|
||||
this[FEE_AMOUNT].copy(
|
||||
value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals),
|
||||
label = getFiatReference(
|
||||
rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
|
||||
value = newFeeAmount,
|
||||
appCurrency = appCurrencyProvider(),
|
||||
),
|
||||
),
|
||||
)
|
||||
set(index, this[index].copy(value = value))
|
||||
}
|
||||
private fun convertFeeValue(value: Fee.Ethereum): SendTextField.CustomFee {
|
||||
val feeValue = value.amount.value
|
||||
|
||||
return SendTextField.CustomFee(
|
||||
value = feeValue?.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_custom_amount_fee_footer),
|
||||
label = getFiatReference(
|
||||
rate = feeCurrency?.fiatRate,
|
||||
value = feeValue,
|
||||
appCurrency = appCurrencyProvider(),
|
||||
),
|
||||
keyboardActions = KeyboardActions(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableList<SendTextField.CustomFee>.setOnGasLimitChange(value: String, index: Int) {
|
||||
if (value.isBlank()) {
|
||||
setEmpty(FEE_AMOUNT)
|
||||
setEmpty(GAS_LIMIT)
|
||||
} else {
|
||||
val newGasLimit = value.parseToBigDecimal(this[GAS_LIMIT].decimals)
|
||||
val gasPrice = this[GAS_PRICE].value.parseToBigDecimal(this[GAS_PRICE].decimals)
|
||||
.movePointLeft(this[GAS_PRICE].decimals) // from GWEI to ETH
|
||||
val newFeeAmount = newGasLimit * gasPrice
|
||||
set(
|
||||
FEE_AMOUNT,
|
||||
this[FEE_AMOUNT].copy(
|
||||
value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals),
|
||||
label = getFiatReference(
|
||||
rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
|
||||
value = newFeeAmount,
|
||||
appCurrency = appCurrencyProvider(),
|
||||
),
|
||||
),
|
||||
)
|
||||
val isNotExceedBalance = checkExceedBalance(
|
||||
feeBalance = feeCryptoCurrencyStatusProvider()?.value?.amount,
|
||||
feeAmount = newFeeAmount,
|
||||
)
|
||||
set(
|
||||
index,
|
||||
this[index].copy(
|
||||
value = value,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = if (!isNotExceedBalance) ImeAction.None else ImeAction.Done,
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
private fun convertGasLimitValue(value: Fee.Ethereum): SendTextField.CustomFee {
|
||||
val isExceedBalance = checkExceedBalance(feeBalance = feeCurrency?.amount, feeAmount = value.amount.value)
|
||||
|
||||
return SendTextField.CustomFee(
|
||||
value = value.gasLimit.toString(),
|
||||
decimals = GAS_DECIMALS,
|
||||
symbol = "",
|
||||
title = resourceReference(R.string.send_gas_limit),
|
||||
footer = resourceReference(R.string.send_gas_limit_footer),
|
||||
onValueChange = { clickIntents.onCustomFeeValueChange(getGasLimitIndex(value), it) },
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = if (isExceedBalance) ImeAction.None else ImeAction.Done,
|
||||
keyboardType = KeyboardType.Number,
|
||||
),
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = { clickIntents.onNextClick(stateRouterProvider().isEditState) },
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ETHEREUM_GAS_UNIT = "GWEI"
|
||||
private const val GIGA_DECIMALS = 9
|
||||
private const val FEE_AMOUNT = 0
|
||||
private const val GAS_PRICE = 1
|
||||
private const val GAS_LIMIT = 2
|
||||
private const val GAS_DECIMALS = 0
|
||||
const val ETHEREUM_GAS_UNIT = "GWEI"
|
||||
const val GIGA_DECIMALS = 9
|
||||
const val GAS_DECIMALS = 0
|
||||
const val FEE_AMOUNT = 0
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
package com.tangem.features.send.impl.presentation.state.fee.custom
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
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.common.ui.amountScreen.utils.getFiatReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
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.fee.custom.EthereumCustomFeeConverter.Companion.ETHEREUM_GAS_UNIT
|
||||
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.FEE_AMOUNT
|
||||
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.GAS_DECIMALS
|
||||
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.GIGA_DECIMALS
|
||||
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 kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.math.RoundingMode
|
||||
|
||||
internal class EthereumEIPCustomFeeConverter(
|
||||
private val clickIntents: SendClickIntents,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val feeCryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
) : BaseEthereumCustomFeeConverter<Fee.Ethereum.EIP1559> {
|
||||
|
||||
override fun convert(value: Fee.Ethereum.EIP1559): ImmutableList<SendTextField.CustomFee> {
|
||||
return persistentListOf(
|
||||
SendTextField.CustomFee(
|
||||
value = value.maxFeePerGas.toBigDecimal().movePointLeft(GIGA_DECIMALS).parseBigDecimal(GIGA_DECIMALS),
|
||||
decimals = GIGA_DECIMALS,
|
||||
symbol = ETHEREUM_GAS_UNIT,
|
||||
title = resourceReference(R.string.send_custom_evm_max_fee),
|
||||
footer = resourceReference(R.string.send_custom_evm_max_fee_footer),
|
||||
onValueChange = { clickIntents.onCustomFeeValueChange(MAX_FEE, it) },
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next, keyboardType = KeyboardType.Number),
|
||||
keyboardActions = KeyboardActions(),
|
||||
),
|
||||
SendTextField.CustomFee(
|
||||
value = value.priorityFee.toBigDecimal().movePointLeft(GIGA_DECIMALS).parseBigDecimal(GIGA_DECIMALS),
|
||||
decimals = GIGA_DECIMALS,
|
||||
symbol = ETHEREUM_GAS_UNIT,
|
||||
title = resourceReference(R.string.send_custom_evm_priority_fee),
|
||||
footer = resourceReference(R.string.send_custom_evm_priority_fee_footer),
|
||||
onValueChange = { clickIntents.onCustomFeeValueChange(PRIORITY_FEE, it) },
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next, keyboardType = KeyboardType.Number),
|
||||
keyboardActions = KeyboardActions(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun convertBack(
|
||||
normalFee: Fee.Ethereum.EIP1559,
|
||||
value: ImmutableList<SendTextField.CustomFee>,
|
||||
): Fee.Ethereum.EIP1559 {
|
||||
val feeAmount = value[FEE_AMOUNT].value.parseToBigDecimal(value[FEE_AMOUNT].decimals)
|
||||
val maxFee = value[MAX_FEE].value.parseToBigDecimal(GAS_DECIMALS).toBigInteger()
|
||||
val priorityFee = value[PRIORITY_FEE].value.parseToBigDecimal(GAS_DECIMALS).toBigInteger()
|
||||
val gasLimit = value[GAS_LIMIT].value.parseToBigDecimal(GAS_DECIMALS).toBigInteger()
|
||||
|
||||
return normalFee.copy(
|
||||
amount = normalFee.amount.copy(value = feeAmount),
|
||||
maxFeePerGas = maxFee,
|
||||
priorityFee = priorityFee,
|
||||
gasLimit = gasLimit,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getGasLimitIndex(feeValue: Fee.Ethereum.EIP1559): Int = GAS_LIMIT
|
||||
|
||||
override fun onValueChange(
|
||||
feeValue: Fee.Ethereum.EIP1559,
|
||||
customValues: ImmutableList<SendTextField.CustomFee>,
|
||||
index: Int,
|
||||
value: String,
|
||||
): ImmutableList<SendTextField.CustomFee> {
|
||||
val mutableCustomValues = customValues.toMutableList()
|
||||
return mutableCustomValues.apply {
|
||||
when (index) {
|
||||
FEE_AMOUNT -> setOnAmountChange(value, index)
|
||||
MAX_FEE -> setOnMaxFeeChange(value, index)
|
||||
else -> set(index, this[index].copy(value = value))
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
||||
private fun MutableList<SendTextField.CustomFee>.setEmpty(index: Int) {
|
||||
set(index, this[index].copy(value = ""))
|
||||
}
|
||||
|
||||
private fun MutableList<SendTextField.CustomFee>.setOnAmountChange(value: String, index: Int) {
|
||||
val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals)
|
||||
if (value.isBlank()) {
|
||||
setEmpty(FEE_AMOUNT)
|
||||
setEmpty(MAX_FEE)
|
||||
} else {
|
||||
val newFeeAmountDecimal = value.parseToBigDecimal(this[FEE_AMOUNT].decimals)
|
||||
val newFeeAmount = newFeeAmountDecimal.movePointRight(GIGA_DECIMALS) // from ETH to GWEI
|
||||
|
||||
val newMaxFee = newFeeAmount.divide(gasLimit, this[MAX_FEE].decimals, RoundingMode.HALF_UP)
|
||||
|
||||
set(
|
||||
index = MAX_FEE,
|
||||
element = this[MAX_FEE].copy(value = newMaxFee.parseBigDecimal(this[MAX_FEE].decimals)),
|
||||
)
|
||||
|
||||
set(
|
||||
index = index,
|
||||
element = this[index].copy(
|
||||
value = value,
|
||||
label = getFiatReference(
|
||||
rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
|
||||
value = newFeeAmountDecimal,
|
||||
appCurrency = appCurrencyProvider(),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<SendTextField.CustomFee>.setOnMaxFeeChange(value: String, index: Int) {
|
||||
val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals)
|
||||
|
||||
if (value.isBlank()) {
|
||||
setEmpty(FEE_AMOUNT)
|
||||
setEmpty(MAX_FEE)
|
||||
} else {
|
||||
val newMaxFee = value.parseToBigDecimal(this[MAX_FEE].decimals).movePointLeft(this[MAX_FEE].decimals)
|
||||
val newFeeAmount = gasLimit * newMaxFee
|
||||
set(
|
||||
FEE_AMOUNT,
|
||||
this[FEE_AMOUNT].copy(
|
||||
value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals),
|
||||
label = getFiatReference(
|
||||
rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
|
||||
value = newFeeAmount,
|
||||
appCurrency = appCurrencyProvider(),
|
||||
),
|
||||
),
|
||||
)
|
||||
set(index, this[index].copy(value = value))
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MAX_FEE = 1
|
||||
const val PRIORITY_FEE = 2
|
||||
const val GAS_LIMIT = 3
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
package com.tangem.features.send.impl.presentation.state.fee.custom
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
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.common.ui.amountScreen.utils.getFiatReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
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.fee.custom.EthereumCustomFeeConverter.Companion.ETHEREUM_GAS_UNIT
|
||||
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.FEE_AMOUNT
|
||||
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.GAS_DECIMALS
|
||||
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter.Companion.GIGA_DECIMALS
|
||||
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 kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.math.RoundingMode
|
||||
|
||||
internal class EthereumLegacyCustomFeeConverter(
|
||||
private val clickIntents: SendClickIntents,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val feeCryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
) : BaseEthereumCustomFeeConverter<Fee.Ethereum.Legacy> {
|
||||
|
||||
override fun convert(value: Fee.Ethereum.Legacy): ImmutableList<SendTextField.CustomFee> {
|
||||
return persistentListOf(
|
||||
SendTextField.CustomFee(
|
||||
value = value.gasPrice.toBigDecimal().movePointLeft(GIGA_DECIMALS).parseBigDecimal(GIGA_DECIMALS),
|
||||
decimals = GIGA_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,
|
||||
),
|
||||
keyboardActions = KeyboardActions(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun convertBack(
|
||||
normalFee: Fee.Ethereum.Legacy,
|
||||
value: ImmutableList<SendTextField.CustomFee>,
|
||||
): Fee.Ethereum.Legacy {
|
||||
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,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getGasLimitIndex(feeValue: Fee.Ethereum.Legacy): Int = GAS_LIMIT
|
||||
|
||||
override fun onValueChange(
|
||||
feeValue: Fee.Ethereum.Legacy,
|
||||
customValues: ImmutableList<SendTextField.CustomFee>,
|
||||
index: Int,
|
||||
value: String,
|
||||
): ImmutableList<SendTextField.CustomFee> {
|
||||
val mutableCustomValues = customValues.toMutableList()
|
||||
return mutableCustomValues.apply {
|
||||
when (index) {
|
||||
FEE_AMOUNT -> setOnAmountChange(value, index)
|
||||
GAS_PRICE -> setOnGasPriceChange(value, index)
|
||||
else -> set(index, this[index].copy(value = value))
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
||||
private fun MutableList<SendTextField.CustomFee>.setEmpty(index: Int) {
|
||||
set(index, this[index].copy(value = ""))
|
||||
}
|
||||
|
||||
private fun MutableList<SendTextField.CustomFee>.setOnAmountChange(value: String, index: Int) {
|
||||
val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals)
|
||||
if (value.isBlank()) {
|
||||
setEmpty(FEE_AMOUNT)
|
||||
setEmpty(GAS_PRICE)
|
||||
} else {
|
||||
val newFeeAmountDecimal = value.parseToBigDecimal(this[FEE_AMOUNT].decimals)
|
||||
val newFeeAmount = newFeeAmountDecimal.movePointRight(this[GAS_PRICE].decimals) // from ETH to GWEI
|
||||
val newGasPrice = newFeeAmount.divide(gasLimit, this[GAS_PRICE].decimals, RoundingMode.HALF_UP)
|
||||
set(GAS_PRICE, this[GAS_PRICE].copy(value = newGasPrice.parseBigDecimal(this[GAS_PRICE].decimals)))
|
||||
set(
|
||||
index,
|
||||
this[index].copy(
|
||||
value = value,
|
||||
label = getFiatReference(
|
||||
rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
|
||||
value = newFeeAmountDecimal,
|
||||
appCurrency = appCurrencyProvider(),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<SendTextField.CustomFee>.setOnGasPriceChange(value: String, index: Int) {
|
||||
val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals)
|
||||
if (value.isBlank()) {
|
||||
setEmpty(FEE_AMOUNT)
|
||||
setEmpty(GAS_PRICE)
|
||||
} else {
|
||||
val newGasPrice = value.parseToBigDecimal(this[GAS_PRICE].decimals)
|
||||
.movePointLeft(this[GAS_PRICE].decimals) // from GWEI to ETH
|
||||
val newFeeAmount = gasLimit * newGasPrice
|
||||
set(
|
||||
FEE_AMOUNT,
|
||||
this[FEE_AMOUNT].copy(
|
||||
value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT].decimals),
|
||||
label = getFiatReference(
|
||||
rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
|
||||
value = newFeeAmount,
|
||||
appCurrency = appCurrencyProvider(),
|
||||
),
|
||||
),
|
||||
)
|
||||
set(index, this[index].copy(value = value))
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val GAS_PRICE = 1
|
||||
const val GAS_LIMIT = 2
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue