diff --git a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt index 66b28de458..662a404f90 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationUM.kt @@ -9,6 +9,7 @@ import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.format.bigdecimal.shorted +import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning import java.math.BigDecimal @@ -399,11 +400,16 @@ sealed class NotificationUM(val config: NotificationConfig) { data class RentExemptionDestination( private val rentExemptionAmount: BigDecimal, + private val cryptoCurrency: CryptoCurrency, ) : Error( title = TextReference.Res(R.string.send_notification_invalid_amount_title), subtitle = TextReference.Res( id = R.string.send_notification_invalid_amount_rent_destination, - formatArgs = wrappedList(rentExemptionAmount), + formatArgs = wrappedList( + rentExemptionAmount.format { + crypto(cryptoCurrency) + }, + ), ), ) } diff --git a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt index 4afee30930..362f8ad5a4 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt @@ -368,6 +368,7 @@ object NotificationsFactory { is BlockchainSdkError.DestinationTagRequired -> addRequireDestinationTagErrorNotification() is BlockchainSdkError.Solana.DestinationRentExemption -> addRentExemptionDestinationNotification( rentExemptionAmount = validationError.rentAmount, + cryptoCurrency = cryptoCurrency, ) is BlockchainSdkError.TransactionDustChangeError -> add( NotificationUM.Error.MinimumAmountError( @@ -462,10 +463,14 @@ object NotificationsFactory { add(NotificationUM.Solana.RentInfo(rentWarning)) } - fun MutableList.addRentExemptionDestinationNotification(rentExemptionAmount: BigDecimal) { + private fun MutableList.addRentExemptionDestinationNotification( + rentExemptionAmount: BigDecimal, + cryptoCurrency: CryptoCurrency, + ) { add( NotificationUM.Solana.RentExemptionDestination( rentExemptionAmount = rentExemptionAmount, + cryptoCurrency = cryptoCurrency, ), ) } diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt index 17aa2184d7..31d7fecf65 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt @@ -22,6 +22,7 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.yieldSupplyKey import com.tangem.domain.models.staking.YieldBalance import com.tangem.domain.staking.utils.getTotalWithRewardsStakingBalance +import com.tangem.lib.crypto.BlockchainUtils import com.tangem.utils.StringsSigns.DASH_SIGN import com.tangem.utils.converter.Converter import com.tangem.utils.extensions.orZero @@ -185,6 +186,7 @@ class TokenItemStateConverter( } } + // polygon-pos_0xc2132d05d31c914a87c6611c10748aeb04b58e8f private fun resolveEarnApy( cryptoCurrencyStatus: CryptoCurrencyStatus, yieldModuleApyMap: Map, @@ -192,7 +194,12 @@ class TokenItemStateConverter( ): Pair { val token = cryptoCurrencyStatus.currency as? CryptoCurrency.Token if (token != null && yieldModuleApyMap.isNotEmpty()) { - val yieldSupplyApy = yieldModuleApyMap[token.yieldSupplyKey()] + val yieldSupplyApy = yieldModuleApyMap.entries.firstOrNull { + it.key.equals( + other = token.yieldSupplyKey(), + ignoreCase = BlockchainUtils.isCaseInsensitiveContractAddress(token.network.rawId), + ) + }?.value if (yieldSupplyApy != null) { val isActive = cryptoCurrencyStatus.value.yieldSupplyStatus?.isActive ?: false return resourceReference( diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index 8e7c887222..22419eb4eb 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -1484,7 +1484,7 @@ Des frais de réseau d\'environ %1$s (%2$s) seront déduits de chaque recharge future, sans dépasser votre limite de %3$s (%4$s). Si les frais de réseau dépassent le montant maximal, la transaction ne sera pas effectuée tant qu\'ils n\'auront pas diminué. Vous pouvez modifier cette limite ultérieurement. Frais maximaux - Le montant minimum est calculé à partir des frais de réseau actuels afin de garantir qu\'il ne dépasse pas 4 %, ce qui donne un minimum de %1$s (%2$s). + Le montant minimum est calculé à partir des frais de réseau actuels afin de garantir qu\'il ne dépasse pas 4 %%, ce qui donne un minimum de %1$s (%2$s). Recharge minimale Politique tarifaire Tangem prélève également des frais de service de 3% sur les revenus générés. diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 143ab7e150..d31c06528c 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -1597,7 +1597,7 @@ Все следующие пополнения %s автоматически поступят в Aave с удержанием комиссии за транзакцию. Если комиссия сети превысит максимальный лимит, транзакция не будет выполнена до тех пор, пока комиссия не снизится. Вы сможете изменить этот лимит позже. Максимальная комиссия - Это минимальный депозит, который можно отправить в Aave. Чтобы депозиты оставались прибыльными, мы не обрабатываем их, когда комиссия сети превышает 4% от суммы. + Это минимальный депозит, который можно отправить в Aave. Чтобы депозиты оставались прибыльными, мы не обрабатываем их, когда комиссия сети превышает %1$s%2$sот суммы. Минимальный депозит Политика комиссий Tangem взимает комиссию за обслуживание в размере 3% от полученного дохода. diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml index 429d57b4f6..4a7a2575b3 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -1432,6 +1432,6 @@ Ні, відправити все Зменшити на %s XTZ Щоб не платити підвищену комісію при наступному поповненні гаманця, зменште суму на %s XTZ - Це найменший депозит, який можна надіслати в Aave. Щоб депозити залишалися прибутковими, ми не обробляємо їх, коли комісія мережі перевищує 4% від суми. + Це найменший депозит, який можна надіслати в Aave. Щоб депозити залишалися прибутковими, ми не обробляємо їх, коли комісія мережі перевищує %1$s%2$s від суми. Дозвіл для вашого токена в режимі Yield було відкликано. Відкрийте токен, щоб надати дозвіл знову. diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt b/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt index 5138158704..e709bd63de 100644 --- a/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt +++ b/domain/staking/src/main/java/com/tangem/domain/staking/usecase/StakingApyFlowUseCase.kt @@ -19,7 +19,7 @@ class StakingApyFlowUseCase(private val stakingRepository: StakingRepository) { return stakingRepository.getEnabledYields() .map { yields -> yields.associate { yield -> - val key = "${yield.token.network.name.lowercase()}_${yield.token.symbol}" + val key = "${yield.token.coinGeckoId}_${yield.token.symbol}" val apy = calculateApy(yield) key to apy } diff --git a/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapPairsUseCase.kt b/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapPairsUseCase.kt index fce04175b5..c45209f0ad 100644 --- a/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapPairsUseCase.kt +++ b/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapPairsUseCase.kt @@ -7,11 +7,7 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.swap.SwapErrorResolver import com.tangem.domain.swap.SwapRepositoryV2 -import com.tangem.domain.swap.models.SwapCryptoCurrency -import com.tangem.domain.swap.models.SwapCurrencies -import com.tangem.domain.swap.models.SwapCurrenciesGroup -import com.tangem.domain.swap.models.SwapPairModel -import com.tangem.domain.swap.models.SwapTxType +import com.tangem.domain.swap.models.* /** * Get list of swap pairs @@ -67,13 +63,14 @@ class GetSwapPairsUseCase( groupingCurrency: (SwapPairModel) -> CryptoCurrencyStatus, cryptoCurrencyStatusList: List, ): SwapCurrenciesGroup { - val availableCryptoCurrencies = filter { pair -> filteringCurrency(pair).currency.id == initialCurrency.id } + val availableCryptoCurrencies = filter { pair -> + filteringCurrency(pair).currency.id.rawCurrencyId == initialCurrency.id.rawCurrencyId + }.filter { pair -> // Search available to swap currency - .filter { pair -> - cryptoCurrencyStatusList.any { currencyStatus -> - currencyStatus.currency.id == pair.to.currency.id - } - }.map { pair -> SwapCryptoCurrency(groupingCurrency(pair), pair.providers) } + cryptoCurrencyStatusList.any { currencyStatus -> + currencyStatus.currency.id == pair.to.currency.id + } + }.map { pair -> SwapCryptoCurrency(groupingCurrency(pair), pair.providers) } val unavailableCryptoCurrencies = cryptoCurrencyStatusList - availableCryptoCurrencies.map { it.currencyStatus }.toSet() diff --git a/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapSupportedPairsUseCase.kt b/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapSupportedPairsUseCase.kt index 775eb8f797..f2d6c9a4c4 100644 --- a/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapSupportedPairsUseCase.kt +++ b/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapSupportedPairsUseCase.kt @@ -7,11 +7,7 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.swap.SwapErrorResolver import com.tangem.domain.swap.SwapRepositoryV2 -import com.tangem.domain.swap.models.SwapCryptoCurrency -import com.tangem.domain.swap.models.SwapCurrencies -import com.tangem.domain.swap.models.SwapCurrenciesGroup -import com.tangem.domain.swap.models.SwapPairModel -import com.tangem.domain.swap.models.SwapTxType +import com.tangem.domain.swap.models.* /** * Returns pais @@ -36,7 +32,7 @@ class GetSwapSupportedPairsUseCase( swapTxType = swapTxType, ) - val filteredOutInitial = cryptoCurrencyList.filterNot { it.id == initialCurrency.id } + val filteredOutInitial = cryptoCurrencyList.filterNot { it.id.rawNetworkId == initialCurrency.id.rawNetworkId } val fromGroup = pairs.groupPairs( initialCurrency = initialCurrency, @@ -63,15 +59,16 @@ class GetSwapSupportedPairsUseCase( groupingCurrency: (SwapPairModel) -> CryptoCurrencyStatus, cryptoCurrencyList: List, ): SwapCurrenciesGroup { - val availableCryptoCurrencies = filter { pair -> filteringCurrency(pair).currency.id == initialCurrency.id } + val availableCryptoCurrencies = filter { pair -> + filteringCurrency(pair).currency.id.rawCurrencyId == initialCurrency.id.rawCurrencyId + }.filter { pair -> // Search available to swap currency - .filter { pair -> - cryptoCurrencyList.any { currencyStatus -> - // Allowed only on networks without tx extras (e.i. memo and destination tag) - val isExtrasSupported = currencyStatus.network.transactionExtrasType.isTxExtrasSupported() - currencyStatus.id == pair.to.currency.id && !isExtrasSupported - } - }.map { pair -> SwapCryptoCurrency(groupingCurrency(pair), pair.providers) } + cryptoCurrencyList.any { currencyStatus -> + // Allowed only on networks without tx extras (e.i. memo and destination tag) + val isExtrasSupported = currencyStatus.network.transactionExtrasType.isTxExtrasSupported() + currencyStatus.id == pair.to.currency.id && !isExtrasSupported + } + }.map { pair -> SwapCryptoCurrency(groupingCurrency(pair), pair.providers) } val unavailableCryptoCurrencies = cryptoCurrencyList - availableCryptoCurrencies.map { it.currencyStatus.currency }.toSet() diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetButtonsStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetButtonsStateTransformer.kt index e51cdf8d61..5a69049425 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetButtonsStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetButtonsStateTransformer.kt @@ -13,6 +13,7 @@ import com.tangem.features.staking.impl.presentation.state.utils.getPendingActio import com.tangem.lib.crypto.BlockchainUtils import com.tangem.utils.extensions.orZero import com.tangem.utils.transformer.Transformer +import kotlin.text.isNullOrEmpty internal class SetButtonsStateTransformer( private val urlOpener: UrlOpener, @@ -25,7 +26,7 @@ internal class SetButtonsStateTransformer( val buttonsState = if (prevState.isButtonsVisible()) { NavigationButtonsState.Data( primaryButton = getPrimaryButton(prevState), - extraButtons = getExtraButtons(prevState).takeIf { txUrl != null }, + extraButtons = getExtraButtons(prevState).takeUnless { txUrl.isNullOrEmpty() }, txUrl = txUrl, onTextClick = urlOpener::openUrl, ) diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt index 913def042b..dbcb639c6b 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt @@ -40,30 +40,32 @@ import com.tangem.utils.StringsSigns internal fun YieldSupplyBlockContent(yieldSupplyUM: YieldSupplyUM, modifier: Modifier = Modifier) { AnimatedContent( targetState = yieldSupplyUM, - modifier = modifier, ) { supplyUM -> when (supplyUM) { - is YieldSupplyUM.Available -> SupplyAvailable(supplyUM) - YieldSupplyUM.Loading -> SupplyLoading() - is YieldSupplyUM.Content -> SupplyContent(supplyUM) + is YieldSupplyUM.Available -> SupplyAvailable(supplyUM, modifier) + YieldSupplyUM.Loading -> SupplyLoading(modifier) + is YieldSupplyUM.Content -> SupplyContent(supplyUM, modifier) YieldSupplyUM.Processing.Enter -> SupplyProcessing( resourceReference(R.string.yield_module_token_details_earn_notification_processing), + modifier, ) YieldSupplyUM.Processing.Exit -> SupplyProcessing( resourceReference(R.string.yield_module_stop_earning), + modifier, ) - YieldSupplyUM.Unavailable -> SupplyUnavailable() - YieldSupplyUM.Initial -> {} + YieldSupplyUM.Unavailable -> SupplyUnavailable(modifier) + YieldSupplyUM.Initial -> Unit } } } @Composable -private fun SupplyAvailable(supplyUM: YieldSupplyUM.Available) { +private fun SupplyAvailable(supplyUM: YieldSupplyUM.Available, modifier: Modifier = Modifier) { SupplyInfo( title = supplyUM.title, subtitle = resourceReference(R.string.yield_module_token_details_earn_notification_description), iconTint = TangemTheme.colors.icon.accent, + modifier = modifier, button = { SecondaryButton( text = stringResourceSafe(R.string.common_learn_more), @@ -76,20 +78,21 @@ private fun SupplyAvailable(supplyUM: YieldSupplyUM.Available) { } @Composable -private fun SupplyUnavailable() { +private fun SupplyUnavailable(modifier: Modifier = Modifier) { SupplyInfo( title = resourceReference(R.string.yield_module_unavailable_title), subtitle = resourceReference(R.string.yield_module_unavailable_subtitle), iconTint = TangemTheme.colors.icon.inactive, button = null, + modifier = modifier, ) } @Composable -private fun SupplyContent(supplyUM: YieldSupplyUM.Content) { +private fun SupplyContent(supplyUM: YieldSupplyUM.Content, modifier: Modifier = Modifier) { Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier + modifier = modifier .clip(RoundedCornerShape(16.dp)) .background(TangemTheme.colors.background.primary) .clickable(onClick = supplyUM.onClick) @@ -149,10 +152,10 @@ private fun SupplyContent(supplyUM: YieldSupplyUM.Content) { } @Composable -private fun SupplyProcessing(text: TextReference) { +private fun SupplyProcessing(text: TextReference, modifier: Modifier = Modifier) { Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier + modifier = modifier .clip(RoundedCornerShape(16.dp)) .background(TangemTheme.colors.background.primary) .padding(12.dp), @@ -190,11 +193,11 @@ private fun SupplyProcessing(text: TextReference) { } @Composable -private fun SupplyLoading() { +private fun SupplyLoading(modifier: Modifier = Modifier) { Column( verticalArrangement = Arrangement.spacedBy(12.dp), horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier + modifier = modifier .clip(RoundedCornerShape(16.dp)) .background(TangemTheme.colors.background.primary) .padding(12.dp), diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveTitle.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveTitle.kt index 300e051ba1..f965c213f4 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveTitle.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/ui/YieldSupplyActiveTitle.kt @@ -16,7 +16,10 @@ import com.tangem.features.yield.supply.impl.R @Composable internal fun YieldSupplyActiveTitle(onCloseClick: () -> Unit) { Box(modifier = Modifier.fillMaxWidth()) { - Column(modifier = Modifier.align(Alignment.Center)) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.align(Alignment.Center), + ) { Text( text = stringResourceSafe(R.string.yield_module_earn_sheet_title), style = TangemTheme.typography.subtitle1, diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt index 17fd386e25..b51011e498 100644 --- a/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt @@ -159,6 +159,13 @@ object BlockchainUtils { return isSolana(blockchainId) || isBSC(blockchainId) || isTon(blockchainId) } + /** Checks if the blockchain uses case-insensitive contract addresses */ + fun isCaseInsensitiveContractAddress(blockchainId: String): Boolean { + val blockchain = Blockchain.fromId(blockchainId) + + return blockchain.isEvm() + } + private fun getNetworkStandardName(blockchain: Blockchain): String { return when (blockchain) { Blockchain.Ethereum, Blockchain.EthereumTestnet -> "ERC20"