diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 6cb64bafa2..84cc72c8e2 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -487,15 +487,17 @@
Транзакция не выполнена
Сумма
Вы можете установить комиссию за транзакцию, изменив значение в поле Satoshi per vByte.
+ Комиссия, которая будет взята за вашу транзакцию. Вы можете выставить своё собственное значение.
Это стоимость, которую вы готовы заплатить за каждую единицу газа. Чем выше цена газа, тем быстрее ваша транзакция будет обработана. (Приоритетная комиссия включена)
Приоритетная комиссия
Комиссия, которую пользователь может заплатить майнерам или валидаторам за ускорение включения его транзакции в блок.
+ Комиссия, которую нужно заплатить за использование каждого неиспользованного выхода транзакции (UTXO) в сети Kaspa. Чем больше UTXO вы используете в транзакции, тем выше будет комиссия.
+ KAS за UTXO
%1$s, %2$s
Адрес
Код назначения
Введите адрес
Адрес совпадает с адресом кошелька
- Комиссия, которая будет взята за вашу транзакцию. Вы можете выставить своё собственное значение.
Недопустимый Tag. Он не будет добавлен в транзакцию.
Недопустимый Memo. Он не будет добавлен в транзакцию.
Tag
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 6b23058989..5ef91d4236 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -39,6 +39,7 @@
Too many attempts
You have disabled biometric authentication on your phone and will not be able to save wallets in the app. To save wallets, please enable the biometric authentication function in your phone settings.
Start backup process
+ From your fiat card or bank account
- %d card
- %d cards
@@ -257,6 +258,7 @@
No tokens found. Please try another request
ID: %s
Transaction ID copied
+ From another currency in your wallet
The following information is optional. You can erase it if you don\'t want to share it.
Tell us what functions you are missing, and we will try to help you.
Please tell us what card do you have
@@ -329,10 +331,12 @@
To start buying, exchanging or receiving this asset, add this token to at least 1 network
This asset is not available
Add to portfolio
+ Add token
Available networks
My portfolio
Market
To generate addresses for selected networks, you need to attach a Tangem card
+ Quick actions
Select network
Select wallet
1m
@@ -348,6 +352,7 @@
Top Gainers
Top losers
Trending
+ About %s
- Based on %d rating
- Based on %d ratings
@@ -486,6 +491,7 @@
Camera access denied
%1$s (%2$s) on %3$s network
Send only %s to this address. Sending any other currency will result in its irreversible loss.
+ Show QR-code or share your address
Participate
Failed to load the information about the referral program. Please try again later.
Failed to load the information about the referral program. Error code: %s. Please try again later.
@@ -541,16 +547,18 @@
The transaction is not completed
Amount
You can set your transaction fee by adjusting the value in the Satoshi per vByte field.
+ The fee that will be charged for your transaction. You can set your own value.
Max fee
This is the cost you are willing to pay for each unit of gas. The higher the gas price, the faster your transaction will be processed. (Priority fee included)
Priority fee
The fee that a user can pay to miners or validators to expedite the inclusion of their transaction in a block.
+ The fee required for using each unspent transaction output (UTXO) in the Kaspa network. The more UTXOs you use in a transaction, the higher the fee will be.
+ KAS per UTXO
%1$s, %2$s
Address
Destination Tag
Enter address
Address is the same as wallet address
- The fee that will be charged for your transaction. You can set your own value.
Invalid Tag. It won\'t be added to the transaction.
Invalid Memo. It won\'t be added to the transaction.
Tag
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeConverter.kt
index 5109aa17b9..670da73277 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeConverter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/FeeConverter.kt
@@ -8,6 +8,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.impl.presentation.state.StateRouter
import com.tangem.features.send.impl.presentation.state.fee.custom.BitcoinCustomFeeConverter
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter
+import com.tangem.features.send.impl.presentation.state.fee.custom.KaspaCustomFeeConverter
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
@@ -37,6 +38,15 @@ internal class FeeConverter(
)
}
+ private val kaspaCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
+ KaspaCustomFeeConverter(
+ clickIntents = clickIntents,
+ stateRouterProvider = stateRouterProvider,
+ appCurrencyProvider = appCurrencyProvider,
+ feeCryptoCurrencyStatusProvider = feeCryptoCurrencyStatusProvider,
+ )
+ }
+
override fun convert(value: FeeSelectorState.Content): Fee {
return when (val fees = value.fees) {
is TransactionFee.Choosable -> {
@@ -47,7 +57,12 @@ internal class FeeConverter(
FeeType.Custom -> convertCustom(value, fees)
}
}
- is TransactionFee.Single -> fees.normal
+ is TransactionFee.Single ->
+ when (value.selectedFee) {
+ FeeType.Market -> fees.normal
+ FeeType.Custom -> convertCustom(value, fees)
+ else -> fees.normal
+ }
}
}
@@ -60,6 +75,7 @@ internal class FeeConverter(
when (normalFee) {
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 -> {
val customFee = customValues.firstOrNull()
Fee.Common(
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeCustomFieldConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeCustomFieldConverter.kt
index 5fd2a4060d..d80cf917b0 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeCustomFieldConverter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeCustomFieldConverter.kt
@@ -6,6 +6,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.impl.presentation.state.StateRouter
import com.tangem.features.send.impl.presentation.state.fee.custom.BitcoinCustomFeeConverter
import com.tangem.features.send.impl.presentation.state.fee.custom.EthereumCustomFeeConverter
+import com.tangem.features.send.impl.presentation.state.fee.custom.KaspaCustomFeeConverter
import com.tangem.features.send.impl.presentation.state.fields.SendTextField
import com.tangem.features.send.impl.presentation.viewmodel.SendClickIntents
import com.tangem.utils.Provider
@@ -38,10 +39,20 @@ internal class SendFeeCustomFieldConverter(
)
}
+ private val kaspaCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
+ KaspaCustomFeeConverter(
+ clickIntents = clickIntents,
+ stateRouterProvider = stateRouterProvider,
+ appCurrencyProvider = appCurrencyProvider,
+ feeCryptoCurrencyStatusProvider = feeCryptoCurrencyStatusProvider,
+ )
+ }
+
override fun convert(value: Fee): ImmutableList {
return when (value) {
is Fee.Ethereum -> ethereumCustomFeeConverter.convert(value)
is Fee.Bitcoin -> bitcoinCustomFeeConverter.convert(value)
+ is Fee.Kaspa -> kaspaCustomFeeConverter.convert(value)
else -> persistentListOf()
}
}
@@ -59,6 +70,12 @@ internal class SendFeeCustomFieldConverter(
value = value,
txSize = fee.txSize,
)
+ is Fee.Kaspa -> kaspaCustomFeeConverter.onValueChange(
+ customValues = feeSelectorState.customValues,
+ index = index,
+ value = value,
+ utxoCount = fee.utxoCount,
+ )
else -> feeSelectorState.customValues
},
)
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt
index 0c9185cf91..fdee783db4 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/EthereumCustomFeeConverter.kt
@@ -43,7 +43,7 @@ internal class EthereumCustomFeeConverter(
keyboardType = KeyboardType.Number,
),
title = resourceReference(R.string.send_max_fee),
- footer = resourceReference(R.string.send_evm_custom_fee_footer),
+ footer = resourceReference(R.string.send_custom_amount_fee_footer),
label = getFiatReference(
rate = feeCurrency?.fiatRate,
value = feeValue,
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/KaspaCustomFeeConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/KaspaCustomFeeConverter.kt
new file mode 100644
index 0000000000..05b117547d
--- /dev/null
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/custom/KaspaCustomFeeConverter.kt
@@ -0,0 +1,153 @@
+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.StateRouter
+import com.tangem.features.send.impl.presentation.state.fee.checkExceedBalance
+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 KaspaCustomFeeConverter(
+ private val clickIntents: SendClickIntents,
+ private val stateRouterProvider: Provider,
+ private val appCurrencyProvider: Provider,
+ private val feeCryptoCurrencyStatusProvider: Provider,
+) : CustomFeeConverter {
+
+ override fun convert(value: Fee.Kaspa): ImmutableList {
+ val feeValue = value.amount.value
+ val feeCurrency = feeCryptoCurrencyStatusProvider()?.value
+ val network = feeCryptoCurrencyStatusProvider()?.currency?.network?.id?.value
+ return if (network != null) {
+ persistentListOf(
+ SendTextField.CustomFee(
+ value = feeValue?.parseBigDecimal(value.amount.decimals).orEmpty(),
+ decimals = value.amount.decimals,
+ symbol = value.amount.currencySymbol,
+ onValueChange = { clickIntents.onCustomFeeValueChange(FEE_AMOUNT_INDEX, 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.valuePerUtxo.parseBigDecimal(value.amount.decimals),
+ decimals = value.amount.decimals,
+ symbol = "",
+ title = resourceReference(R.string.send_custom_kaspa_per_utxo_title),
+ footer = resourceReference(R.string.send_custom_kaspa_per_utxo_footer),
+ onValueChange = { clickIntents.onCustomFeeValueChange(FEE_VALUE_PER_UTXO_INDEX, 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) },
+ ),
+ ),
+ )
+ } else {
+ persistentListOf()
+ }
+ }
+
+ override fun convertBack(normalFee: Fee.Kaspa, value: ImmutableList): Fee.Kaspa {
+ val feeAmount = value[FEE_AMOUNT_INDEX].value.parseToBigDecimal(value[FEE_AMOUNT_INDEX].decimals)
+ val valuePerUtxo =
+ value[FEE_VALUE_PER_UTXO_INDEX].value.parseToBigDecimal(value[FEE_VALUE_PER_UTXO_INDEX].decimals)
+ return normalFee.copy(
+ amount = normalFee.amount.copy(value = feeAmount),
+ valuePerUtxo = valuePerUtxo,
+ )
+ }
+
+ fun onValueChange(
+ customValues: ImmutableList,
+ index: Int,
+ value: String,
+ utxoCount: Int,
+ ): ImmutableList {
+ val mutableCustomValues = customValues.toMutableList()
+ return mutableCustomValues.apply {
+ when (index) {
+ FEE_AMOUNT_INDEX -> {
+ val valueDecimal = value.parseToBigDecimal(this[FEE_AMOUNT_INDEX].decimals)
+ val newValuePerUtxo = valueDecimal.divide(
+ /* divisor = */ utxoCount.toBigDecimal(),
+ /* scale = */ this[FEE_VALUE_PER_UTXO_INDEX].decimals,
+ /* roundingMode = */ RoundingMode.HALF_UP,
+ )
+ set(
+ FEE_VALUE_PER_UTXO_INDEX,
+ this[FEE_VALUE_PER_UTXO_INDEX].copy(
+ value = newValuePerUtxo.parseBigDecimal(this[FEE_VALUE_PER_UTXO_INDEX].decimals),
+ ),
+ )
+ set(
+ index,
+ this[index].copy(
+ value = value,
+ label = getFiatReference(
+ rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
+ value = valueDecimal,
+ appCurrency = appCurrencyProvider(),
+ ),
+ ),
+ )
+ }
+ FEE_VALUE_PER_UTXO_INDEX -> {
+ val valuePerUtxo = value.parseToBigDecimal(this[FEE_VALUE_PER_UTXO_INDEX].decimals)
+ val newFeeAmount = valuePerUtxo.multiply(utxoCount.toBigDecimal())
+ set(
+ FEE_AMOUNT_INDEX,
+ this[FEE_AMOUNT_INDEX].copy(
+ value = newFeeAmount.parseBigDecimal(this[FEE_AMOUNT_INDEX].decimals),
+ label = getFiatReference(
+ rate = feeCryptoCurrencyStatusProvider()?.value?.fiatRate,
+ value = newFeeAmount,
+ appCurrency = appCurrencyProvider(),
+ ),
+ ),
+ )
+ set(index, this[index].copy(value = value))
+ }
+ }
+ }.toImmutableList()
+ }
+
+ private companion object {
+ private const val FEE_AMOUNT_INDEX = 0
+ private const val FEE_VALUE_PER_UTXO_INDEX = 1
+ }
+}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt
index b1cf3f315d..08e3ff9853 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/fee/SendSpeedSelectorItem.kt
@@ -36,9 +36,8 @@ internal fun SendSpeedSelectorItem(
val content = feeSelectorState as? FeeSelectorState.Content
val amount = content?.getAmount(feeType)
val (showDivider, isVisible) = content.getDividerAndVisibility(feeType)
- val hasCustomValues = !content?.customValues.isNullOrEmpty()
AnimatedVisibility(
- visible = isVisible || hasCustomValues,
+ visible = isVisible,
label = "Fee Selector Visibility Animation",
enter = expandVertically().plus(fadeIn()),
exit = shrinkVertically().plus(fadeOut()),
@@ -135,7 +134,7 @@ private fun FeeSelectorState.Content?.getDividerAndVisibility(feeType: FeeType):
val isNotSingle = this?.fees !is TransactionFee.Single
return when (feeType) {
FeeType.Slow -> true to isNotSingle
- FeeType.Market -> isNotSingle to true
+ FeeType.Market -> (isNotSingle || hasCustomValues) to true
FeeType.Fast -> hasCustomValues to isNotSingle
FeeType.Custom -> false to hasCustomValues
}
diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml
index 4742ffb2c9..e8dbee94ec 100644
--- a/gradle/dependencies.toml
+++ b/gradle/dependencies.toml
@@ -88,7 +88,7 @@ markdown = "0.7.2"
# endregion Other libraries
# region Tangem
-tangemBlockchainSdk = "develop-699"
+tangemBlockchainSdk = "develop-700"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-370"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^