diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt
index a50de375f4..dbf1db4f40 100644
--- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt
@@ -330,6 +330,7 @@ class ReceiptReducer : SendInternalReducer {
FeePaidCurrency.Coin -> wallet.blockchain.currency
FeePaidCurrency.SameCurrency -> store.state.sendState.currency?.symbol
is FeePaidCurrency.Token -> feePaidCurrency.token.symbol
+ is FeePaidCurrency.FeeResource -> feePaidCurrency.currency
},
)
}
@@ -356,9 +357,12 @@ class ReceiptReducer : SendInternalReducer {
FeePaidCurrency.Coin -> when (amountType) {
AmountType.Coin -> ReceiptLayoutType.FIAT
is AmountType.Token -> ReceiptLayoutType.TOKEN_FIAT
- AmountType.Reserve -> ReceiptLayoutType.UNKNOWN
+ is AmountType.FeeResource,
+ AmountType.Reserve,
+ -> ReceiptLayoutType.UNKNOWN
}
FeePaidCurrency.SameCurrency -> ReceiptLayoutType.SAME_CURRENCY_FIAT
+ is FeePaidCurrency.FeeResource -> ReceiptLayoutType.SAME_CURRENCY
}
}
@@ -374,8 +378,11 @@ class ReceiptReducer : SendInternalReducer {
FeePaidCurrency.Coin -> when (amountType) {
AmountType.Coin -> ReceiptLayoutType.CRYPTO
is AmountType.Token -> ReceiptLayoutType.TOKEN_CRYPTO
- AmountType.Reserve -> ReceiptLayoutType.UNKNOWN
+ is AmountType.FeeResource,
+ AmountType.Reserve,
+ -> ReceiptLayoutType.UNKNOWN
}
+ is FeePaidCurrency.FeeResource -> ReceiptLayoutType.UNKNOWN
}
}
diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt
index f71667eed8..9ac9254fec 100644
--- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/SendScreenReducer.kt
@@ -122,6 +122,7 @@ private class PrepareSendScreenStatesReducer : SendInternalReducer {
sendToken.name.equals(feePaidCurrency.token.name, ignoreCase = true) &&
sendToken.symbol.equals(feePaidCurrency.token.symbol, ignoreCase = true)
}
+ is FeePaidCurrency.FeeResource -> false
}
}
}
diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt
index b953ab71dd..d3d3cd7e19 100644
--- a/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt
+++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt
@@ -82,14 +82,18 @@ data class SendState(
fun convertFiatToExtractCrypto(fiatValue: BigDecimal): BigDecimal = when (amountState.typeOfAmount) {
AmountType.Coin -> convertFiatToCoin(fiatValue)
is AmountType.Token -> convertFiatToToken(fiatValue)
- AmountType.Reserve -> fiatValue
+ is AmountType.FeeResource,
+ AmountType.Reserve,
+ -> fiatValue
}
fun convertExtractCryptoToFiat(cryptoValue: BigDecimal, scaleWithPrecision: Boolean = false): BigDecimal {
return when (amountState.typeOfAmount) {
AmountType.Coin -> convertCoinToFiat(cryptoValue, scaleWithPrecision)
is AmountType.Token -> convertTokenToFiat(cryptoValue, scaleWithPrecision)
- AmountType.Reserve -> cryptoValue
+ is AmountType.FeeResource,
+ AmountType.Reserve,
+ -> cryptoValue
}
}
@@ -108,7 +112,9 @@ data class SendState(
return when (amountState.typeOfAmount) {
AmountType.Coin -> coinIsConvertible()
is AmountType.Token -> tokenIsConvertible()
- AmountType.Reserve -> false
+ is AmountType.FeeResource,
+ AmountType.Reserve,
+ -> false
}
}
diff --git a/app/src/test/kotlin/com/tangem/tap/domain/card/CryptoCurrenciesMocks.kt b/app/src/test/kotlin/com/tangem/tap/domain/card/CryptoCurrenciesMocks.kt
index 43c27150f4..aadeccf980 100644
--- a/app/src/test/kotlin/com/tangem/tap/domain/card/CryptoCurrenciesMocks.kt
+++ b/app/src/test/kotlin/com/tangem/tap/domain/card/CryptoCurrenciesMocks.kt
@@ -67,6 +67,7 @@ internal class CryptoCurrenciesMocks(private val scanResponse: ScanResponse) {
),
isTestnet = false,
standardType = Network.StandardType.ERC20,
+ hasFiatFeeRate = true,
),
name = "NEVER-MIND",
symbol = "NEVER-MIND",
diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 23dd6a8a8c..d69a9a52dd 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -94,6 +94,7 @@
Получить адреса
К провайдеру
Импортировать
+ Позже
Заблокирован
Основная сеть
Сетевая комиссия
@@ -254,6 +255,14 @@
Приложите, чтобы подписать
Приложите карту
Вы обновили данные биометрии, отсканируйте свою карту для входа
+ Ваш баланс должен быть выше суммы комиссии для осуществления перевода
+ Недостаточно средств
+ У вас недостаточно Маны для этой транзакции. Пожалуйста, подождите, пока Мана восполнится. Ваш баланс маны равен %1$s/%2$s
+ Недостаточно Маны
+ Вы можете перевести только %s из-за ограничения Mana, установленного сетью Koinos
+ Лимит маны
+ Сеть Koinos использует Ману для оплаты комиссии сети. У вас есть %1$s/%2$s Mana
+ Уровень маны
Чтобы начать отслеживать свои криптоактивы и транзакции, добавьте токены
Управление токенами
Чтобы получить доступ ко всем сетям, вам необходимо отсканировать карту
@@ -298,6 +307,7 @@
Введенные коды доступа не совпадают
Необходимо повторить операцию, при этом карта будет сброшена к заводским настройкам
Ошибка активации
+ Добавление токенов
Вы добавили одну резервную карту. После того, как процесс будет завершен, Вы больше не сможете добавить карт. Если у Вас есть еще одна карта, добавьте ее в резервную копию. Хотите продолжить?
Процесс резервного копирования почти завершен. Вы не можете выйти из него сейчас.
Парольная фраза — это расширенная функция безопасности, которую используют криптокошельки. Она добавляет дополнительное слово или фразу по вашему выбору к уже существующей seed - фразе, чтобы разблокировать совершенно новый набор адресов.
@@ -445,6 +455,9 @@
Транзакция не выполнена
Сумма
Вы можете установить комиссию за транзакцию, изменив значение в поле Satoshi per vByte.
+ Это стоимость, которую вы готовы заплатить за каждую единицу газа. Чем выше цена газа, тем быстрее ваша транзакция будет обработана. (Приоритетная комиссия включена)
+ Приоритетная комиссия
+ Комиссия, которую пользователь может заплатить майнерам или валидаторам за ускорение включения его транзакции в блок.
%1$s, %2$s
Адрес
Код назначения
@@ -468,8 +481,8 @@
Это стоимость, которую вы готовы заплатить за каждую единицу газа. Чем выше цена газа, тем быстрее ваша транзакция будет обработана.
Всё
Максимальная сумма
- Комиссия не превысит
- Допустим ввод только цифр
+ Комиссия не превысит
+ Недопустимый Memo
Покрытие сетевой комиссии
Недостаточно средств для перевода, так как сумма комиссии и сумма перевода в совокупности больше имеющегося баланса
Недостаточно средств
@@ -486,6 +499,7 @@
Сумма отправки не может быть менее %s
Оставить %s
Уменьшить на %s
+ Уменьшить до %s
Обратите внимание, что при определенных параметрах комиссии возможны задержки по вашей транзакции
Возможны задержки по транзакции
Из-за ограничений %1$s в одну транзакцию может поместиться только %2$s UTXO. Это означает, что вы можете отправить только %3$s или меньше. Вам нужно уменьшить сумму.
@@ -505,6 +519,7 @@
Нажмите на любое поле, чтобы изменить его
Отправка %s
Вы отправляете **%1$s**, включая комиссию сети %2$s
+ Вы отправляете **%1$s** и %2$s
Отправка %s
Всего
%1$s и %2$s будет отправлено
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 99df15650b..50d7c7f7d5 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -93,6 +93,7 @@
Get addresses
Go to provider
Import
+ Later
Locked
Main network
Network fee
@@ -253,6 +254,14 @@
Tap to sign
Tap the card
You have updated biometrics, scan your card to enter
+ Your balance should be higher than the fee value to make a transfer
+ Not enough balance
+ You don\'t have enough Mana for this transaction. Please wait until the Mana is refilled. Your Mana balance is %1$s/%2$s
+ Not enough Mana
+ You can transfer only %s due to the Mana limit imposed by the Koinos network
+ Mana limit
+ The Koinos network requires Mana for network fees. Your have %1$s/%2$s Mana
+ Mana level
To begin tracking your crypto assets and transactions, add tokens
Manage tokens
To access all the networks you need to scan the card
@@ -297,6 +306,7 @@
Entered access code didn\'t match the initial access code
Please repeat the operation. The card will be reset to factory settings.
Activation error
+ Add tokens
You\'ve added one backup card. When backup process is finished you can\'t add more backup cards. If you have one more card, add it to backup. Do you like to continue the backup process?
The backup process is partly complete. You can\'t exit it now.
The passphrase is an advanced security feature that crypto wallets use. It adds an extra word or phrase of your own choosing to your already existing recovery phrase to unlock a brand-new set of addresses.
@@ -435,9 +445,11 @@
Reason: %1$s\nCode: %2$s
The transaction is not completed
Amount
- Base fee
- Represents the part of the transaction fee that goes to the miner
You can set your transaction fee by adjusting the value in the Satoshi per vByte field.
+ 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.
%1$s, %2$s
Address
Destination Tag
@@ -461,8 +473,8 @@
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.
Max
Maximum amount
- Max fee
- Numbers only for Destination Tag
+ Fee up to
+ Invalid Memo
Network fee coverage
Insufficient funds for the transfer, as the total of the fee and transfer amount exceeds the existing balance
Total exceeds balance
@@ -479,13 +491,12 @@
The amount to send must be at least %s
Leave %s
Reduce by %s
+ Reduce to %s
Kindly be aware that your transaction may experience delays under specific fee settings
Transaction delays are possible
Due to %1$s limitations only %2$s UTXOs can fit in a single transaction. This means you can only send %3$s or less. You need to reduce the amount.
Transaction limitation
Optional
- Priority fee
- Represents the minimum gasUsed multiplier required for a transaction to be included in a block. This is the part of the transaction fee that is burnt.
Please align your QR code with the square to scan it. Ensure you scan %s network address.
Recent
Recipient
@@ -500,6 +511,7 @@
Tap any field to change it
Send %s
You are sending **%1$s** including a network fee of %2$s
+ You are sending **%1$s** and %2$s
Sending %s
Total
%1$s and %2$s will be sent
diff --git a/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt b/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt
index e6e331c589..3c849d7c63 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/extensions/BlockchainIcons.kt
@@ -68,6 +68,7 @@ fun getActiveIconRes(blockchainId: String): Int {
"radiant" -> R.drawable.img_radiant_22
"base" -> R.drawable.img_base_22
"joystream" -> R.drawable.img_joystream_22
+ "koinos", "koinos/test" -> R.drawable.img_koinos_22
else -> R.drawable.ic_alert_24
}
}
@@ -137,6 +138,7 @@ fun getActiveIconResByNetworkId(networkId: String): Int {
"radiant" -> R.drawable.img_radiant_22
"base" -> R.drawable.img_base_22
"joystream" -> R.drawable.img_joystream_22
+ "koinos", "koinos/test" -> R.drawable.img_koinos_22
else -> R.drawable.ic_alert_24
}
}
@@ -272,6 +274,7 @@ fun getGreyedOutIconRes(blockchainId: String): Int {
"radiant" -> R.drawable.ic_radiant_22
"base", "base/test" -> R.drawable.ic_base_22
"joystream" -> R.drawable.ic_joystream_22
+ "koinos", "koinos/test" -> R.drawable.ic_koinos_22
else -> R.drawable.ic_alert_24
}
}
@@ -341,6 +344,7 @@ fun getGreyedOutIconResByNetworkId(networkId: String): Int {
"radiant" -> R.drawable.ic_radiant_22
"base", "base/test" -> R.drawable.ic_base_22
"joystream" -> R.drawable.ic_joystream_22
+ "koinos", "koinos/test" -> R.drawable.ic_koinos_22
else -> R.drawable.ic_alert_24
}
}
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt b/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt
index f995dee52e..0dbdded548 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/utils/BigDecimalFormatter.kt
@@ -13,6 +13,7 @@ object BigDecimalFormatter {
const val EMPTY_BALANCE_SIGN = "—"
const val CAN_BE_LOWER_SIGN = "<"
+ private val FORMAT_THRESHOLD = BigDecimal("0.01")
private const val TEMP_CURRENCY_CODE = "USD"
@@ -44,6 +45,39 @@ object BigDecimalFormatter {
}
}
+ fun formatCryptoAmountShorted(
+ cryptoAmount: BigDecimal?,
+ cryptoCurrency: String,
+ decimals: Int,
+ locale: Locale = Locale.getDefault(),
+ ): String {
+ if (cryptoAmount == null) return EMPTY_BALANCE_SIGN
+
+ val formatter = if (cryptoAmount.isMoreThanThreshold()) {
+ NumberFormat.getNumberInstance(locale).apply {
+ maximumFractionDigits = 2
+ minimumFractionDigits = 2
+ isGroupingUsed = true
+ roundingMode = RoundingMode.HALF_UP
+ }
+ } else {
+ NumberFormat.getNumberInstance(locale).apply {
+ maximumFractionDigits = decimals.coerceAtMost(maximumValue = 6)
+ minimumFractionDigits = 2
+ isGroupingUsed = true
+ roundingMode = RoundingMode.DOWN
+ }
+ }
+
+ return formatter.format(cryptoAmount).let {
+ if (cryptoCurrency.isEmpty()) {
+ it
+ } else {
+ it + "\u2009$cryptoCurrency"
+ }
+ }
+ }
+
fun formatCryptoAmountUncapped(
cryptoAmount: BigDecimal?,
cryptoCurrency: CryptoCurrency,
@@ -169,6 +203,8 @@ object BigDecimalFormatter {
fun formatWithSymbol(amount: String, symbol: String) = "$amount\u2009$symbol"
+ private fun BigDecimal.isMoreThanThreshold() = this > FORMAT_THRESHOLD
+
private fun getCurrency(code: String): Currency {
return runCatching { Currency.getInstance(code) }
.getOrElse { e ->
diff --git a/core/ui/src/main/res/drawable/ic_koinos_22.xml b/core/ui/src/main/res/drawable/ic_koinos_22.xml
new file mode 100644
index 0000000000..3d3ad5087a
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_koinos_22.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/core/ui/src/main/res/drawable/img_koinos_22.xml b/core/ui/src/main/res/drawable/img_koinos_22.xml
new file mode 100644
index 0000000000..2364704dc9
--- /dev/null
+++ b/core/ui/src/main/res/drawable/img_koinos_22.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt
index f15c13019f..1b8f9800e3 100644
--- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt
+++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt
@@ -388,6 +388,7 @@ internal class DefaultCurrenciesRepository(
balance = balance,
)
}
+ is FeePaidSdkCurrency.FeeResource -> FeePaidCurrency.FeeResource(currency = feePaidCurrency.currency)
}
}
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 8f21f5d495..ea56a8adbf 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
@@ -1,9 +1,11 @@
package com.tangem.data.tokens.repository
import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider
+import com.tangem.blockchain.common.FeeResourceAmountProvider
import com.tangem.blockchain.common.ReserveAmountProvider
import com.tangem.blockchain.common.UtxoAmountLimitProvider
import com.tangem.data.tokens.converters.UtxoConverter
+import com.tangem.domain.tokens.model.CurrencyAmount
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.tokens.model.blockchains.UtxoAmountLimit
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
@@ -41,6 +43,40 @@ internal class DefaultCurrencyChecksRepository(
return if (manager is ReserveAmountProvider) manager.getReserveAmount() else null
}
+ override suspend fun getFeeResourceAmount(userWalletId: UserWalletId, network: Network): CurrencyAmount? {
+ val manager = walletManagersFacade.getOrCreateWalletManager(
+ userWalletId = userWalletId,
+ network = network,
+ )
+
+ return if (manager is FeeResourceAmountProvider) {
+ val feeResource = manager.getFeeResource()
+ CurrencyAmount(
+ value = feeResource.value,
+ maxValue = feeResource.maxValue,
+ )
+ } else {
+ null
+ }
+ }
+
+ override suspend fun checkIfFeeResourceEnough(
+ amount: BigDecimal,
+ userWalletId: UserWalletId,
+ network: Network,
+ ): Boolean {
+ val manager = walletManagersFacade.getOrCreateWalletManager(
+ userWalletId = userWalletId,
+ network = network,
+ )
+
+ return if (manager is FeeResourceAmountProvider) {
+ manager.isFeeEnough(amount)
+ } else {
+ false
+ }
+ }
+
override suspend fun checkIfAccountFunded(userWalletId: UserWalletId, network: Network, address: String): Boolean {
val manager = walletManagersFacade.getOrCreateWalletManager(
userWalletId = userWalletId,
diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkOperations.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkOperations.kt
index 38f09a5623..251a2b420f 100644
--- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkOperations.kt
+++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkOperations.kt
@@ -1,6 +1,7 @@
package com.tangem.data.tokens.utils
import com.tangem.blockchain.common.Blockchain
+import com.tangem.blockchain.common.FeePaidCurrency
import com.tangem.blockchainsdk.utils.toNetworkId
import com.tangem.domain.common.DerivationStyleProvider
import com.tangem.domain.tokens.model.Network
@@ -28,6 +29,7 @@ internal fun getNetwork(
derivationPath = getNetworkDerivationPath(blockchain, extraDerivationPath, derivationStyleProvider),
currencySymbol = blockchain.currency,
standardType = getNetworkStandardType(blockchain),
+ hasFiatFeeRate = blockchain.feePaidCurrency() !is FeePaidCurrency.FeeResource,
)
}
diff --git a/domain/demo/src/main/java/com/tangem/domain/demo/DemoConfig.kt b/domain/demo/src/main/java/com/tangem/domain/demo/DemoConfig.kt
index 32faeb03aa..a7b9ab2d90 100644
--- a/domain/demo/src/main/java/com/tangem/domain/demo/DemoConfig.kt
+++ b/domain/demo/src/main/java/com/tangem/domain/demo/DemoConfig.kt
@@ -1,6 +1,5 @@
package com.tangem.domain.demo
-import com.tangem.blockchain.BuildConfig
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Blockchain
import java.math.BigDecimal
diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt
index 381b9cadd3..cd756efd3c 100644
--- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt
+++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt
@@ -66,6 +66,7 @@ internal class TransactionDataToTxHistoryItemConverter(
value
}
}
+ is FeePaidCurrency.FeeResource -> value
}
}
diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt
index b6620652d5..84b194166b 100644
--- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt
+++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt
@@ -114,7 +114,9 @@ internal class UpdateWalletManagerResultFactory {
is AmountType.Coin -> CryptoCurrencyAmount.Coin(
value = getCurrencyAmountValue(amount) ?: return null,
)
- is AmountType.Reserve -> null
+ is AmountType.FeeResource,
+ AmountType.Reserve,
+ -> null
}
}
@@ -135,7 +137,9 @@ internal class UpdateWalletManagerResultFactory {
txHistoryItem = txHistoryItem,
)
}
- is AmountType.Reserve -> null
+ is AmountType.FeeResource,
+ AmountType.Reserve,
+ -> null
}
}
diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/FeePaidCurrency.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/FeePaidCurrency.kt
index dba9b23181..e61ffb4e2f 100644
--- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/FeePaidCurrency.kt
+++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/FeePaidCurrency.kt
@@ -5,6 +5,7 @@ import java.math.BigDecimal
sealed class FeePaidCurrency {
data object Coin : FeePaidCurrency()
data object SameCurrency : FeePaidCurrency()
+ data class FeeResource(val currency: String) : FeePaidCurrency()
data class Token(
val tokenId: CryptoCurrency.ID,
val name: String,
diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt
index 17274cfbe9..5dcdb275ef 100644
--- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt
+++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt
@@ -16,6 +16,9 @@ import kotlinx.parcelize.Parcelize
* @property derivationPath The path used to derive keys for this network.
* @property isTestnet Indicates whether the network is a test network or a main network.
* @property standardType The type of blockchain standard the network adheres to.
+ * @property hasFiatFeeRate Indicates whether there is a fee in the network
+ * that cannot be represented in a fiat currency.
+ * (For those blockchains that have FeeResource instead of a standard type of fee)
*/
@Parcelize
data class Network(
@@ -26,6 +29,7 @@ data class Network(
val derivationPath: DerivationPath,
val isTestnet: Boolean,
val standardType: StandardType,
+ val hasFiatFeeRate: Boolean,
) : Parcelable {
init {
diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt
index 86b0059faf..2fa13a5018 100644
--- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt
+++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/warnings/CryptoCurrencyWarning.kt
@@ -47,4 +47,12 @@ sealed class CryptoCurrencyWarning {
) : CryptoCurrencyWarning()
data object BeaconChainShutdown : CryptoCurrencyWarning()
+
+ /**
+ * Shows a warning about an available fee resource for a transaction in several blockchains (ex. Koinos)
+ */
+ data class FeeResourceInfo(
+ val amount: BigDecimal,
+ val maxAmount: BigDecimal?,
+ ) : CryptoCurrencyWarning()
}
\ No newline at end of file
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 ba46c3aca0..eb7296acea 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
@@ -1,10 +1,7 @@
package com.tangem.domain.tokens
import com.tangem.domain.settings.ShouldShowSwapPromoTokenUseCase
-import com.tangem.domain.tokens.model.CryptoCurrency
-import com.tangem.domain.tokens.model.CryptoCurrencyStatus
-import com.tangem.domain.tokens.model.FeePaidCurrency
-import com.tangem.domain.tokens.model.Network
+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.operations.CurrenciesStatusesOperations
@@ -59,22 +56,19 @@ class GetCurrencyWarningsUseCase(
),
flowOf(walletManagersFacade.getRentInfo(userWalletId, currency.network)),
flowOf(currencyChecksRepository.getExistentialDeposit(userWalletId, currency.network)),
+ flowOf(currencyChecksRepository.getFeeResourceAmount(userWalletId, currency.network)),
getSwapPromoNotificationWarning(
operations = operations,
userWalletId = userWalletId,
currencyStatus = currencyStatus,
).conflate(),
- ) { coinRelatedWarnings, maybeRentWarning, maybeEdWarning, maybeSwapPromo ->
+ ) { coinRelatedWarnings, maybeRentWarning, maybeEdWarning, maybeFeeResource, maybeSwapPromo ->
setOfNotNull(
maybeSwapPromo,
maybeRentWarning,
- maybeEdWarning?.let {
- CryptoCurrencyWarning.ExistentialDeposit(
- currencyName = currency.name,
- edStringValueWithSymbol = "${it.toPlainString()} ${currency.symbol}",
- )
- },
- *coinRelatedWarnings.toTypedArray(),
+ maybeEdWarning?.let { getExistentialDepositWarning(currency, it) },
+ maybeFeeResource?.let { getFeeResourceWarning(it) },
+ * coinRelatedWarnings.toTypedArray(),
getNetworkUnavailableWarning(currencyStatus),
getNetworkNoAccountWarning(currencyStatus),
getBeaconChainShutdownWarning(currency.network.id),
@@ -270,6 +264,23 @@ class GetCurrencyWarningsUseCase(
return if (BlockchainUtils.isBeaconChain(networkId.value)) CryptoCurrencyWarning.BeaconChainShutdown else null
}
+ private fun getExistentialDepositWarning(
+ currency: CryptoCurrency,
+ amount: BigDecimal,
+ ): CryptoCurrencyWarning.ExistentialDeposit {
+ return CryptoCurrencyWarning.ExistentialDeposit(
+ currencyName = currency.name,
+ edStringValueWithSymbol = "${amount.toPlainString()} ${currency.symbol}",
+ )
+ }
+
+ private fun getFeeResourceWarning(feeResource: CurrencyAmount): CryptoCurrencyWarning.FeeResourceInfo {
+ return CryptoCurrencyWarning.FeeResourceInfo(
+ amount = feeResource.value,
+ maxAmount = feeResource.maxValue,
+ )
+ }
+
private suspend fun getAssetRequirementsWarning(
userWalletId: UserWalletId,
currency: CryptoCurrency,
diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetFeePaidCryptoCurrencyStatusSyncUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetFeePaidCryptoCurrencyStatusSyncUseCase.kt
index cd41c82702..d38fa6a951 100644
--- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetFeePaidCryptoCurrencyStatusSyncUseCase.kt
+++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetFeePaidCryptoCurrencyStatusSyncUseCase.kt
@@ -38,7 +38,9 @@ class GetFeePaidCryptoCurrencyStatusSyncUseCase(
operations
.getNetworkCoinSync(cryptoCurrency.network.id, cryptoCurrency.network.derivationPath)
.getOrNull()
- FeePaidCurrency.SameCurrency -> cryptoCurrencyStatus
+ FeePaidCurrency.SameCurrency,
+ is FeePaidCurrency.FeeResource,
+ -> cryptoCurrencyStatus
is FeePaidCurrency.Token -> operations.getCurrencyStatusSync(feePaidCurrency.tokenId).getOrNull()
}
}
diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/IsAmountSubtractAvailableUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/IsAmountSubtractAvailableUseCase.kt
index d003a95067..59510b29f3 100644
--- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/IsAmountSubtractAvailableUseCase.kt
+++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/IsAmountSubtractAvailableUseCase.kt
@@ -23,6 +23,7 @@ class IsAmountSubtractAvailableUseCase(
is FeePaidCurrency.Coin -> currency is CryptoCurrency.Coin
is FeePaidCurrency.SameCurrency -> true
is FeePaidCurrency.Token -> currency.id == feeCurrency.tokenId
+ is FeePaidCurrency.FeeResource -> false
}
}
}
diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/CurrencyAmount.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/CurrencyAmount.kt
new file mode 100644
index 0000000000..e916aeee2e
--- /dev/null
+++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/CurrencyAmount.kt
@@ -0,0 +1,12 @@
+package com.tangem.domain.tokens.model
+
+import java.math.BigDecimal
+
+/**
+ * The amount of currency with the possible [maxValue] field
+ * Useful for some [com.tangem.blockchain.common.AmountType] that have maximum value
+ */
+data class CurrencyAmount(
+ val value: BigDecimal,
+ val maxValue: BigDecimal?,
+)
\ No newline at end of file
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 914007040a..0b5745a983 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.CurrencyAmount
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.tokens.model.blockchains.UtxoAmountLimit
import com.tangem.domain.wallets.models.UserWalletId
@@ -19,6 +20,12 @@ interface CurrencyChecksRepository {
/** Returns reserve amount which is required to create an account */
suspend fun getReserveAmount(userWalletId: UserWalletId, network: Network): BigDecimal?
+ /** Returns a fee resource amount available and max for paying fees in several blockchains */
+ suspend fun getFeeResourceAmount(userWalletId: UserWalletId, network: Network): CurrencyAmount?
+
+ /** Is fee resource enough for a transaction amount */
+ suspend fun checkIfFeeResourceEnough(amount: BigDecimal, userWalletId: UserWalletId, network: Network): Boolean
+
/** Returns true if account with [address] was reserved with minimum amount */
suspend fun checkIfAccountFunded(userWalletId: UserWalletId, network: Network, address: String): Boolean
diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt
index 0f03851309..091154dda9 100644
--- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt
+++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt
@@ -21,6 +21,7 @@ internal object MockNetworks {
backendId = "network1",
currencySymbol = "ETH",
derivationPath = Network.DerivationPath.None,
+ hasFiatFeeRate = true,
)
val network2 = Network(
@@ -31,6 +32,7 @@ internal object MockNetworks {
backendId = "network1",
currencySymbol = "ETH",
derivationPath = Network.DerivationPath.None,
+ hasFiatFeeRate = true,
)
val network3 = Network(
@@ -41,6 +43,7 @@ internal object MockNetworks {
backendId = "network1",
currencySymbol = "ETH",
derivationPath = Network.DerivationPath.None,
+ hasFiatFeeRate = true,
)
val networkStatus1 = NetworkStatus(
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotification.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotification.kt
index f2bf0e4d67..65318c9c39 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotification.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendNotification.kt
@@ -1,10 +1,13 @@
package com.tangem.features.send.impl.presentation.state
+import com.tangem.blockchain.common.Blockchain
import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
+import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.features.send.impl.R
+import java.math.BigDecimal
internal sealed class SendNotification(val config: NotificationConfig) {
@@ -186,4 +189,46 @@ internal sealed class SendNotification(val config: NotificationConfig) {
),
)
}
+
+ sealed interface Koinos {
+ data class InsufficientRecoverableMana(
+ val mana: BigDecimal,
+ val maxMana: BigDecimal,
+ ) : Error(
+ title = resourceReference(R.string.koinos_insufficient_mana_to_send_koin_title),
+ subtitle = resourceReference(
+ R.string.koinos_insufficient_mana_to_send_koin_description,
+ formatArgs = wrappedList(
+ BigDecimalFormatter.formatCryptoAmountShorted(mana, "", Blockchain.Koinos.decimals()),
+ BigDecimalFormatter.formatCryptoAmountShorted(maxMana, "", Blockchain.Koinos.decimals()),
+ ),
+ ),
+ )
+
+ data object InsufficientBalance : Error(
+ title = resourceReference(R.string.koinos_insufficient_balance_to_send_koin_title),
+ subtitle = resourceReference(R.string.koinos_insufficient_balance_to_send_koin_description),
+ )
+
+ data class ManaExceedsBalance(
+ val availableKoinForTransfer: BigDecimal,
+ val onReduceClick: () -> Unit,
+ ) : Error(
+ title = resourceReference(R.string.koinos_mana_exceeds_koin_balance_title),
+ subtitle = resourceReference(
+ R.string.koinos_mana_exceeds_koin_balance_description,
+ formatArgs = wrappedList(
+ BigDecimalFormatter.formatCryptoAmount(
+ availableKoinForTransfer,
+ Blockchain.Koinos.currency,
+ Blockchain.Koinos.decimals(),
+ ),
+ ),
+ ),
+ buttonState = NotificationConfig.ButtonsState.PrimaryButtonConfig(
+ text = resourceReference(R.string.send_notification_reduce_to, wrappedList(availableKoinForTransfer)),
+ onClick = onReduceClick,
+ ),
+ )
+ }
}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt
index 3d038ef6a6..34f1f0caf9 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendStateFactory.kt
@@ -60,6 +60,7 @@ internal class SendStateFactory(
SendFeeStateConverter(
appCurrencyProvider = appCurrencyProvider,
feeCryptoCurrencyStatusProvider = feeCryptoCurrencyStatusProvider,
+ cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
)
}
private val confirmStateConverter by lazy(LazyThreadSafetyMode.NONE) {
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt
index c7aa7ddff0..4c16ece506 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/SendUiState.kt
@@ -125,6 +125,7 @@ internal sealed class SendStates {
val feeSelectorState: FeeSelectorState,
val fee: Fee?,
val rate: BigDecimal?,
+ val isFeeConvertibleToFiat: Boolean,
val appCurrency: AppCurrency,
val isFeeApproximate: Boolean,
val isCustomSelected: Boolean,
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt
index 81edeef29c..16c1315e2d 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt
@@ -101,7 +101,11 @@ internal class SendNotificationFactory(
addTooLowNotification(feeState)
// blockchain specific
- addCardanoNotifications(sendingAmount, feeState.fee, state)
+ addValidateTransactionNotifications(
+ sendingAmount = sendingAmount,
+ fee = feeState.fee,
+ state = state,
+ )
}.toImmutableList()
}
@@ -420,13 +424,12 @@ internal class SendNotificationFactory(
return Blockchain.fromNetworkId(this.currency.network.backendId) == Blockchain.Arbitrum
}
- private suspend fun MutableList.addCardanoNotifications(
+ private suspend fun MutableList.addValidateTransactionNotifications(
sendingAmount: BigDecimal,
fee: Fee?,
state: SendUiState,
) {
val sendingCurrency = cryptoCurrencyStatusProvider().currency
- if (!BlockchainUtils.isCardano(sendingCurrency.network.id.value)) return
validateTransactionUseCase(
amount = sendingAmount.convertToAmount(sendingCurrency),
@@ -437,10 +440,14 @@ internal class SendNotificationFactory(
network = sendingCurrency.network,
).fold(
ifLeft = {
- addCardanoTransactionValidationError(
- error = it as? BlockchainSdkError.Cardano ?: return@fold,
- sendingCurrency = sendingCurrency,
- )
+ when (it) {
+ is BlockchainSdkError.Cardano -> addCardanoTransactionValidationError(
+ error = it,
+ sendingCurrency = sendingCurrency,
+ )
+ is BlockchainSdkError.Koinos -> addKoinosTransactionValidationError(error = it)
+ else -> return
+ }
},
ifRight = {
(fee as? Fee.CardanoToken)?.let {
@@ -488,6 +495,36 @@ internal class SendNotificationFactory(
}
}
+ private fun MutableList.addKoinosTransactionValidationError(error: BlockchainSdkError.Koinos) {
+ when (error) {
+ is BlockchainSdkError.Koinos.InsufficientBalance -> {
+ add(SendNotification.Koinos.InsufficientBalance)
+ }
+ is BlockchainSdkError.Koinos.InsufficientMana -> {
+ add(
+ SendNotification.Koinos.InsufficientRecoverableMana(
+ mana = error.manaBalance ?: BigDecimal.ZERO,
+ maxMana = error.maxMana ?: BigDecimal.ZERO,
+ ),
+ )
+ }
+ is BlockchainSdkError.Koinos.ManaFeeExceedsBalance -> {
+ add(
+ SendNotification.Koinos.ManaExceedsBalance(
+ availableKoinForTransfer = error.availableKoinForTransfer,
+ onReduceClick = {
+ clickIntents.onAmountReduceClick(
+ reduceAmountTo = error.availableKoinForTransfer,
+ clazz = SendNotification.Koinos.InsufficientRecoverableMana::class.java,
+ )
+ },
+ ),
+ )
+ }
+ else -> {}
+ }
+ }
+
private suspend fun MutableList.addDustWarningNotification(
feeValue: BigDecimal,
sendingAmount: BigDecimal,
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeStateConverter.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeStateConverter.kt
index f0cdd28425..d24ed03da0 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeStateConverter.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/fee/SendFeeStateConverter.kt
@@ -10,6 +10,7 @@ import kotlinx.collections.immutable.persistentListOf
internal class SendFeeStateConverter(
private val appCurrencyProvider: Provider,
private val feeCryptoCurrencyStatusProvider: Provider,
+ private val cryptoCurrencyStatusProvider: Provider,
) : Converter {
override fun convert(value: Unit): SendStates.FeeState {
@@ -21,6 +22,7 @@ internal class SendFeeStateConverter(
appCurrency = appCurrencyProvider(),
isFeeApproximate = false,
isCustomSelected = false,
+ isFeeConvertibleToFiat = cryptoCurrencyStatusProvider().currency.network.hasFiatFeeRate,
)
}
}
\ No newline at end of file
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/FeeStatePreviewData.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/FeeStatePreviewData.kt
index da305b36ea..c024b39ee0 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/FeeStatePreviewData.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/previewdata/FeeStatePreviewData.kt
@@ -82,6 +82,7 @@ internal object FeeStatePreviewData {
isFeeApproximate = false,
notifications = persistentListOf(),
isCustomSelected = false,
+ isFeeConvertibleToFiat = true,
)
val feeChoosableState = feeState.copy(
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt
index 672f385fc0..f5247e516a 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/SendNavigationButtons.kt
@@ -29,16 +29,15 @@ import com.tangem.core.ui.components.buttons.common.TangemButton
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
import com.tangem.core.ui.components.keyboardAsState
-import com.tangem.core.ui.extensions.resolveAnnotatedReference
-import com.tangem.core.ui.extensions.resourceReference
-import com.tangem.core.ui.extensions.shareText
-import com.tangem.core.ui.extensions.wrappedList
+import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.BigDecimalFormatter
+import com.tangem.domain.tokens.model.Amount
import com.tangem.features.send.impl.presentation.state.SendUiCurrentScreen
import com.tangem.features.send.impl.presentation.state.SendUiState
import com.tangem.features.send.impl.presentation.state.SendUiStateType
import com.tangem.features.send.impl.presentation.utils.getFiatString
+import com.tangem.features.send.impl.presentation.utils.getCryptoReference
@Composable
internal fun SendNavigationButtons(
@@ -175,7 +174,11 @@ private fun SendingText(
val sendingFiat = if (uiState.isSubtracted) {
fiatAmount?.value
} else {
- feeFiat?.let { fiatAmount?.value?.plus(it) }
+ if (feeState?.isFeeConvertibleToFiat == true) {
+ feeFiat?.let { fiatAmount?.value?.plus(it) }
+ } else {
+ fiatAmount?.value
+ }
}
if (feeFiat != null && sendingFiat != null) {
@@ -184,14 +187,23 @@ private fun SendingText(
fiatCurrencySymbol = feeState.appCurrency.symbol,
fiatCurrencyCode = feeState.appCurrency.code,
)
- val feeValue = getFiatString(
- value = feeState.fee?.amount?.value,
- rate = feeState.rate,
- appCurrency = feeState.appCurrency,
- )
+ val feeValue = if (feeState.isFeeConvertibleToFiat) {
+ getFiatString(
+ value = feeState.fee?.amount?.value,
+ rate = feeState.rate,
+ appCurrency = feeState.appCurrency,
+ )
+ } else {
+ getCryptoReference(feeState.fee?.amount, feeState.isFeeApproximate)?.resolveReference().orEmpty()
+ }
+
val textResource = remember(uiState) {
resourceReference(
- id = R.string.send_summary_transaction_description,
+ id = if (feeState.isFeeConvertibleToFiat) {
+ R.string.send_summary_transaction_description
+ } else {
+ R.string.send_summary_transaction_description_no_fiat_fee
+ },
formatArgs = wrappedList(sendingValue, feeValue),
)
}
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 d29fea2394..ed1ad443a4 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
@@ -54,7 +54,11 @@ internal fun SendSpeedSelectorItem(
onSelect = onSelect,
modifier = modifier,
preDot = getCryptoReference(amount, state.isFeeApproximate),
- postDot = getFiatReference(amount?.value, state.rate, state.appCurrency),
+ postDot = if (state.isFeeConvertibleToFiat) {
+ getFiatReference(amount?.value, state.rate, state.appCurrency)
+ } else {
+ null
+ },
ellipsizeOffset = amount?.currencySymbol?.length,
isSelected = content?.selectedFee == feeType,
showDivider = showDivider,
diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt
index 55d5985fa6..f2dcd33987 100644
--- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt
+++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/ui/send/FeeBlock.kt
@@ -62,7 +62,11 @@ internal fun FeeBlock(feeState: SendStates.FeeState, isClickDisabled: Boolean, o
titleRes = title,
iconRes = icon,
preDot = getCryptoReference(feeAmount, feeState.isFeeApproximate),
- postDot = getFiatReference(feeAmount?.value, feeState.rate, feeState.appCurrency),
+ postDot = if (feeState.isFeeConvertibleToFiat) {
+ getFiatReference(feeAmount?.value, feeState.rate, feeState.appCurrency)
+ } else {
+ null
+ },
ellipsizeOffset = feeAmount?.currencySymbol?.length,
isSelected = true,
showDivider = false,
diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt
index 8bba53e589..ab1e044b30 100644
--- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt
+++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt
@@ -390,7 +390,7 @@ internal class SwapInteractorImpl @Inject constructor(
manageExistentialDepositWarning(warnings, userWalletId, amount, fromToken)
manageDustWarning(warnings, feeState, userWalletId, fromTokenStatus, amount)
manageReduceAmountWarning(warnings, fromTokenStatus, amount)
- manageCardanoTransactionValidationWarnings(
+ manageTransactionValidationWarnings(
warnings = warnings,
fromToken = fromToken,
amount = amount,
@@ -468,7 +468,7 @@ internal class SwapInteractorImpl @Inject constructor(
}
}
- private suspend fun manageCardanoTransactionValidationWarnings(
+ private suspend fun manageTransactionValidationWarnings(
warnings: MutableList,
fromToken: CryptoCurrency,
amount: SwapAmount,
@@ -1612,6 +1612,7 @@ internal class SwapInteractorImpl @Inject constructor(
return amountToSwap.replace(",", ".").toBigDecimalOrNull()
}
+ @Suppress("LongMethod", "CyclomaticComplexMethod")
private suspend fun getFeeState(
fee: BigDecimal?,
spendAmount: SwapAmount,
@@ -1682,6 +1683,20 @@ internal class SwapInteractorImpl @Inject constructor(
)
}
}
+ is FeePaidCurrency.FeeResource -> {
+ val network = repository.getNativeTokenForNetwork(networkId).network
+ val isFeeResourceEnough = currencyChecksRepository.checkIfFeeResourceEnough(
+ amount = spendAmount.value,
+ userWalletId = userWalletId,
+ network = network,
+ )
+
+ if (isFeeResourceEnough) {
+ SwapFeeState.Enough
+ } else {
+ SwapFeeState.NotEnough()
+ }
+ }
}
}
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 998dbf0aff..a69442cd51 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
@@ -43,6 +43,7 @@ internal class TokenDetailsNotificationsAnalyticsSender(
is TokenDetailsNotification.SwapPromo,
is TokenDetailsNotification.NetworkShutdown,
is TokenDetailsNotification.HederaAssociateWarning,
+ is TokenDetailsNotification.KoinosMana,
-> null
}
}
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 c6314d4e3f..950f24a218 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
@@ -2,10 +2,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.componen
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.notifications.NotificationConfig
-import com.tangem.core.ui.extensions.TextReference
-import com.tangem.core.ui.extensions.networkIconResId
-import com.tangem.core.ui.extensions.resourceReference
-import com.tangem.core.ui.extensions.wrappedList
+import com.tangem.core.ui.extensions.*
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.features.tokendetails.impl.R
@@ -197,4 +194,15 @@ internal sealed class TokenDetailsNotification(val config: NotificationConfig) {
onClick = onAssociateClick,
),
)
+
+ data class KoinosMana(
+ val manaBalanceAmount: String,
+ val maxManaBalanceAmount: String,
+ ) : Informational(
+ title = resourceReference(id = R.string.koinos_mana_level_title),
+ subtitle = resourceReference(
+ id = R.string.koinos_mana_level_description,
+ formatArgs = wrappedList(manaBalanceAmount, maxManaBalanceAmount),
+ ),
+ )
}
\ No newline at end of file
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 33c5b85d67..fd828b47d0 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
@@ -16,6 +16,8 @@ import com.tangem.utils.converter.Converter
import com.tangem.utils.extensions.removeBy
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
+import timber.log.Timber
+import java.math.BigDecimal
internal class TokenDetailsNotificationConverter(
private val clickIntents: TokenDetailsClickIntents,
@@ -37,7 +39,7 @@ internal class TokenDetailsNotificationConverter(
return newNotifications.toImmutableList()
}
- @Suppress("LongMethod")
+ @Suppress("LongMethod", "CyclomaticComplexMethod")
private fun mapToNotification(warning: CryptoCurrencyWarning): TokenDetailsNotification {
return when (warning) {
is CryptoCurrencyWarning.BalanceNotEnoughForFee -> NetworkFeeWithBuyButton(
@@ -111,9 +113,26 @@ internal class TokenDetailsNotificationConverter(
feeCurrencySymbol = warning.feeCurrencySymbol,
onAssociateClick = clickIntents::onAssociateClick,
)
+ is CryptoCurrencyWarning.FeeResourceInfo -> KoinosMana(
+ manaBalanceAmount = formatMana(warning.amount),
+ maxManaBalanceAmount = warning.maxAmount?.let {
+ formatMana(it)
+ } ?: run {
+ Timber.e("FeeResource maxAmount cannot be null in Koinos. Check KoinosWalletManager")
+ ""
+ },
+ )
}
}
+ private fun formatMana(amount: BigDecimal): String {
+ return BigDecimalFormatter.formatCryptoAmountShorted(
+ cryptoAmount = amount,
+ cryptoCurrency = "",
+ decimals = Blockchain.Koinos.decimals(),
+ )
+ }
+
// workaround for networks that users have misunderstanding
private fun CryptoCurrency.shouldMergeFeeNetworkName(): Boolean {
return Blockchain.fromNetworkId(this.network.backendId) == Blockchain.Arbitrum
diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml
index ec97c63128..53962859e2 100644
--- a/gradle/dependencies.toml
+++ b/gradle/dependencies.toml
@@ -87,7 +87,7 @@ markdown = "0.7.2"
# endregion Other libraries
# region Tangem
-tangemBlockchainSdk = "develop-637"
+tangemBlockchainSdk = "develop-651"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-356"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^