Updated on 2026-08-14
This commit is contained in:
parent
3f60d15820
commit
03f4f51fc7
8 changed files with 42 additions and 354 deletions
|
|
@ -20,7 +20,6 @@ import com.tangem.data.staking.converters.transaction.StakingTransactionConverte
|
|||
import com.tangem.data.staking.converters.transaction.StakingTransactionStatusConverter
|
||||
import com.tangem.data.staking.converters.transaction.StakingTransactionTypeConverter
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.utils.StakingIdFactory
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.stakekit.StakeKitApi
|
||||
|
|
@ -60,7 +59,6 @@ import com.tangem.utils.extensions.orZero
|
|||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Suppress("LargeClass", "LongParameterList", "TooManyFunctions")
|
||||
internal class DefaultStakingRepository(
|
||||
|
|
@ -71,7 +69,6 @@ internal class DefaultStakingRepository(
|
|||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val stakingFeatureToggles: StakingFeatureToggles,
|
||||
private val stakingIdFactory: StakingIdFactory,
|
||||
moshi: Moshi,
|
||||
) : StakingRepository {
|
||||
|
||||
|
|
@ -375,32 +372,6 @@ internal class DefaultStakingRepository(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun getSingleYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): YieldBalance {
|
||||
val stakingId = stakingIdFactory.create(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
network = cryptoCurrency.network,
|
||||
) ?: error("Could not create stakingId")
|
||||
|
||||
return stakingBalanceStoreV2.getSyncOrNull(userWalletId = userWalletId, stakingId = stakingId)
|
||||
?: YieldBalance.Error(integrationId = stakingId.integrationId, address = stakingId.address)
|
||||
}
|
||||
|
||||
override suspend fun getMultiYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): List<YieldBalance>? {
|
||||
val stakingIds = cryptoCurrencies.mapNotNull {
|
||||
stakingIdFactory.create(userWalletId = userWalletId, currencyId = it.id, network = it.network)
|
||||
}
|
||||
|
||||
return stakingBalanceStoreV2.getAllSyncOrNull(userWalletId)
|
||||
?.filter { it.getStakingId() in stakingIds }
|
||||
}
|
||||
|
||||
override suspend fun isAnyTokenStaked(userWalletId: UserWalletId): Boolean {
|
||||
return withContext(dispatchers.default) {
|
||||
val balances = stakingBalanceStoreV2.getAllSyncOrNull(userWalletId) ?: return@withContext false
|
||||
|
|
@ -415,14 +386,6 @@ internal class DefaultStakingRepository(
|
|||
}
|
||||
}
|
||||
|
||||
override fun getActionRequirementAmount(integrationId: String, stakingActionType: StakingActionType): BigDecimal? {
|
||||
return when {
|
||||
stakingIdFactory.isPolygonIntegrationId(integrationId) &&
|
||||
stakingActionType == StakingActionType.CLAIM_REWARDS -> BigDecimal.ONE
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun createActionRequestBody(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import com.tangem.data.staking.DefaultStakingTransactionHashRepository
|
|||
import com.tangem.data.staking.converters.error.StakeKitErrorConverter
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.toggles.DefaultStakingFeatureToggles
|
||||
import com.tangem.data.staking.utils.StakingIdFactory
|
||||
import com.tangem.datasource.api.stakekit.StakeKitApi
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.error.StakeKitErrorResponse
|
||||
import com.tangem.datasource.di.NetworkMoshi
|
||||
|
|
@ -45,7 +44,6 @@ internal object StakingDataModule {
|
|||
walletManagersFacade: WalletManagersFacade,
|
||||
getUserWalletUseCase: GetUserWalletUseCase,
|
||||
stakingFeatureToggles: StakingFeatureToggles,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
): StakingRepository {
|
||||
return DefaultStakingRepository(
|
||||
|
|
@ -57,7 +55,6 @@ internal object StakingDataModule {
|
|||
getUserWalletUseCase = getUserWalletUseCase,
|
||||
stakingFeatureToggles = stakingFeatureToggles,
|
||||
moshi = moshi,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
package com.tangem.data.staking.utils
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.toCoinId
|
||||
import com.tangem.blockchainsdk.utils.toMigratedCoinId
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.model.StakingID
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Factory of [StakingID]
|
||||
*
|
||||
* @property walletManagersFacade wallet manager facade
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class StakingIdFactory @Inject constructor(
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
) {
|
||||
|
||||
suspend fun create(userWalletId: UserWalletId, currencyId: CryptoCurrency.ID, network: Network): StakingID? {
|
||||
val address = walletManagersFacade.getDefaultAddress(userWalletId = userWalletId, network = network)
|
||||
val integrationId = createIntegrationId(currencyId)
|
||||
|
||||
if (address == null || integrationId == null) return null
|
||||
|
||||
return StakingID(integrationId = integrationId, address = address)
|
||||
}
|
||||
|
||||
fun createIntegrationId(currencyId: CryptoCurrency.ID): String? {
|
||||
val integrationKey = with(currencyId) { rawNetworkId.plus(rawCurrencyId) }
|
||||
return integrationIdMap[integrationKey]
|
||||
}
|
||||
|
||||
fun isPolygonIntegrationId(integrationId: String): Boolean = integrationId == ETHEREUM_POLYGON_INTEGRATION_ID
|
||||
|
||||
@Suppress("UnusedPrivateMember", "unused")
|
||||
companion object {
|
||||
|
||||
private const val TON_INTEGRATION_ID = "ton-ton-chorus-one-pools-staking"
|
||||
private const val SOLANA_INTEGRATION_ID = "solana-sol-native-multivalidator-staking"
|
||||
private const val COSMOS_INTEGRATION_ID = "cosmos-atom-native-staking"
|
||||
private const val ETHEREUM_POLYGON_INTEGRATION_ID = "ethereum-matic-native-staking"
|
||||
private const val BINANCE_INTEGRATION_ID = "bsc-bnb-native-staking"
|
||||
private const val POLKADOT_INTEGRATION_ID = "polkadot-dot-validator-staking"
|
||||
private const val AVALANCHE_INTEGRATION_ID = "avalanche-avax-native-staking"
|
||||
private const val TRON_INTEGRATION_ID = "tron-trx-native-staking"
|
||||
private const val CRONOS_INTEGRATION_ID = "cronos-cro-native-staking"
|
||||
private const val KAVA_INTEGRATION_ID = "kava-kava-native-staking"
|
||||
private const val NEAR_INTEGRATION_ID = "near-near-native-staking"
|
||||
private const val TEZOS_INTEGRATION_ID = "tezos-xtz-native-staking"
|
||||
private const val CARDANO_INTEGRATION_ID = "cardano-ada-native-staking"
|
||||
|
||||
// uncomment items as implementation is ready
|
||||
private val integrationIdMap = mapOf(
|
||||
Blockchain.TON.toDefaultKey() to TON_INTEGRATION_ID,
|
||||
Blockchain.Solana.toDefaultKey() to SOLANA_INTEGRATION_ID,
|
||||
Blockchain.Cosmos.toDefaultKey() to COSMOS_INTEGRATION_ID,
|
||||
Blockchain.Tron.toDefaultKey() to TRON_INTEGRATION_ID,
|
||||
Blockchain.Ethereum.id + Blockchain.Polygon.toMigratedCoinId() to ETHEREUM_POLYGON_INTEGRATION_ID,
|
||||
// Blockchain.Ethereum.id + Blockchain.Polygon.toCoinId() to ETHEREUM_POLYGON_INTEGRATION_ID,
|
||||
Blockchain.BSC.toDefaultKey() to BINANCE_INTEGRATION_ID,
|
||||
// Blockchain.Polkadot.toDefaultKey() to POLKADOT_INTEGRATION_ID,
|
||||
// Blockchain.Avalanche.toDefaultKey() to AVALANCHE_INTEGRATION_ID,
|
||||
// Blockchain.Cronos.toDefaultKey() to CRONOS_INTEGRATION_ID,
|
||||
// Blockchain.Kava.toDefaultKey() to KAVA_INTEGRATION_ID,
|
||||
// Blockchain.Near.toDefaultKey() to NEAR_INTEGRATION_ID,
|
||||
// Blockchain.Tezos.toDefaultKey() to TEZOS_INTEGRATION_ID,
|
||||
Blockchain.Cardano.toDefaultKey() to CARDANO_INTEGRATION_ID,
|
||||
)
|
||||
|
||||
private fun Blockchain.toDefaultKey(): String = id + toCoinId()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,188 +0,0 @@
|
|||
package com.tangem.data.staking.utils
|
||||
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.toCoinId
|
||||
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
||||
import com.tangem.common.test.utils.ProvideTestModels
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.model.StakingID
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class StakingIdFactoryTest {
|
||||
|
||||
private val walletManagersFacade: WalletManagersFacade = mockk()
|
||||
private val factory = StakingIdFactory(walletManagersFacade = walletManagersFacade)
|
||||
|
||||
@BeforeEach
|
||||
fun resetMocks() {
|
||||
clearMocks(walletManagersFacade)
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class CreateIntegrationId {
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun createIntegrationId(model: CreateIntegrationIdModel) {
|
||||
// Act
|
||||
val actual = factory.createIntegrationId(currencyId = model.currencyId)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEqualTo(model.expected)
|
||||
}
|
||||
|
||||
private fun provideTestModels() = listOf(
|
||||
CreateIntegrationIdModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.TON),
|
||||
expected = "ton-ton-chorus-one-pools-staking",
|
||||
),
|
||||
CreateIntegrationIdModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.Solana),
|
||||
expected = "solana-sol-native-multivalidator-staking",
|
||||
),
|
||||
CreateIntegrationIdModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.Cosmos),
|
||||
expected = "cosmos-atom-native-staking",
|
||||
),
|
||||
CreateIntegrationIdModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.Tron),
|
||||
expected = "tron-trx-native-staking",
|
||||
),
|
||||
CreateIntegrationIdModel(
|
||||
currencyId = CryptoCurrency.ID.fromValue(value = "coin⟨ETH⟩polygon-ecosystem-token⚓"),
|
||||
expected = "ethereum-matic-native-staking",
|
||||
),
|
||||
CreateIntegrationIdModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.BSC),
|
||||
expected = "bsc-bnb-native-staking",
|
||||
),
|
||||
CreateIntegrationIdModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.Cardano),
|
||||
expected = "cardano-ada-native-staking",
|
||||
),
|
||||
CreateIntegrationIdModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.Bitcoin),
|
||||
expected = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
data class CreateIntegrationIdModel(val currencyId: CryptoCurrency.ID, val expected: String?)
|
||||
|
||||
@Nested
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
inner class Create {
|
||||
|
||||
private val defaultAddress = "address"
|
||||
|
||||
@Test
|
||||
fun `create returns null if address is null`() = runTest {
|
||||
// Arrange
|
||||
val userWalletId = UserWalletId(stringValue = "011")
|
||||
val currency = MockCryptoCurrencyFactory().createCoin(Blockchain.TON)
|
||||
|
||||
coEvery {
|
||||
walletManagersFacade.getDefaultAddress(userWalletId = userWalletId, network = currency.network)
|
||||
} returns null
|
||||
|
||||
// Act
|
||||
val actual = factory.create(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = currency.id,
|
||||
network = currency.network,
|
||||
)
|
||||
|
||||
// Assert
|
||||
val expected = null
|
||||
Truth.assertThat(actual).isEqualTo(expected)
|
||||
|
||||
coVerify(exactly = 1) {
|
||||
walletManagersFacade.getDefaultAddress(userWalletId = userWalletId, network = currency.network)
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ProvideTestModels
|
||||
fun create(model: CreateModel) = runTest {
|
||||
// Arrange
|
||||
val userWalletId = UserWalletId(stringValue = "011")
|
||||
val network = MockCryptoCurrencyFactory().createCoin(Blockchain.TON).network
|
||||
|
||||
coEvery {
|
||||
walletManagersFacade.getDefaultAddress(userWalletId = userWalletId, network = network)
|
||||
} returns defaultAddress
|
||||
|
||||
// Act
|
||||
val actual = factory.create(userWalletId = userWalletId, currencyId = model.currencyId, network = network)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEqualTo(model.expected)
|
||||
|
||||
coVerify(exactly = 1) {
|
||||
walletManagersFacade.getDefaultAddress(userWalletId = userWalletId, network = network)
|
||||
}
|
||||
}
|
||||
|
||||
private fun provideTestModels() = listOf(
|
||||
CreateModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.TON),
|
||||
expected = createStakingId(integrationId = "ton-ton-chorus-one-pools-staking"),
|
||||
),
|
||||
CreateModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.Solana),
|
||||
expected = createStakingId(integrationId = "solana-sol-native-multivalidator-staking"),
|
||||
),
|
||||
CreateModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.Cosmos),
|
||||
expected = createStakingId(integrationId = "cosmos-atom-native-staking"),
|
||||
),
|
||||
CreateModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.Tron),
|
||||
expected = createStakingId(integrationId = "tron-trx-native-staking"),
|
||||
),
|
||||
CreateModel(
|
||||
currencyId = CryptoCurrency.ID.fromValue(value = "coin⟨ETH⟩polygon-ecosystem-token⚓"),
|
||||
expected = createStakingId(integrationId = "ethereum-matic-native-staking"),
|
||||
),
|
||||
CreateModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.BSC),
|
||||
expected = createStakingId(integrationId = "bsc-bnb-native-staking"),
|
||||
),
|
||||
CreateModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.Cardano),
|
||||
expected = createStakingId(integrationId = "cardano-ada-native-staking"),
|
||||
),
|
||||
CreateModel(
|
||||
currencyId = createCurrencyId(blockchain = Blockchain.Bitcoin),
|
||||
expected = null,
|
||||
),
|
||||
)
|
||||
|
||||
private fun createStakingId(integrationId: String): StakingID {
|
||||
return StakingID(integrationId = integrationId, address = defaultAddress)
|
||||
}
|
||||
}
|
||||
|
||||
data class CreateModel(val currencyId: CryptoCurrency.ID, val expected: StakingID?)
|
||||
|
||||
private fun createCurrencyId(blockchain: Blockchain): CryptoCurrency.ID {
|
||||
return CryptoCurrency.ID.fromValue(value = "coin⟨${blockchain.id}⟩${blockchain.toCoinId()}⚓")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue