Updated on 2026-08-14

This commit is contained in:
Tangem 2023-12-07 15:08:05 +03:00
parent d80b167451
commit 53d1d8b9a6
5 changed files with 46 additions and 27 deletions

View file

@ -295,9 +295,13 @@ internal class SwapInteractorImpl @Inject constructor(
)
val fromTokenAddress = getTokenAddress(fromToken.currency)
val isAllowedToSpend = quotes.dataModel?.allowanceContract?.let {
isAllowedToSpend(networkId, fromToken.currency, amount, it)
} ?: true
val isAllowedToSpend = if (quotes.dataModel != null) {
quotes.dataModel.allowanceContract?.let {
isAllowedToSpend(networkId, fromToken.currency, amount, it)
} ?: true
} else {
false
}
if (isAllowedToSpend && allowPermissionsHandler.isAddressAllowanceInProgress(fromTokenAddress)) {
allowPermissionsHandler.removeAddressFromProgress(fromTokenAddress)

View file

@ -25,7 +25,7 @@ sealed class ProviderState {
val subtitle: TextReference,
val selectionType: SelectionType,
val additionalBadge: AdditionalBadge,
val percentLowerThenBest: Float?,
val percentLowerThenBest: Float = 0f,
override val onProviderClick: (String) -> Unit,
) : ProviderState()
@ -48,4 +48,20 @@ sealed class ProviderState {
enum class SelectionType {
NONE, CLICK, SELECT
}
}
object ProviderPercentDiffComparator : Comparator<ProviderState> {
override fun compare(o1: ProviderState, o2: ProviderState): Int {
if (o1 is ProviderState.Content && o2 !is ProviderState.Content) {
return 1
}
if (o1 !is ProviderState.Content && o2 is ProviderState.Content) {
return -1
}
return if (o1 is ProviderState.Content && o2 is ProviderState.Content) {
o1.percentLowerThenBest.compareTo(o2.percentLowerThenBest)
} else {
0
}
}
}

View file

@ -151,7 +151,7 @@ private fun ProviderContentState(
maxLines = 1,
)
}
if (state.percentLowerThenBest != null) {
if (state.percentLowerThenBest > 0f) {
AnimatedContent(targetState = state.percentLowerThenBest, label = "") {
Text(
text = "-$it%",

View file

@ -780,9 +780,11 @@ internal class StateBuilder(
unavailableProviders: List<SwapProvider>,
onDismiss: () -> Unit,
): SwapStateHolder {
val availableProvidersStates = providersStates.entries.mapNotNull {
it.convertToProviderBottomSheetState(pricesLowerBest, actions.onProviderSelect)
}
val availableProvidersStates = providersStates.entries
.mapNotNull {
it.convertToProviderBottomSheetState(pricesLowerBest, actions.onProviderSelect)
}
.sortedWith(ProviderPercentDiffComparator)
val unavailableProviderStates = unavailableProviders.map {
it.convertToUnavailableProviderState(
alertText = resourceReference(R.string.express_provider_not_available),
@ -1024,7 +1026,7 @@ internal class StateBuilder(
subtitle = stringReference(rateString),
additionalBadge = badge,
selectionType = selectionType,
percentLowerThenBest = null,
percentLowerThenBest = ZERO_PERCENT,
onProviderClick = onProviderClick,
)
}
@ -1053,7 +1055,7 @@ internal class StateBuilder(
subtitle = stringReference(rateString),
additionalBadge = additionalBadge,
selectionType = selectionType,
percentLowerThenBest = pricesLowerBest[this],
percentLowerThenBest = pricesLowerBest[this] ?: ZERO_PERCENT,
onProviderClick = onProviderClick,
)
}
@ -1087,7 +1089,7 @@ internal class StateBuilder(
selectionType = selectionType,
subtitle = alertText,
additionalBadge = ProviderState.AdditionalBadge.Empty,
percentLowerThenBest = null,
percentLowerThenBest = ZERO_PERCENT,
onProviderClick = onProviderClick,
)
}
@ -1128,5 +1130,6 @@ internal class StateBuilder(
private const val HUNDRED_PERCENTS = 100
private const val UNKNOWN_AMOUNT_SIGN = ""
private const val MAX_DECIMALS_TO_SHOW = 8
private const val ZERO_PERCENT = 0f
}
}

View file

@ -42,6 +42,7 @@ import java.text.DecimalFormat
import java.text.NumberFormat
import java.util.Locale
import javax.inject.Inject
import kotlin.math.absoluteValue
import kotlin.properties.Delegates
typealias SuccessLoadedSwapData = Map<SwapProvider, SwapState.QuotesLoadedState>
@ -863,21 +864,17 @@ internal class SwapViewModel @Inject constructor(
}
private fun getPricesLowerBest(state: SuccessLoadedSwapData): Map<SwapProvider, Float> {
val rates = state.mapValues {
it.value.fromTokenInfo.amountFiat.divide(
it.value.toTokenInfo.amountFiat,
2,
RoundingMode.HALF_UP,
)
}
val bestRate = rates.minByOrNull { it.value } ?: return emptyMap()
return rates.mapNotNull {
if (it.key != bestRate.key) {
val percentDiff = bestRate.value
.divide(it.value, 2, RoundingMode.HALF_UP)
.multiply(BigDecimal(HUNDRED_PERCENT))
.toFloat()
HUNDRED_PERCENT - percentDiff
val bestRateEntry = state.maxByOrNull { it.value.toTokenInfo.tokenAmount.value } ?: return emptyMap()
val bestRate = bestRateEntry.value.toTokenInfo.tokenAmount.value
val hundredPercent = BigDecimal("100")
return state.mapNotNull {
if (it.key != bestRateEntry.key) {
val amount = it.value.toTokenInfo.tokenAmount.value
val percentDiff = BigDecimal.ONE.minus(
amount.divide(bestRate, RoundingMode.HALF_UP)
.multiply(hundredPercent),
)
percentDiff.setScale(2, RoundingMode.HALF_UP).toFloat().absoluteValue
} else {
null
}
@ -935,6 +932,5 @@ internal class SwapViewModel @Inject constructor(
private const val INITIAL_AMOUNT = ""
private const val UPDATE_DELAY = 10000L
private const val DEBOUNCE_AMOUNT_DELAY = 1000L
private const val HUNDRED_PERCENT = 100
}
}