Updated on 2026-08-14
This commit is contained in:
parent
50332186fa
commit
5f6767abaf
58 changed files with 85 additions and 717 deletions
|
|
@ -14,26 +14,6 @@ internal class DefaultSwapFeatureToggles @Inject constructor(
|
|||
toggle = FeatureToggles.TWI_1326_YIELD_MODE_SWAP_ENABLED,
|
||||
)
|
||||
|
||||
override val isSwapSwitchToTransferEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(
|
||||
toggle = FeatureToggles.AND_15207_SWAP_SWITCH_TO_TRANSFER_ENABLED,
|
||||
)
|
||||
|
||||
override val isSwapIntegratedApproveEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(
|
||||
toggle = FeatureToggles.AND_15120_SWAP_INTEGRATED_APPROVE,
|
||||
)
|
||||
|
||||
override val isExpressShareButtonEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(
|
||||
toggle = FeatureToggles.AND_15489_EXPRESS_SHARE_BUTTON_ENABLED,
|
||||
)
|
||||
|
||||
override val isSwapBestDexRateEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(
|
||||
toggle = FeatureToggles.AND_15715_SWAP_BEST_DEX_RATE_ENABLED,
|
||||
) && isSwapIntegratedApproveEnabled
|
||||
|
||||
override val isHighFeeWarningEnabled: Boolean
|
||||
get() = featureTogglesManager.isFeatureEnabled(
|
||||
toggle = FeatureToggles.TWI_1367_HIGH_FEE_WARNING_ENABLED,
|
||||
|
|
|
|||
|
|
@ -28,18 +28,11 @@ internal object SwapProviderResolver {
|
|||
/**
|
||||
* Picks the best provider among [states].
|
||||
*
|
||||
* When [isSwapBestDexRateEnabled] is on and at least one DEX/DEX_BRIDGE provider is present, the
|
||||
* best-rated DEX provider wins; otherwise the overall best-rated provider is returned (the best
|
||||
* CEX when no DEX is available). "Best rated" = lowest from/to fiat ratio (most output per unit
|
||||
* of input). Returns null when [states] is empty.
|
||||
*
|
||||
* @param isSwapBestDexRateEnabled whether the Best DEX Rate feature toggle is on.
|
||||
* When at least one DEX/DEX_BRIDGE provider is present, the best-rated DEX provider wins; otherwise
|
||||
* the overall best-rated provider is returned (the best CEX when no DEX is available). "Best rated" =
|
||||
* lowest from/to fiat ratio (most output per unit of input). Returns null when [states] is empty.
|
||||
*/
|
||||
fun findBest(
|
||||
states: Map<SwapProvider, SwapState.QuotesLoadedState>,
|
||||
isSwapBestDexRateEnabled: Boolean,
|
||||
): SwapProvider? {
|
||||
if (!isSwapBestDexRateEnabled) return findBestRated(states)
|
||||
fun findBest(states: Map<SwapProvider, SwapState.QuotesLoadedState>): SwapProvider? {
|
||||
val dexStates = states.filterKeys { it.type.isDex() }
|
||||
return if (dexStates.isNotEmpty()) {
|
||||
findBestRated(dexStates)
|
||||
|
|
@ -54,7 +47,7 @@ internal object SwapProviderResolver {
|
|||
* Priority: FCA restriction → permission required → recommended → best rate → none. A best-rate
|
||||
* badge is shown only when more than one provider is considered, FCA restrictions are not applied,
|
||||
* and this row's quote carries no price-impact warning. Which best-rate badge it is depends on the
|
||||
* provider mix (only relevant when [isSwapBestDexRateEnabled] is on):
|
||||
* provider mix:
|
||||
* - [AdditionalBadge.BestTrade] ("Best rate") — always on the overall best-rated provider,
|
||||
* regardless of its type.
|
||||
* - [AdditionalBadge.BestDexRate] ("Best DEX rate") — only when both CEX and DEX providers are
|
||||
|
|
@ -62,22 +55,17 @@ internal object SwapProviderResolver {
|
|||
* shown on the best-rated DEX. When a DEX already is the overall best, or the set is CEX-only /
|
||||
* DEX-only, no separate "Best DEX rate" badge is shown.
|
||||
*
|
||||
* When [isSwapBestDexRateEnabled] is off, only the overall best provider gets [AdditionalBadge.BestTrade]
|
||||
* (legacy behaviour) and [AdditionalBadge.BestDexRate] is never produced.
|
||||
*
|
||||
* @param states all loaded quotes — used to find the best providers and to count considered providers.
|
||||
* @param provider the provider this row represents.
|
||||
* @param needApplyFCARestrictions whether FCA restrictions apply to the current user.
|
||||
* @param state this provider's [SwapState]; price-impact and permission are read from it when it
|
||||
* is a [SwapState.QuotesLoadedState]. Null for error rows (which only resolve to FCA / recommended / none).
|
||||
* @param isSwapBestDexRateEnabled whether the Best DEX Rate feature toggle is on.
|
||||
*/
|
||||
fun resolveBadge(
|
||||
states: Map<SwapProvider, SwapState.QuotesLoadedState>,
|
||||
provider: SwapProvider,
|
||||
needApplyFCARestrictions: Boolean,
|
||||
state: SwapState? = null,
|
||||
isSwapBestDexRateEnabled: Boolean,
|
||||
): AdditionalBadge {
|
||||
val priceImpact = (state as? SwapState.QuotesLoadedState)?.priceImpact
|
||||
val permissionState = (state as? SwapState.QuotesLoadedState)?.permissionState
|
||||
|
|
@ -90,7 +78,7 @@ internal object SwapProviderResolver {
|
|||
needApplyFCARestrictions && provider.isFCARestricted() -> AdditionalBadge.FCAWarningList
|
||||
permissionState is PermissionDataState.PermissionRequired -> AdditionalBadge.PermissionRequired
|
||||
provider.isRecommended -> AdditionalBadge.Recommended
|
||||
isBestRateBadgeAllowed -> resolveBestRateBadge(states, provider, isSwapBestDexRateEnabled)
|
||||
isBestRateBadgeAllowed -> resolveBestRateBadge(states, provider)
|
||||
else -> AdditionalBadge.Empty
|
||||
}
|
||||
}
|
||||
|
|
@ -102,16 +90,10 @@ internal object SwapProviderResolver {
|
|||
private fun resolveBestRateBadge(
|
||||
states: Map<SwapProvider, SwapState.QuotesLoadedState>,
|
||||
provider: SwapProvider,
|
||||
isSwapBestDexRateEnabled: Boolean,
|
||||
): AdditionalBadge {
|
||||
val overallBest = findBestRated(states)
|
||||
val isOverallBest = provider.providerId == overallBest?.providerId
|
||||
|
||||
// Toggle off → legacy behaviour: only the overall best provider gets the "Best rate" badge.
|
||||
if (!isSwapBestDexRateEnabled) {
|
||||
return if (isOverallBest) AdditionalBadge.BestTrade else AdditionalBadge.Empty
|
||||
}
|
||||
|
||||
val dexStates = states.filterKeys { it.type.isDex() }
|
||||
val hasDex = dexStates.isNotEmpty()
|
||||
val hasCex = states.keys.any { !it.type.isDex() }
|
||||
|
|
|
|||
|
|
@ -281,7 +281,6 @@ internal class SwapModel @Inject constructor(
|
|||
get() {
|
||||
val permissionState = dataState.getCurrentLoadedSwapState()?.permissionState
|
||||
return permissionState == PermissionDataState.Empty ||
|
||||
swapFeatureToggles.isSwapIntegratedApproveEnabled &&
|
||||
permissionState is PermissionDataState.PermissionSettings
|
||||
}
|
||||
|
||||
|
|
@ -1175,7 +1174,6 @@ internal class SwapModel @Inject constructor(
|
|||
needApplyFCARestrictions = userCountry.needApplyFCARestrictions(),
|
||||
states = loadedStates,
|
||||
state = state,
|
||||
isSwapBestDexRateEnabled = swapFeatureToggles.isSwapBestDexRateEnabled,
|
||||
)
|
||||
val swapFee = getSelectedSwapFee()
|
||||
uiState = stateBuilder.createQuotesLoadedState(
|
||||
|
|
@ -1272,7 +1270,6 @@ internal class SwapModel @Inject constructor(
|
|||
needApplyFCARestrictions = userCountry.needApplyFCARestrictions(),
|
||||
states = loadedStates,
|
||||
state = state,
|
||||
isSwapBestDexRateEnabled = swapFeatureToggles.isSwapBestDexRateEnabled,
|
||||
)
|
||||
uiState = stateBuilder.createQuotesErrorState(
|
||||
uiStateHolder = uiState,
|
||||
|
|
@ -1327,10 +1324,7 @@ internal class SwapModel @Inject constructor(
|
|||
|
||||
return if (consideredProviders.isNotEmpty()) {
|
||||
val successLoadedData = consideredProviders.getLastLoadedSuccessStates()
|
||||
val bestQuotesProvider = SwapProviderResolver.findBest(
|
||||
states = successLoadedData,
|
||||
isSwapBestDexRateEnabled = swapFeatureToggles.isSwapBestDexRateEnabled,
|
||||
)
|
||||
val bestQuotesProvider = SwapProviderResolver.findBest(states = successLoadedData)
|
||||
val currentSelected = dataState.selectedProvider
|
||||
if (currentSelected != null && consideredProviders.keys.contains(currentSelected)) {
|
||||
// logic for always choose best if already selected provider
|
||||
|
|
@ -2111,7 +2105,6 @@ internal class SwapModel @Inject constructor(
|
|||
selectedProviderId = providerId,
|
||||
pricesLowerBest = pricesLowerBest,
|
||||
providersStates = dataState.lastLoadedSwapStates,
|
||||
isSwapBestDexRateEnabled = swapFeatureToggles.isSwapBestDexRateEnabled,
|
||||
needApplyFCARestrictions = userCountry.needApplyFCARestrictions(),
|
||||
) { uiState = stateBuilder.dismissBottomSheet(uiState) }
|
||||
},
|
||||
|
|
@ -2663,8 +2656,7 @@ internal class SwapModel @Inject constructor(
|
|||
val swapDataForCall = resolveDexSwapDataForFee(quoteState)
|
||||
.getOrElse { return Either.Left(it) }
|
||||
|
||||
val integratedSettings = (quoteState.permissionState as? PermissionDataState.PermissionSettings)
|
||||
?.takeIf { swapFeatureToggles.isSwapIntegratedApproveEnabled }
|
||||
val integratedSettings = quoteState.permissionState as? PermissionDataState.PermissionSettings
|
||||
|
||||
return swapInteractor.loadSwapFee(
|
||||
quotesLoadedState = quoteState,
|
||||
|
|
@ -2833,8 +2825,7 @@ internal class SwapModel @Inject constructor(
|
|||
|
||||
private fun isPermissionNotificationShown(): Boolean {
|
||||
val permissionState = dataState.getCurrentLoadedSwapState()?.permissionState
|
||||
val isApprovalIntegrated = swapFeatureToggles.isSwapIntegratedApproveEnabled &&
|
||||
permissionState is PermissionDataState.PermissionSettings
|
||||
val isApprovalIntegrated = permissionState is PermissionDataState.PermissionSettings
|
||||
return permissionState != null && permissionState !is PermissionDataState.Empty && !isApprovalIntegrated
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1220,7 +1220,6 @@ internal class StateBuilder(
|
|||
pricesLowerBest: Map<String, Float>,
|
||||
providersStates: Map<SwapProvider, SwapState>,
|
||||
needApplyFCARestrictions: Boolean,
|
||||
isSwapBestDexRateEnabled: Boolean,
|
||||
onDismiss: () -> Unit,
|
||||
): SwapStateHolder {
|
||||
val successStates = providersStates.getLastLoadedSuccessStates()
|
||||
|
|
@ -1231,7 +1230,6 @@ internal class StateBuilder(
|
|||
provider = entry.key,
|
||||
needApplyFCARestrictions = needApplyFCARestrictions,
|
||||
state = entry.value,
|
||||
isSwapBestDexRateEnabled = isSwapBestDexRateEnabled,
|
||||
)
|
||||
entry.convertToProviderBottomSheetState(
|
||||
pricesLowerBest = pricesLowerBest,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue