Updated on 2026-08-14
This commit is contained in:
parent
8889ad4c31
commit
d2518865d1
39 changed files with 414 additions and 57 deletions
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
<string name="common_generate_addresses">Получить адреса</string>
|
||||
<string name="common_go_to_provider">К провайдеру</string>
|
||||
<string name="common_import">Импортировать</string>
|
||||
<string name="common_later">Позже</string>
|
||||
<string name="common_locked">Заблокирован</string>
|
||||
<string name="common_main_network">Основная сеть</string>
|
||||
<string name="common_network_fee_title">Сетевая комиссия</string>
|
||||
|
|
@ -254,6 +255,14 @@
|
|||
<string name="initial_message_sign_header">Приложите, чтобы подписать</string>
|
||||
<string name="initial_message_tap_header">Приложите карту</string>
|
||||
<string name="key_invalidated_warning_description">Вы обновили данные биометрии, отсканируйте свою карту для входа</string>
|
||||
<string name="koinos_insufficient_balance_to_send_koin_description">Ваш баланс должен быть выше суммы комиссии для осуществления перевода</string>
|
||||
<string name="koinos_insufficient_balance_to_send_koin_title">Недостаточно средств</string>
|
||||
<string name="koinos_insufficient_mana_to_send_koin_description">У вас недостаточно Маны для этой транзакции. Пожалуйста, подождите, пока Мана восполнится. Ваш баланс маны равен %1$s/%2$s</string>
|
||||
<string name="koinos_insufficient_mana_to_send_koin_title">Недостаточно Маны</string>
|
||||
<string name="koinos_mana_exceeds_koin_balance_description">Вы можете перевести только %s из-за ограничения Mana, установленного сетью Koinos</string>
|
||||
<string name="koinos_mana_exceeds_koin_balance_title">Лимит маны</string>
|
||||
<string name="koinos_mana_level_description">Сеть Koinos использует Ману для оплаты комиссии сети. У вас есть %1$s/%2$s Mana</string>
|
||||
<string name="koinos_mana_level_title">Уровень маны</string>
|
||||
<string name="main_empty_tokens_list_message">Чтобы начать отслеживать свои криптоактивы и транзакции, добавьте токены</string>
|
||||
<string name="main_manage_tokens">Управление токенами</string>
|
||||
<string name="main_scan_card_warning_view_subtitle">Чтобы получить доступ ко всем сетям, вам необходимо отсканировать карту</string>
|
||||
|
|
@ -298,6 +307,7 @@
|
|||
<string name="onboarding_access_codes_doesnt_match">Введенные коды доступа не совпадают</string>
|
||||
<string name="onboarding_activation_error_message">Необходимо повторить операцию, при этом карта будет сброшена к заводским настройкам</string>
|
||||
<string name="onboarding_activation_error_title">Ошибка активации</string>
|
||||
<string name="onboarding_add_tokens">Добавление токенов</string>
|
||||
<string name="onboarding_alert_message_not_max_backup_cards_added">Вы добавили одну резервную карту. После того, как процесс будет завершен, Вы больше не сможете добавить карт. Если у Вас есть еще одна карта, добавьте ее в резервную копию. Хотите продолжить?</string>
|
||||
<string name="onboarding_backup_exit_warning">Процесс резервного копирования почти завершен. Вы не можете выйти из него сейчас.</string>
|
||||
<string name="onboarding_bottom_sheet_passphrase_description">Парольная фраза — это расширенная функция безопасности, которую используют криптокошельки. Она добавляет дополнительное слово или фразу по вашему выбору к уже существующей seed - фразе, чтобы разблокировать совершенно новый набор адресов.</string>
|
||||
|
|
@ -445,6 +455,9 @@
|
|||
<string name="send_alert_transaction_failed_title">Транзакция не выполнена</string>
|
||||
<string name="send_amount_label">Сумма</string>
|
||||
<string name="send_bitcoin_custom_fee_footer">Вы можете установить комиссию за транзакцию, изменив значение в поле Satoshi per vByte.</string>
|
||||
<string name="send_custom_evm_max_fee_footer">Это стоимость, которую вы готовы заплатить за каждую единицу газа. Чем выше цена газа, тем быстрее ваша транзакция будет обработана. (Приоритетная комиссия включена)</string>
|
||||
<string name="send_custom_evm_priority_fee">Приоритетная комиссия</string>
|
||||
<string name="send_custom_evm_priority_fee_footer">Комиссия, которую пользователь может заплатить майнерам или валидаторам за ускорение включения его транзакции в блок.</string>
|
||||
<string name="send_date_format">%1$s, %2$s</string>
|
||||
<string name="send_destination_hint_address">Адрес</string>
|
||||
<string name="send_destination_tag_field">Код назначения</string>
|
||||
|
|
@ -468,8 +481,8 @@
|
|||
<string name="send_gas_price_footer">Это стоимость, которую вы готовы заплатить за каждую единицу газа. Чем выше цена газа, тем быстрее ваша транзакция будет обработана.</string>
|
||||
<string name="send_max_amount">Всё</string>
|
||||
<string name="send_max_amount_label">Максимальная сумма</string>
|
||||
<string name="send_max_fee">Комиссия не превысит </string>
|
||||
<string name="send_memo_destination_tag_error">Допустим ввод только цифр</string>
|
||||
<string name="send_max_fee">Комиссия не превысит</string>
|
||||
<string name="send_memo_destination_tag_error">Недопустимый Memo</string>
|
||||
<string name="send_network_fee_warning_title">Покрытие сетевой комиссии</string>
|
||||
<string name="send_notification_exceed_balance_text">Недостаточно средств для перевода, так как сумма комиссии и сумма перевода в совокупности больше имеющегося баланса</string>
|
||||
<string name="send_notification_exceed_balance_title">Недостаточно средств</string>
|
||||
|
|
@ -486,6 +499,7 @@
|
|||
<string name="send_notification_invalid_reserve_amount_title">Сумма отправки не может быть менее %s</string>
|
||||
<string name="send_notification_leave_button">Оставить %s</string>
|
||||
<string name="send_notification_reduce_by">Уменьшить на %s</string>
|
||||
<string name="send_notification_reduce_to">Уменьшить до %s</string>
|
||||
<string name="send_notification_transaction_delay_text">Обратите внимание, что при определенных параметрах комиссии возможны задержки по вашей транзакции</string>
|
||||
<string name="send_notification_transaction_delay_title">Возможны задержки по транзакции</string>
|
||||
<string name="send_notification_transaction_limit_text">Из-за ограничений %1$s в одну транзакцию может поместиться только %2$s UTXO. Это означает, что вы можете отправить только %3$s или меньше. Вам нужно уменьшить сумму.</string>
|
||||
|
|
@ -505,6 +519,7 @@
|
|||
<string name="send_summary_tap_hint">Нажмите на любое поле, чтобы изменить его</string>
|
||||
<string name="send_summary_title">Отправка %s</string>
|
||||
<string name="send_summary_transaction_description">Вы отправляете **%1$s**, включая комиссию сети %2$s</string>
|
||||
<string name="send_summary_transaction_description_no_fiat_fee">Вы отправляете **%1$s** и %2$s</string>
|
||||
<string name="send_title_currency_format">Отправка %s</string>
|
||||
<string name="send_total_label">Всего</string>
|
||||
<string name="send_total_subtitle_asset_format">%1$s и %2$s будет отправлено</string>
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@
|
|||
<string name="common_generate_addresses">Get addresses</string>
|
||||
<string name="common_go_to_provider">Go to provider</string>
|
||||
<string name="common_import">Import</string>
|
||||
<string name="common_later">Later</string>
|
||||
<string name="common_locked">Locked</string>
|
||||
<string name="common_main_network">Main network</string>
|
||||
<string name="common_network_fee_title">Network fee</string>
|
||||
|
|
@ -253,6 +254,14 @@
|
|||
<string name="initial_message_sign_header">Tap to sign</string>
|
||||
<string name="initial_message_tap_header">Tap the card</string>
|
||||
<string name="key_invalidated_warning_description">You have updated biometrics, scan your card to enter</string>
|
||||
<string name="koinos_insufficient_balance_to_send_koin_description">Your balance should be higher than the fee value to make a transfer</string>
|
||||
<string name="koinos_insufficient_balance_to_send_koin_title">Not enough balance</string>
|
||||
<string name="koinos_insufficient_mana_to_send_koin_description">You don\'t have enough Mana for this transaction. Please wait until the Mana is refilled. Your Mana balance is %1$s/%2$s</string>
|
||||
<string name="koinos_insufficient_mana_to_send_koin_title">Not enough Mana</string>
|
||||
<string name="koinos_mana_exceeds_koin_balance_description">You can transfer only %s due to the Mana limit imposed by the Koinos network</string>
|
||||
<string name="koinos_mana_exceeds_koin_balance_title">Mana limit</string>
|
||||
<string name="koinos_mana_level_description">The Koinos network requires Mana for network fees. Your have %1$s/%2$s Mana</string>
|
||||
<string name="koinos_mana_level_title">Mana level</string>
|
||||
<string name="main_empty_tokens_list_message">To begin tracking your crypto assets and transactions, add tokens</string>
|
||||
<string name="main_manage_tokens">Manage tokens</string>
|
||||
<string name="main_scan_card_warning_view_subtitle">To access all the networks you need to scan the card</string>
|
||||
|
|
@ -297,6 +306,7 @@
|
|||
<string name="onboarding_access_codes_doesnt_match">Entered access code didn\'t match the initial access code</string>
|
||||
<string name="onboarding_activation_error_message">Please repeat the operation. The card will be reset to factory settings.</string>
|
||||
<string name="onboarding_activation_error_title">Activation error</string>
|
||||
<string name="onboarding_add_tokens">Add tokens</string>
|
||||
<string name="onboarding_alert_message_not_max_backup_cards_added">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?</string>
|
||||
<string name="onboarding_backup_exit_warning">The backup process is partly complete. You can\'t exit it now.</string>
|
||||
<string name="onboarding_bottom_sheet_passphrase_description">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.</string>
|
||||
|
|
@ -435,9 +445,11 @@
|
|||
<string name="send_alert_transaction_failed_text">Reason: %1$s\nCode: %2$s</string>
|
||||
<string name="send_alert_transaction_failed_title">The transaction is not completed</string>
|
||||
<string name="send_amount_label">Amount</string>
|
||||
<string name="send_base_fee">Base fee</string>
|
||||
<string name="send_base_fee_footer">Represents the part of the transaction fee that goes to the miner</string>
|
||||
<string name="send_bitcoin_custom_fee_footer">You can set your transaction fee by adjusting the value in the Satoshi per vByte field.</string>
|
||||
<string name="send_custom_evm_max_fee">Max fee</string>
|
||||
<string name="send_custom_evm_max_fee_footer">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)</string>
|
||||
<string name="send_custom_evm_priority_fee">Priority fee</string>
|
||||
<string name="send_custom_evm_priority_fee_footer">The fee that a user can pay to miners or validators to expedite the inclusion of their transaction in a block.</string>
|
||||
<string name="send_date_format">%1$s, %2$s</string>
|
||||
<string name="send_destination_hint_address">Address</string>
|
||||
<string name="send_destination_tag_field">Destination Tag</string>
|
||||
|
|
@ -461,8 +473,8 @@
|
|||
<string name="send_gas_price_footer">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.</string>
|
||||
<string name="send_max_amount">Max</string>
|
||||
<string name="send_max_amount_label">Maximum amount</string>
|
||||
<string name="send_max_fee">Max fee</string>
|
||||
<string name="send_memo_destination_tag_error">Numbers only for Destination Tag</string>
|
||||
<string name="send_max_fee">Fee up to</string>
|
||||
<string name="send_memo_destination_tag_error">Invalid Memo</string>
|
||||
<string name="send_network_fee_warning_title">Network fee coverage</string>
|
||||
<string name="send_notification_exceed_balance_text">Insufficient funds for the transfer, as the total of the fee and transfer amount exceeds the existing balance</string>
|
||||
<string name="send_notification_exceed_balance_title">Total exceeds balance</string>
|
||||
|
|
@ -479,13 +491,12 @@
|
|||
<string name="send_notification_invalid_reserve_amount_title">The amount to send must be at least %s</string>
|
||||
<string name="send_notification_leave_button">Leave %s</string>
|
||||
<string name="send_notification_reduce_by">Reduce by %s</string>
|
||||
<string name="send_notification_reduce_to">Reduce to %s</string>
|
||||
<string name="send_notification_transaction_delay_text">Kindly be aware that your transaction may experience delays under specific fee settings</string>
|
||||
<string name="send_notification_transaction_delay_title">Transaction delays are possible</string>
|
||||
<string name="send_notification_transaction_limit_text">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.</string>
|
||||
<string name="send_notification_transaction_limit_title">Transaction limitation</string>
|
||||
<string name="send_optional_field">Optional</string>
|
||||
<string name="send_priority_fee">Priority fee</string>
|
||||
<string name="send_priority_fee_footer">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.</string>
|
||||
<string name="send_qrcode_scan_info">Please align your QR code with the square to scan it. Ensure you scan %s network address.</string>
|
||||
<string name="send_recent_transactions">Recent</string>
|
||||
<string name="send_recipient">Recipient</string>
|
||||
|
|
@ -500,6 +511,7 @@
|
|||
<string name="send_summary_tap_hint">Tap any field to change it</string>
|
||||
<string name="send_summary_title">Send %s</string>
|
||||
<string name="send_summary_transaction_description">You are sending **%1$s** including a network fee of %2$s</string>
|
||||
<string name="send_summary_transaction_description_no_fiat_fee">You are sending **%1$s** and %2$s</string>
|
||||
<string name="send_title_currency_format">Sending %s</string>
|
||||
<string name="send_total_label">Total</string>
|
||||
<string name="send_total_subtitle_asset_format">%1$s and %2$s will be sent</string>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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 ->
|
||||
|
|
|
|||
13
core/ui/src/main/res/drawable/ic_koinos_22.xml
Normal file
13
core/ui/src/main/res/drawable/ic_koinos_22.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
<path
|
||||
android:pathData="M5.525,7.811L11,4.65L16.475,7.811C16.491,7.82 16.5,7.836 16.5,7.854V14.148C16.5,14.166 16.491,14.182 16.475,14.191L11.025,17.338L11.024,17.338L11.023,17.338L11.022,17.339L11.021,17.339L11.02,17.34L11.019,17.34L11.019,17.34L11.015,17.342L11.014,17.342L11.013,17.342H11.013L11.012,17.343L11.011,17.343H11.01L11.009,17.343H11.009L11.008,17.344H11.007L11.006,17.344H11.005L11.004,17.344H10.996L10.995,17.344H10.994L10.993,17.344H10.992L10.991,17.343H10.991L10.99,17.343H10.989L10.988,17.343L10.987,17.342H10.987L10.986,17.342L10.985,17.342L10.981,17.34L10.981,17.34L10.98,17.34L10.979,17.339L10.978,17.339L10.977,17.338L10.976,17.338L10.975,17.338L5.525,14.191C5.509,14.182 5.5,14.166 5.5,14.148V7.854C5.5,7.836 5.509,7.82 5.525,7.811ZM5.598,14.12L10.951,17.21V13.727L8.639,12.392C8.624,12.383 8.615,12.367 8.615,12.349V9.68L5.598,7.939V14.12ZM13.385,9.68V12.378L11.049,13.727V17.21L16.402,14.12V7.939L13.385,9.68ZM8.713,12.321L10.951,13.613V11.029L8.713,9.737V12.321ZM13.287,9.755L11.049,11.047V13.613L13.287,12.321V9.755ZM8.762,9.652L11,10.944L13.238,9.652L11,8.36L8.762,9.652ZM11,8.247L13.336,9.595L16.353,7.854L11,4.764L5.648,7.854L8.664,9.595L11,8.247Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.75"
|
||||
android:fillColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeColor="#000000"/>
|
||||
</vector>
|
||||
20
core/ui/src/main/res/drawable/img_koinos_22.xml
Normal file
20
core/ui/src/main/res/drawable/img_koinos_22.xml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="22dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="22"
|
||||
android:viewportHeight="22">
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M11,0L11,0A11,11 0,0 1,22 11L22,11A11,11 0,0 1,11 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z"/>
|
||||
<path
|
||||
android:pathData="M11,0L11,0A11,11 0,0 1,22 11L22,11A11,11 0,0 1,11 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z"
|
||||
android:fillColor="#25174E"/>
|
||||
<path
|
||||
android:pathData="M5.525,7.811L11,4.65L16.475,7.811C16.491,7.82 16.5,7.836 16.5,7.854V14.148C16.5,14.166 16.491,14.182 16.475,14.191L11.025,17.338L11.024,17.338L11.023,17.338L11.022,17.339L11.021,17.339L11.02,17.34L11.019,17.34L11.019,17.34L11.015,17.342L11.014,17.342L11.013,17.342H11.013L11.012,17.343L11.011,17.343H11.01L11.009,17.343H11.009L11.008,17.344H11.007L11.006,17.344H11.005L11.004,17.344H10.996L10.995,17.344H10.994L10.993,17.344H10.992L10.991,17.343H10.991L10.99,17.343H10.989L10.988,17.343L10.987,17.342H10.987L10.986,17.342L10.985,17.342L10.981,17.34L10.981,17.34L10.98,17.34L10.979,17.339L10.978,17.339L10.977,17.338L10.976,17.338L10.975,17.338L5.525,14.191C5.509,14.182 5.5,14.166 5.5,14.148V7.854C5.5,7.836 5.509,7.82 5.525,7.811ZM5.598,14.12L10.951,17.21V13.727L8.639,12.392C8.624,12.383 8.615,12.367 8.615,12.35V9.681L5.598,7.939V14.12ZM13.385,9.681V12.378L11.049,13.727V17.21L16.402,14.12V7.939L13.385,9.681ZM8.713,12.321L10.951,13.613V11.029L8.713,9.737V12.321ZM13.287,9.756L11.049,11.047V13.613L13.287,12.321V9.756ZM8.762,9.652L11,10.944L13.238,9.652L11,8.36L8.762,9.652ZM11,8.247L13.336,9.595L16.353,7.854L11,4.764L5.648,7.854L8.664,9.595L11,8.247Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="0.75"
|
||||
android:fillColor="#00000000"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeColor="#ffffff"/>
|
||||
</group>
|
||||
</vector>
|
||||
|
|
@ -388,6 +388,7 @@ internal class DefaultCurrenciesRepository(
|
|||
balance = balance,
|
||||
)
|
||||
}
|
||||
is FeePaidSdkCurrency.FeeResource -> FeePaidCurrency.FeeResource(currency = feePaidCurrency.currency)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ internal class TransactionDataToTxHistoryItemConverter(
|
|||
value
|
||||
}
|
||||
}
|
||||
is FeePaidCurrency.FeeResource -> value
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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?,
|
||||
)
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -60,6 +60,7 @@ internal class SendStateFactory(
|
|||
SendFeeStateConverter(
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
feeCryptoCurrencyStatusProvider = feeCryptoCurrencyStatusProvider,
|
||||
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
|
||||
)
|
||||
}
|
||||
private val confirmStateConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<SendNotification>.addCardanoNotifications(
|
||||
private suspend fun MutableList<SendNotification>.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<SendNotification>.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<SendNotification>.addDustWarningNotification(
|
||||
feeValue: BigDecimal,
|
||||
sendingAmount: BigDecimal,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
internal class SendFeeStateConverter(
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val feeCryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
) : Converter<Unit, SendStates.FeeState> {
|
||||
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -82,6 +82,7 @@ internal object FeeStatePreviewData {
|
|||
isFeeApproximate = false,
|
||||
notifications = persistentListOf(),
|
||||
isCustomSelected = false,
|
||||
isFeeConvertibleToFiat = true,
|
||||
)
|
||||
|
||||
val feeChoosableState = feeState.copy(
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<Warning>,
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ internal class TokenDetailsNotificationsAnalyticsSender(
|
|||
is TokenDetailsNotification.SwapPromo,
|
||||
is TokenDetailsNotification.NetworkShutdown,
|
||||
is TokenDetailsNotification.HederaAssociateWarning,
|
||||
is TokenDetailsNotification.KoinosMana,
|
||||
-> null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ^
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue