Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-26 12:24:43 +02:00
parent 4ba8525f23
commit a2d9c5118b
3 changed files with 109 additions and 1 deletions

View file

@ -18,6 +18,7 @@ import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.model.StakingOption import com.tangem.domain.staking.model.StakingOption
import com.tangem.domain.staking.model.ethpool.P2PEthPoolBroadcastResult import com.tangem.domain.staking.model.ethpool.P2PEthPoolBroadcastResult
import com.tangem.domain.staking.model.ethpool.P2PEthPoolNetwork import com.tangem.domain.staking.model.ethpool.P2PEthPoolNetwork
import com.tangem.domain.staking.model.ethpool.P2PEthPoolStakingConfig
import com.tangem.domain.staking.model.ethpool.P2PEthPoolUnsignedTx import com.tangem.domain.staking.model.ethpool.P2PEthPoolUnsignedTx
import com.tangem.domain.staking.model.ethpool.P2PEthPoolVault import com.tangem.domain.staking.model.ethpool.P2PEthPoolVault
import com.tangem.domain.staking.model.stakekit.StakingError import com.tangem.domain.staking.model.stakekit.StakingError
@ -81,7 +82,9 @@ internal class DefaultP2PEthPoolRepository(
override suspend fun getVaults(network: P2PEthPoolNetwork): Either<StakingError, List<P2PEthPoolVault>> = either { override suspend fun getVaults(network: P2PEthPoolNetwork): Either<StakingError, List<P2PEthPoolVault>> = either {
withContext(dispatchers.io) { withContext(dispatchers.io) {
handleApiResponse(p2pEthPoolApi.getVaults(network.value)) { result -> handleApiResponse(p2pEthPoolApi.getVaults(network.value)) { result ->
result.vaults.map { vaultConverter.convert(it) } result.vaults
.map { vaultConverter.convert(it) }
.filter { it.vaultAddress.lowercase() !in P2PEthPoolStakingConfig.TEST_VAULT_ADDRESSES }
} }
} }
} }

View file

@ -0,0 +1,100 @@
package com.tangem.data.staking
import com.google.common.truth.Truth.assertThat
import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.ethpool.P2PEthPoolApi
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolNetworkDTO
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolResponse
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolVaultDTO
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolVaultsResponse
import com.tangem.datasource.local.token.P2PEthPoolVaultsStore
import com.tangem.domain.staking.model.StakingIntegrationID
import com.tangem.domain.staking.model.ethpool.P2PEthPoolNetwork
import com.tangem.domain.staking.toggles.StakingFeatureToggles
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
import io.mockk.coEvery
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import java.math.BigDecimal
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class P2PEthPoolVaultFilterTest {
private companion object {
const val PRODUCTION_VAULT_ADDRESS = "0x4c09BC47db288F998b33CD63BCc1b6ddCCe13F33"
const val TEST_VAULT_ADDRESS = "0xB72668D6FF7A0e318F83097A754c6AEd0f8AF034"
}
private val api = mockk<P2PEthPoolApi>()
private val store = mockk<P2PEthPoolVaultsStore>(relaxed = true)
private val featureToggles = mockk<StakingFeatureToggles> {
every { isIntegrationEnabled(StakingIntegrationID.P2PEthPool) } returns true
}
private val repository = DefaultP2PEthPoolRepository(
p2pEthPoolApi = api,
p2pEthPoolVaultsStore = store,
dispatchers = TestingCoroutineDispatcherProvider(),
stakingFeatureToggles = featureToggles,
)
private fun buildVaultDTO(address: String) = P2PEthPoolVaultDTO(
vaultAddress = address,
displayName = "Vault $address",
apy = BigDecimal("4.5"),
baseApy = BigDecimal("4.0"),
capacity = BigDecimal("10000"),
totalAssets = BigDecimal("5000"),
feePercent = BigDecimal("10"),
isPrivate = false,
isGenesis = false,
isSmoothingPool = true,
isErc20 = false,
tokenName = null,
tokenSymbol = null,
createdAt = 0L,
)
private fun successResponse(vararg addresses: String) = ApiResponse.Success(
P2PEthPoolResponse(
error = null,
result = P2PEthPoolVaultsResponse(
network = P2PEthPoolNetworkDTO.MAINNET,
vaults = addresses.map { buildVaultDTO(it) },
),
),
)
@Test
fun `test vault address is filtered from getVaults result`() = runTest {
coEvery { api.getVaults(any()) } returns successResponse(PRODUCTION_VAULT_ADDRESS, TEST_VAULT_ADDRESS)
val vaults = repository.getVaults(P2PEthPoolNetwork.MAINNET).getOrNull()
assertThat(vaults).hasSize(1)
assertThat(vaults?.first()?.vaultAddress).isEqualTo(PRODUCTION_VAULT_ADDRESS)
}
@Test
fun `production vault address passes filter`() = runTest {
coEvery { api.getVaults(any()) } returns successResponse(PRODUCTION_VAULT_ADDRESS)
val vaults = repository.getVaults(P2PEthPoolNetwork.MAINNET).getOrNull()
assertThat(vaults).hasSize(1)
}
@Test
fun `filter is case-insensitive`() = runTest {
coEvery { api.getVaults(any()) } returns successResponse(
TEST_VAULT_ADDRESS.uppercase(),
TEST_VAULT_ADDRESS.lowercase(),
)
val vaults = repository.getVaults(P2PEthPoolNetwork.MAINNET).getOrNull()
assertThat(vaults).isEmpty()
}
}

View file

@ -11,4 +11,9 @@ object P2PEthPoolStakingConfig {
val activeNetwork: P2PEthPoolNetwork val activeNetwork: P2PEthPoolNetwork
get() = if (USE_TESTNET) P2PEthPoolNetwork.TESTNET else P2PEthPoolNetwork.MAINNET get() = if (USE_TESTNET) P2PEthPoolNetwork.TESTNET else P2PEthPoolNetwork.MAINNET
/** Vault addresses returned by the backend that should not be shown to users (test/stub vaults). Stored in lowercase. */
val TEST_VAULT_ADDRESSES: Set<String> = setOf(
"0xb72668d6ff7a0e318f83097a754c6aed0f8af034",
)
} }