Updated on 2026-08-14
This commit is contained in:
parent
2091e5eecd
commit
16b069cf7a
2 changed files with 170 additions and 9 deletions
|
|
@ -532,16 +532,21 @@ internal class DefaultSwapRepositoryV2 @Inject constructor(
|
||||||
private fun List<ExpressProvider>.filterYieldSupplyProvider(
|
private fun List<ExpressProvider>.filterYieldSupplyProvider(
|
||||||
cryptoCurrencyStatus: CryptoCurrencyStatus?,
|
cryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||||
): List<ExpressProvider> {
|
): List<ExpressProvider> {
|
||||||
|
val isYieldSupplyActive = cryptoCurrencyStatus?.value?.yieldSupplyStatus?.isActive == true
|
||||||
|
if (!isYieldSupplyActive) return this
|
||||||
|
|
||||||
return if (featureTogglesManager.isFeatureEnabled(FeatureToggles.TWI_1326_YIELD_MODE_SWAP_ENABLED)) {
|
return if (featureTogglesManager.isFeatureEnabled(FeatureToggles.TWI_1326_YIELD_MODE_SWAP_ENABLED)) {
|
||||||
this
|
|
||||||
} else {
|
|
||||||
filter { provider ->
|
filter { provider ->
|
||||||
if (cryptoCurrencyStatus?.value?.yieldSupplyStatus?.isActive == true) {
|
when (provider.type) {
|
||||||
provider.type == ExpressProviderType.CEX
|
ExpressProviderType.CEX -> true
|
||||||
} else {
|
ExpressProviderType.DEX,
|
||||||
true
|
ExpressProviderType.DEX_BRIDGE,
|
||||||
|
-> provider.providerId in YIELD_ALLOWED_DEX_PROVIDER_IDS
|
||||||
|
ExpressProviderType.ONRAMP -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
filter { it.type == ExpressProviderType.CEX }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -552,6 +557,17 @@ private val MEMO_RESTRICTED_NETWORKS = setOf(
|
||||||
Blockchain.Algorand.toNetworkId(),
|
Blockchain.Algorand.toNetworkId(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEX providers allowed for token swaps in yield mode.
|
||||||
|
* Mirrors iOS ExpressConstants.yieldModuleDEXProviderIds (PR #4998).
|
||||||
|
*/
|
||||||
|
private val YIELD_ALLOWED_DEX_PROVIDER_IDS = setOf(
|
||||||
|
"1inch",
|
||||||
|
"li-fi",
|
||||||
|
"okx-cross-chain",
|
||||||
|
"okx-on-chain",
|
||||||
|
)
|
||||||
|
|
||||||
private suspend fun ExpressRepository.getFilteredProviders(
|
private suspend fun ExpressRepository.getFilteredProviders(
|
||||||
userWallet: UserWallet,
|
userWallet: UserWallet,
|
||||||
filterProviderTypes: List<ExpressProviderType>,
|
filterProviderTypes: List<ExpressProviderType>,
|
||||||
|
|
|
||||||
|
|
@ -539,7 +539,7 @@ internal class DefaultSwapRepositoryV2Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getPairs keeps DEX providers when yield supply is active and flag is on`() = runTest {
|
fun `GIVEN yield active and flag on WHEN getPairs THEN non-allowlisted DEX filtered out`() = runTest {
|
||||||
// Arrange
|
// Arrange
|
||||||
every { featureTogglesManager.isFeatureEnabled(FeatureToggles.TWI_1326_YIELD_MODE_SWAP_ENABLED) } returns true
|
every { featureTogglesManager.isFeatureEnabled(FeatureToggles.TWI_1326_YIELD_MODE_SWAP_ENABLED) } returns true
|
||||||
val primaryStatus = createCryptoCurrencyStatusWithActiveYield(primaryCoin)
|
val primaryStatus = createCryptoCurrencyStatusWithActiveYield(primaryCoin)
|
||||||
|
|
@ -580,10 +580,155 @@ internal class DefaultSwapRepositoryV2Test {
|
||||||
swapTxType = SwapTxType.Swap,
|
swapTxType = SwapTxType.Swap,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Assert — both providers should remain
|
// Assert — non-allowlisted DEX (dex-provider-1) dropped, only CEX remains
|
||||||
assertThat(result).hasSize(2)
|
assertThat(result).hasSize(2)
|
||||||
val providers = result.first().providers
|
val providers = result.first().providers
|
||||||
assertThat(providers).hasSize(2)
|
assertThat(providers).hasSize(1)
|
||||||
|
assertThat(providers.first().type).isEqualTo(ExpressProviderType.CEX)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN yield active and flag on WHEN getPairs THEN allowlisted DEX kept with CEX`() = runTest {
|
||||||
|
// Arrange
|
||||||
|
every { featureTogglesManager.isFeatureEnabled(FeatureToggles.TWI_1326_YIELD_MODE_SWAP_ENABLED) } returns true
|
||||||
|
val primaryStatus = createCryptoCurrencyStatusWithActiveYield(primaryCoin)
|
||||||
|
val secondaryStatus = createCryptoCurrencyStatus(secondaryCoin)
|
||||||
|
val primarySwapCurrencyStatus = SwapCurrencyStatus(userWallet = userWallet, status = primaryStatus, account = mockk())
|
||||||
|
val secondarySwapCurrencyStatus = SwapCurrencyStatus(userWallet = userWallet, status = secondaryStatus, account = mockk())
|
||||||
|
|
||||||
|
val allowedDexProvider = dexProvider.copy(providerId = "1inch")
|
||||||
|
val swapPair = SwapPair(
|
||||||
|
from = LeastTokenInfo(contractAddress = "0", network = ETH_BACKEND_ID),
|
||||||
|
to = LeastTokenInfo(contractAddress = "0", network = BTC_BACKEND_ID),
|
||||||
|
providers = listOf(
|
||||||
|
SwapPairProvider(providerId = "1inch", rateTypes = listOf(RateType.FLOAT)),
|
||||||
|
SwapPairProvider(providerId = CEX_PROVIDER_ID, rateTypes = listOf(RateType.FLOAT)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
coEvery { tangemExpressApi.getPairs(any(), any(), any()) } returns ApiResponse.Success(listOf(swapPair))
|
||||||
|
coEvery { expressRepository.getProviders(any(), any()) } returns listOf(allowedDexProvider, cexProvider)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = repository.getPairs(
|
||||||
|
primarySwapCurrencyStatus = primarySwapCurrencyStatus,
|
||||||
|
secondarySwapCurrencyStatus = secondarySwapCurrencyStatus,
|
||||||
|
filterProviderTypes = emptyList(),
|
||||||
|
swapTxType = SwapTxType.Swap,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert — allow-listed DEX (1inch) + CEX both kept
|
||||||
|
assertThat(result).hasSize(2)
|
||||||
|
val providers = result.first().providers
|
||||||
|
assertThat(providers.map { it.providerId }).containsExactly("1inch", CEX_PROVIDER_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN yield active and flag on WHEN getPairs THEN allowlisted DEX_BRIDGE kept with CEX`() = runTest {
|
||||||
|
// Arrange
|
||||||
|
every { featureTogglesManager.isFeatureEnabled(FeatureToggles.TWI_1326_YIELD_MODE_SWAP_ENABLED) } returns true
|
||||||
|
val primaryStatus = createCryptoCurrencyStatusWithActiveYield(primaryCoin)
|
||||||
|
val secondaryStatus = createCryptoCurrencyStatus(secondaryCoin)
|
||||||
|
val primarySwapCurrencyStatus = SwapCurrencyStatus(userWallet = userWallet, status = primaryStatus, account = mockk())
|
||||||
|
val secondarySwapCurrencyStatus = SwapCurrencyStatus(userWallet = userWallet, status = secondaryStatus, account = mockk())
|
||||||
|
|
||||||
|
val lifiProvider = dexProvider.copy(providerId = "li-fi", type = ExpressProviderType.DEX_BRIDGE)
|
||||||
|
val swapPair = SwapPair(
|
||||||
|
from = LeastTokenInfo(contractAddress = "0", network = ETH_BACKEND_ID),
|
||||||
|
to = LeastTokenInfo(contractAddress = "0", network = BTC_BACKEND_ID),
|
||||||
|
providers = listOf(
|
||||||
|
SwapPairProvider(providerId = "li-fi", rateTypes = listOf(RateType.FLOAT)),
|
||||||
|
SwapPairProvider(providerId = CEX_PROVIDER_ID, rateTypes = listOf(RateType.FLOAT)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
coEvery { tangemExpressApi.getPairs(any(), any(), any()) } returns ApiResponse.Success(listOf(swapPair))
|
||||||
|
coEvery { expressRepository.getProviders(any(), any()) } returns listOf(lifiProvider, cexProvider)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = repository.getPairs(
|
||||||
|
primarySwapCurrencyStatus = primarySwapCurrencyStatus,
|
||||||
|
secondarySwapCurrencyStatus = secondarySwapCurrencyStatus,
|
||||||
|
filterProviderTypes = emptyList(),
|
||||||
|
swapTxType = SwapTxType.Swap,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert — allow-listed DEX_BRIDGE (li-fi) + CEX both kept
|
||||||
|
assertThat(result).hasSize(2)
|
||||||
|
val providers = result.first().providers
|
||||||
|
assertThat(providers.map { it.providerId }).containsExactly("li-fi", CEX_PROVIDER_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN yield active and flag on WHEN getPairs THEN ONRAMP provider filtered out`() = runTest {
|
||||||
|
// Arrange
|
||||||
|
every { featureTogglesManager.isFeatureEnabled(FeatureToggles.TWI_1326_YIELD_MODE_SWAP_ENABLED) } returns true
|
||||||
|
val primaryStatus = createCryptoCurrencyStatusWithActiveYield(primaryCoin)
|
||||||
|
val secondaryStatus = createCryptoCurrencyStatus(secondaryCoin)
|
||||||
|
val primarySwapCurrencyStatus = SwapCurrencyStatus(userWallet = userWallet, status = primaryStatus, account = mockk())
|
||||||
|
val secondarySwapCurrencyStatus = SwapCurrencyStatus(userWallet = userWallet, status = secondaryStatus, account = mockk())
|
||||||
|
|
||||||
|
val onrampProvider = dexProvider.copy(providerId = "onramp-provider", type = ExpressProviderType.ONRAMP)
|
||||||
|
val swapPair = SwapPair(
|
||||||
|
from = LeastTokenInfo(contractAddress = "0", network = ETH_BACKEND_ID),
|
||||||
|
to = LeastTokenInfo(contractAddress = "0", network = BTC_BACKEND_ID),
|
||||||
|
providers = listOf(
|
||||||
|
SwapPairProvider(providerId = "onramp-provider", rateTypes = listOf(RateType.FLOAT)),
|
||||||
|
SwapPairProvider(providerId = CEX_PROVIDER_ID, rateTypes = listOf(RateType.FLOAT)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
coEvery { tangemExpressApi.getPairs(any(), any(), any()) } returns ApiResponse.Success(listOf(swapPair))
|
||||||
|
coEvery { expressRepository.getProviders(any(), any()) } returns listOf(onrampProvider, cexProvider)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = repository.getPairs(
|
||||||
|
primarySwapCurrencyStatus = primarySwapCurrencyStatus,
|
||||||
|
secondarySwapCurrencyStatus = secondarySwapCurrencyStatus,
|
||||||
|
filterProviderTypes = emptyList(),
|
||||||
|
swapTxType = SwapTxType.Swap,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert — ONRAMP dropped, only CEX remains
|
||||||
|
assertThat(result).hasSize(2)
|
||||||
|
val providers = result.first().providers
|
||||||
|
assertThat(providers).hasSize(1)
|
||||||
|
assertThat(providers.first().type).isEqualTo(ExpressProviderType.CEX)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN yield inactive and flag on WHEN getPairs THEN all providers kept`() = runTest {
|
||||||
|
// Arrange
|
||||||
|
every { featureTogglesManager.isFeatureEnabled(FeatureToggles.TWI_1326_YIELD_MODE_SWAP_ENABLED) } returns true
|
||||||
|
val primaryStatus = createCryptoCurrencyStatus(primaryCoin)
|
||||||
|
val secondaryStatus = createCryptoCurrencyStatus(secondaryCoin)
|
||||||
|
val primarySwapCurrencyStatus = SwapCurrencyStatus(userWallet = userWallet, status = primaryStatus, account = mockk())
|
||||||
|
val secondarySwapCurrencyStatus = SwapCurrencyStatus(userWallet = userWallet, status = secondaryStatus, account = mockk())
|
||||||
|
|
||||||
|
val swapPair = SwapPair(
|
||||||
|
from = LeastTokenInfo(contractAddress = "0", network = ETH_BACKEND_ID),
|
||||||
|
to = LeastTokenInfo(contractAddress = "0", network = BTC_BACKEND_ID),
|
||||||
|
providers = listOf(
|
||||||
|
SwapPairProvider(providerId = PROVIDER_ID, rateTypes = listOf(RateType.FLOAT)),
|
||||||
|
SwapPairProvider(providerId = CEX_PROVIDER_ID, rateTypes = listOf(RateType.FLOAT)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
coEvery { tangemExpressApi.getPairs(any(), any(), any()) } returns ApiResponse.Success(listOf(swapPair))
|
||||||
|
coEvery { expressRepository.getProviders(any(), any()) } returns listOf(dexProvider, cexProvider)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = repository.getPairs(
|
||||||
|
primarySwapCurrencyStatus = primarySwapCurrencyStatus,
|
||||||
|
secondarySwapCurrencyStatus = secondarySwapCurrencyStatus,
|
||||||
|
filterProviderTypes = emptyList(),
|
||||||
|
swapTxType = SwapTxType.Swap,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert — yield inactive → non-allow-listed DEX (dex-provider-1) survives alongside CEX
|
||||||
|
assertThat(result).hasSize(2)
|
||||||
|
val providers = result.first().providers
|
||||||
|
assertThat(providers.map { it.providerId }).containsExactly(PROVIDER_ID, CEX_PROVIDER_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue