Updated on 2026-08-14
This commit is contained in:
parent
19fdd19139
commit
078e215ad7
18 changed files with 318 additions and 160 deletions
|
|
@ -3,6 +3,7 @@ package com.tangem.datasource.local.token
|
|||
import androidx.datastore.core.DataStore
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.datasource.local.token.StakingBalanceStore.StakingID
|
||||
import com.tangem.datasource.local.token.converter.YieldBalanceConverter
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
|
|
@ -26,10 +27,16 @@ internal class DefaultStakingBalanceStore(
|
|||
private val runtimeStore: RuntimeSharedStore<YieldBalanceListByWalletId>,
|
||||
) : StakingBalanceStore {
|
||||
|
||||
override fun get(userWalletId: UserWalletId): Flow<Set<YieldBalance>> = channelFlow {
|
||||
override fun get(userWalletId: UserWalletId, stakingIds: List<StakingID>): Flow<Set<YieldBalance>> = channelFlow {
|
||||
val cachedBalances = persistenceStore.data
|
||||
.map {
|
||||
val wrappers = it[userWalletId.stringValue].orEmpty()
|
||||
.filter { wrapper ->
|
||||
stakingIds.any { id ->
|
||||
id.address == wrapper.addresses.address && id.integrationId == wrapper.integrationId
|
||||
}
|
||||
}
|
||||
|
||||
YieldBalanceConverter(isCached = true).convertSet(input = wrappers)
|
||||
}
|
||||
.firstOrNull()
|
||||
|
|
@ -40,33 +47,64 @@ internal class DefaultStakingBalanceStore(
|
|||
}
|
||||
|
||||
runtimeStore.get()
|
||||
.map { it[userWalletId].orEmpty() }
|
||||
.map {
|
||||
it[userWalletId].orEmpty().filter { balance ->
|
||||
stakingIds.any { id ->
|
||||
id.address == balance.address && id.integrationId == balance.integrationId
|
||||
}
|
||||
}
|
||||
.toSet()
|
||||
}
|
||||
.onEach {
|
||||
val mergedBalances = mergeYieldBalances(cachedBalances = cachedBalances, runtimeBalances = it)
|
||||
val mergedBalances = mergeYieldBalances(
|
||||
stakingIds = stakingIds,
|
||||
cachedBalances = cachedBalances,
|
||||
runtimeBalances = it,
|
||||
)
|
||||
|
||||
send(mergedBalances)
|
||||
}
|
||||
.launchIn(scope = this)
|
||||
}
|
||||
|
||||
override fun get(userWalletId: UserWalletId, address: String, integrationId: String): Flow<YieldBalance?> {
|
||||
return get(userWalletId).map { balances ->
|
||||
balances.getBalance(address = address, integrationId = integrationId)
|
||||
override fun get(userWalletId: UserWalletId, stakingID: StakingID): Flow<YieldBalance?> {
|
||||
return get(userWalletId = userWalletId, stakingIds = listOf(stakingID)).map { balances ->
|
||||
balances.getBalance(stakingID = stakingID)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId): Set<YieldBalance>? {
|
||||
return runtimeStore.getSyncOrNull()?.getValue(userWalletId)
|
||||
val runtimeBalances = runtimeStore.getSyncOrNull()?.getValue(userWalletId).orEmpty()
|
||||
val cachedBalances = persistenceStore.data.firstOrNull()?.get(userWalletId.stringValue).orEmpty()
|
||||
|
||||
if (runtimeBalances.isEmpty() && cachedBalances.isEmpty()) return null
|
||||
|
||||
return cachedBalances.mapTo(hashSetOf()) {
|
||||
val cached = YieldBalanceConverter(source = StatusSource.ONLY_CACHE).convert(value = it)
|
||||
val runtime = runtimeBalances.getBalance(address = cached.address, integrationId = cached.integrationId)
|
||||
|
||||
if (runtime == null || runtime is YieldBalance.Error) cached else runtime
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(
|
||||
userWalletId: UserWalletId,
|
||||
address: String,
|
||||
integrationId: String,
|
||||
): YieldBalance? {
|
||||
val balances = getSyncOrNull(userWalletId) ?: return null
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingIds: List<StakingID>): Set<YieldBalance>? {
|
||||
val runtime = runtimeStore.getSyncOrNull()?.getValue(userWalletId)
|
||||
val cached = persistenceStore.data.firstOrNull()?.get(userWalletId.stringValue)
|
||||
|
||||
return balances.getBalance(address, integrationId)
|
||||
if (runtime.isNullOrEmpty() && cached.isNullOrEmpty()) return null
|
||||
|
||||
return mergeYieldBalances(
|
||||
cachedBalances = YieldBalanceConverter(source = StatusSource.ONLY_CACHE)
|
||||
.convertSet(input = cached.orEmpty()),
|
||||
runtimeBalances = runtime.orEmpty(),
|
||||
stakingIds = stakingIds,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingID: StakingID): YieldBalance? {
|
||||
val balances = getSyncOrNull(userWalletId = userWalletId, stakingIds = listOf(stakingID)) ?: return null
|
||||
|
||||
return balances.getBalance(stakingID = stakingID)
|
||||
}
|
||||
|
||||
override suspend fun store(userWalletId: UserWalletId, items: Set<YieldBalanceWrapperDTO>) {
|
||||
|
|
@ -88,34 +126,52 @@ internal class DefaultStakingBalanceStore(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun refresh(userWalletId: UserWalletId, addressWithIntegrationIdMap: Map<String, String>) {
|
||||
override suspend fun refresh(userWalletId: UserWalletId, stakingIds: List<StakingID>) {
|
||||
updateRuntimeStore(userWalletId = userWalletId) { saved ->
|
||||
saved.mapTo(hashSetOf()) { balance ->
|
||||
val refreshIntegrationId = addressWithIntegrationIdMap[balance.address]
|
||||
saved.mapTo(hashSetOf()) {
|
||||
val yieldBalance = it.takeIf { balance ->
|
||||
stakingIds.any { id -> balance.integrationId == id.integrationId && balance.address == id.address }
|
||||
}
|
||||
|
||||
if (balance.integrationId == refreshIntegrationId) {
|
||||
when (balance) {
|
||||
is YieldBalance.Data -> balance.copy(source = StatusSource.CACHE)
|
||||
is YieldBalance.Empty -> balance.copy(source = StatusSource.CACHE)
|
||||
is YieldBalance.Error -> balance
|
||||
if (yieldBalance != null) {
|
||||
when (yieldBalance) {
|
||||
is YieldBalance.Data -> yieldBalance.copy(source = StatusSource.CACHE)
|
||||
is YieldBalance.Empty -> yieldBalance.copy(source = StatusSource.CACHE)
|
||||
is YieldBalance.Error -> yieldBalance
|
||||
}
|
||||
} else {
|
||||
balance
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun store(
|
||||
userWalletId: UserWalletId,
|
||||
integrationId: String,
|
||||
address: String,
|
||||
item: YieldBalanceWrapperDTO,
|
||||
) {
|
||||
override suspend fun store(userWalletId: UserWalletId, stakingID: StakingID, item: YieldBalanceWrapperDTO) {
|
||||
coroutineScope {
|
||||
launch {
|
||||
storeInRuntimeStore(userWalletId, integrationId, address, item)
|
||||
storeInPersistenceStore(userWalletId, integrationId, address, item)
|
||||
storeInRuntimeStore(
|
||||
userWalletId = userWalletId,
|
||||
integrationId = stakingID.integrationId,
|
||||
address = stakingID.address,
|
||||
item = item,
|
||||
)
|
||||
|
||||
storeInPersistenceStore(
|
||||
userWalletId = userWalletId,
|
||||
integrationId = stakingID.integrationId,
|
||||
address = stakingID.address,
|
||||
item = item,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun storeSingleYieldBalance(userWalletId: UserWalletId, item: YieldBalance) {
|
||||
runtimeStore.update(default = emptyMap()) { saved ->
|
||||
saved.toMutableMap().apply {
|
||||
this[userWalletId] = saved[userWalletId]
|
||||
?.addOrReplace(item) { it.integrationId == item.integrationId && it.address == item.address }
|
||||
?: setOf(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -178,28 +234,22 @@ internal class DefaultStakingBalanceStore(
|
|||
private fun mergeYieldBalances(
|
||||
cachedBalances: Set<YieldBalance>,
|
||||
runtimeBalances: Set<YieldBalance>,
|
||||
stakingIds: List<StakingID>,
|
||||
): Set<YieldBalance> {
|
||||
if (runtimeBalances.isEmpty()) {
|
||||
return cachedBalances.mapNotNullTo(hashSetOf()) {
|
||||
when (it) {
|
||||
is YieldBalance.Data -> it.copy(source = StatusSource.ONLY_CACHE)
|
||||
is YieldBalance.Empty -> it.copy(source = StatusSource.ONLY_CACHE)
|
||||
is YieldBalance.Error -> null
|
||||
}
|
||||
return stakingIds.mapTo(hashSetOf()) { id ->
|
||||
val runtime = runtimeBalances.getBalance(stakingID = id)
|
||||
|
||||
if (runtime == null || runtime is YieldBalance.Error) {
|
||||
getCachedBalanceIfPossible(cachedBalances = cachedBalances, stakingID = id)
|
||||
} else {
|
||||
runtime
|
||||
}
|
||||
}
|
||||
|
||||
return runtimeBalances
|
||||
.map { runtime ->
|
||||
runtime.takeIf { runtime !is YieldBalance.Error }
|
||||
?: getCachedBalanceIfPossible(cachedBalances, runtime)
|
||||
}
|
||||
.toSet()
|
||||
}
|
||||
|
||||
private fun getCachedBalanceIfPossible(cachedBalances: Set<YieldBalance>, runtime: YieldBalance): YieldBalance {
|
||||
val cached = cachedBalances.getBalance(address = runtime.address, integrationId = runtime.integrationId)
|
||||
?: return runtime
|
||||
private fun getCachedBalanceIfPossible(cachedBalances: Set<YieldBalance>, stakingID: StakingID): YieldBalance {
|
||||
val cached = cachedBalances.getBalance(stakingID)
|
||||
?: return YieldBalance.Error(integrationId = stakingID.address, address = stakingID.integrationId)
|
||||
|
||||
val updatedCached = when (cached) {
|
||||
is YieldBalance.Data -> cached.copy(source = StatusSource.ONLY_CACHE)
|
||||
|
|
@ -207,7 +257,11 @@ internal class DefaultStakingBalanceStore(
|
|||
is YieldBalance.Error -> null
|
||||
}
|
||||
|
||||
return updatedCached ?: runtime
|
||||
return updatedCached ?: YieldBalance.Error(integrationId = stakingID.address, address = stakingID.integrationId)
|
||||
}
|
||||
|
||||
private fun Set<YieldBalance>.getBalance(stakingID: StakingID): YieldBalance? {
|
||||
return getBalance(address = stakingID.address, integrationId = stakingID.integrationId)
|
||||
}
|
||||
|
||||
private fun Set<YieldBalance>.getBalance(address: String?, integrationId: String?): YieldBalance? {
|
||||
|
|
|
|||
|
|
@ -9,23 +9,32 @@ import kotlinx.coroutines.flow.Flow
|
|||
/** Staking balance store */
|
||||
interface StakingBalanceStore {
|
||||
|
||||
/** Get flow of [YieldBalanceList] by [userWalletId] */
|
||||
fun get(userWalletId: UserWalletId): Flow<Set<YieldBalance>>
|
||||
/** Get flow of [YieldBalanceList] by [userWalletId] and [stakingIds] */
|
||||
fun get(userWalletId: UserWalletId, stakingIds: List<StakingID>): Flow<Set<YieldBalance>>
|
||||
|
||||
/** Get flow of [YieldBalance] by [userWalletId], [address] and [integrationId] */
|
||||
fun get(userWalletId: UserWalletId, address: String, integrationId: String): Flow<YieldBalance?>
|
||||
/** Get flow of [YieldBalance] by [userWalletId] and [stakingID] */
|
||||
fun get(userWalletId: UserWalletId, stakingID: StakingID): Flow<YieldBalance?>
|
||||
|
||||
/** Get [YieldBalanceList] synchronously or null by [userWalletId] */
|
||||
/** Get all [YieldBalance] synchronously or null by [userWalletId] */
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId): Set<YieldBalance>?
|
||||
|
||||
/** Get [YieldBalance] synchronously or null by [userWalletId], [address] and [integrationId] */
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId, address: String, integrationId: String): YieldBalance?
|
||||
/** Get [YieldBalanceList] synchronously or null by [userWalletId] and [stakingIds] */
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingIds: List<StakingID>): Set<YieldBalance>?
|
||||
|
||||
/** Get [YieldBalance] synchronously or null by [userWalletId] and [stakingID] */
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingID: StakingID): YieldBalance?
|
||||
|
||||
/** Store [items] by [userWalletId] */
|
||||
suspend fun store(userWalletId: UserWalletId, items: Set<YieldBalanceWrapperDTO>)
|
||||
|
||||
/** Store [item] by [userWalletId], [integrationId] and [address] */
|
||||
suspend fun store(userWalletId: UserWalletId, integrationId: String, address: String, item: YieldBalanceWrapperDTO)
|
||||
/** Store [item] by [userWalletId] and [stakingID] */
|
||||
suspend fun store(userWalletId: UserWalletId, stakingID: StakingID, item: YieldBalanceWrapperDTO)
|
||||
|
||||
suspend fun refresh(userWalletId: UserWalletId, addressWithIntegrationIdMap: Map<String, String>)
|
||||
/** Store [item] by [userWalletId] */
|
||||
suspend fun storeSingleYieldBalance(userWalletId: UserWalletId, item: YieldBalance)
|
||||
|
||||
/** Refresh balances of [stakingIds] by [userWalletId] */
|
||||
suspend fun refresh(userWalletId: UserWalletId, stakingIds: List<StakingID>)
|
||||
|
||||
data class StakingID(val integrationId: String, val address: String)
|
||||
}
|
||||
|
|
@ -7,14 +7,18 @@ import com.tangem.domain.staking.model.stakekit.YieldBalance
|
|||
import com.tangem.domain.staking.model.stakekit.YieldBalanceItem
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class YieldBalanceConverter(private val isCached: Boolean) : Converter<YieldBalanceWrapperDTO, YieldBalance> {
|
||||
internal class YieldBalanceConverter(
|
||||
private val source: StatusSource,
|
||||
) : Converter<YieldBalanceWrapperDTO, YieldBalance> {
|
||||
|
||||
constructor(isCached: Boolean) : this(source = if (isCached) StatusSource.CACHE else StatusSource.ACTUAL)
|
||||
|
||||
override fun convert(value: YieldBalanceWrapperDTO): YieldBalance {
|
||||
return if (value.balances.isEmpty()) {
|
||||
YieldBalance.Empty(
|
||||
integrationId = value.integrationId,
|
||||
address = value.addresses.address,
|
||||
source = if (isCached) StatusSource.CACHE else StatusSource.ACTUAL,
|
||||
source = source,
|
||||
)
|
||||
} else {
|
||||
YieldBalance.Data(
|
||||
|
|
@ -40,7 +44,7 @@ internal class YieldBalanceConverter(private val isCached: Boolean) : Converter<
|
|||
.sortedWith(compareBy({ it.type }, { it.amount })),
|
||||
integrationId = value.integrationId,
|
||||
),
|
||||
source = if (isCached) StatusSource.CACHE else StatusSource.ACTUAL,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -372,20 +372,33 @@ internal class DefaultStakingRepository(
|
|||
}
|
||||
|
||||
val requestBody = getBalanceRequestData(address, integrationId)
|
||||
val result = stakeKitApi.getSingleYieldBalance(
|
||||
integrationId = requestBody.integrationId,
|
||||
body = requestBody,
|
||||
).getOrThrow()
|
||||
|
||||
stakingBalanceStore.store(
|
||||
userWalletId = userWalletId,
|
||||
integrationId = requestBody.integrationId,
|
||||
address = address,
|
||||
item = YieldBalanceWrapperDTO(
|
||||
balances = result,
|
||||
integrationId = requestBody.integrationId,
|
||||
addresses = requestBody.addresses,
|
||||
),
|
||||
safeApiCall(
|
||||
call = {
|
||||
val result = stakeKitApi.getSingleYieldBalance(
|
||||
integrationId = requestBody.integrationId,
|
||||
body = requestBody,
|
||||
).bind()
|
||||
|
||||
stakingBalanceStore.store(
|
||||
userWalletId = userWalletId,
|
||||
stakingID = StakingBalanceStore.StakingID(
|
||||
integrationId = requestBody.integrationId,
|
||||
address = address,
|
||||
),
|
||||
item = YieldBalanceWrapperDTO(
|
||||
balances = result,
|
||||
integrationId = requestBody.integrationId,
|
||||
addresses = requestBody.addresses,
|
||||
),
|
||||
)
|
||||
},
|
||||
onError = {
|
||||
stakingBalanceStore.storeSingleYieldBalance(
|
||||
userWalletId = userWalletId,
|
||||
item = YieldBalance.Error(integrationId = requestBody.integrationId, address = address),
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -399,7 +412,11 @@ internal class DefaultStakingRepository(
|
|||
val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network).orEmpty()
|
||||
val integrationId = integrationIdMap[getIntegrationKey(cryptoCurrency.id)]
|
||||
?: error("Could not get integrationId")
|
||||
stakingBalanceStore.get(userWalletId, address, integrationId)
|
||||
|
||||
stakingBalanceStore.get(
|
||||
userWalletId = userWalletId,
|
||||
stakingID = StakingBalanceStore.StakingID(integrationId = integrationId, address = address),
|
||||
)
|
||||
.distinctUntilChanged()
|
||||
.collectLatest {
|
||||
if (it != null) {
|
||||
|
|
@ -413,10 +430,7 @@ internal class DefaultStakingRepository(
|
|||
}
|
||||
|
||||
withContext(dispatchers.io) {
|
||||
fetchSingleYieldBalance(
|
||||
userWalletId,
|
||||
cryptoCurrency,
|
||||
)
|
||||
fetchSingleYieldBalance(userWalletId = userWalletId, cryptoCurrency = cryptoCurrency)
|
||||
}
|
||||
}.cancellable()
|
||||
|
||||
|
|
@ -431,7 +445,10 @@ internal class DefaultStakingRepository(
|
|||
val integrationId = integrationIdMap[getIntegrationKey(cryptoCurrency.id)]
|
||||
?: error("Could not get integrationId")
|
||||
|
||||
stakingBalanceStore.getSyncOrNull(userWalletId, address, integrationId)
|
||||
stakingBalanceStore.getSyncOrNull(
|
||||
userWalletId = userWalletId,
|
||||
stakingID = StakingBalanceStore.StakingID(integrationId = integrationId, address = address),
|
||||
)
|
||||
?: YieldBalance.Error(integrationId, address)
|
||||
}
|
||||
|
||||
|
|
@ -444,21 +461,7 @@ internal class DefaultStakingRepository(
|
|||
if (refresh) {
|
||||
stakingBalanceStore.refresh(
|
||||
userWalletId = userWalletId,
|
||||
addressWithIntegrationIdMap = cryptoCurrencies
|
||||
.mapNotNull { currency ->
|
||||
val addresses = walletManagersFacade.getAddresses(userWalletId, currency.network)
|
||||
val integrationId = integrationIdMap[getIntegrationKey(currency.id)]
|
||||
|
||||
if (integrationId != null) {
|
||||
addresses to integrationId
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
.flatMap { (addresses, integrationId) ->
|
||||
addresses.map { address -> integrationId to address.value }
|
||||
}
|
||||
.toMap(),
|
||||
stakingIds = cryptoCurrencies.mapStakingId(userWalletId),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -523,20 +526,52 @@ internal class DefaultStakingRepository(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun List<CryptoCurrency>.mapStakingId(
|
||||
userWalletId: UserWalletId,
|
||||
): List<StakingBalanceStore.StakingID> {
|
||||
return this
|
||||
.mapNotNull { currency ->
|
||||
val addresses = walletManagersFacade.getAddresses(userWalletId, currency.network)
|
||||
val integrationId = integrationIdMap[getIntegrationKey(currency.id)]
|
||||
|
||||
if (integrationId != null) {
|
||||
addresses to integrationId
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
.flatMap { (addresses, integrationId) ->
|
||||
addresses.map { address ->
|
||||
StakingBalanceStore.StakingID(
|
||||
integrationId = integrationId,
|
||||
address = address.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMultiYieldBalanceUpdates(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Flow<YieldBalanceList> {
|
||||
return stakingBalanceStore.get(userWalletId)
|
||||
.map(YieldBalanceListConverter::convert)
|
||||
.flowOn(dispatchers.io)
|
||||
return flow {
|
||||
stakingBalanceStore.get(
|
||||
userWalletId = userWalletId,
|
||||
stakingIds = cryptoCurrencies.mapStakingId(userWalletId),
|
||||
)
|
||||
.map(YieldBalanceListConverter::convert)
|
||||
.collect { emit(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMultiYieldBalanceUpdatesLegacy(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Flow<YieldBalanceList> = channelFlow {
|
||||
stakingBalanceStore.get(userWalletId)
|
||||
stakingBalanceStore.get(
|
||||
userWalletId = userWalletId,
|
||||
stakingIds = cryptoCurrencies.mapStakingId(userWalletId),
|
||||
)
|
||||
.onEach {
|
||||
val balances = YieldBalanceListConverter.convert(it)
|
||||
send(balances)
|
||||
|
|
@ -554,7 +589,8 @@ internal class DefaultStakingRepository(
|
|||
): YieldBalanceList = withContext(dispatchers.io) {
|
||||
fetchMultiYieldBalance(userWalletId, cryptoCurrencies)
|
||||
|
||||
stakingBalanceStore.getSyncOrNull(userWalletId)?.let(YieldBalanceListConverter::convert)
|
||||
stakingBalanceStore.getSyncOrNull(userWalletId, cryptoCurrencies.mapStakingId(userWalletId))
|
||||
?.let(YieldBalanceListConverter::convert)
|
||||
?: YieldBalanceList.Error
|
||||
}
|
||||
|
||||
|
|
@ -697,6 +733,7 @@ internal class DefaultStakingRepository(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
private companion object {
|
||||
const val YIELDS_STORE_KEY = "yields"
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,13 @@ class CachedCurrenciesStatusesOperations(
|
|||
val rawCurrenciesIds = currenciesIds.mapNotNullTo(mutableSetOf()) { it.rawCurrencyId }
|
||||
quotesRepository.fetchQuotes(rawCurrenciesIds)
|
||||
},
|
||||
async { stakingRepository.fetchMultiYieldBalance(userWalletId, currencies) },
|
||||
async {
|
||||
if (currencies.size == 1) {
|
||||
stakingRepository.fetchSingleYieldBalance(userWalletId, currencies.first())
|
||||
} else {
|
||||
stakingRepository.fetchMultiYieldBalance(userWalletId, currencies)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
.map { }
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ internal class StakingModel @Inject constructor(
|
|||
private val shareManager: ShareManager,
|
||||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
private val innerRouter: InnerStakingRouter,
|
||||
private val appRouter: AppRouter,
|
||||
appRouter: AppRouter,
|
||||
) : Model(), StakingClickIntents {
|
||||
|
||||
val uiState: StateFlow<StakingUiState> = stateController.uiState
|
||||
|
|
@ -207,6 +207,7 @@ internal class StakingModel @Inject constructor(
|
|||
|
||||
private val transactionsInProgress: CopyOnWriteArrayList<StakingTransaction> = CopyOnWriteArrayList()
|
||||
|
||||
private var actionsJobHolder: JobHolder = JobHolder()
|
||||
private var approvalJobHolder: JobHolder = JobHolder()
|
||||
private var feeJobHolder: JobHolder = JobHolder()
|
||||
private var sendTransactionJobHolder = JobHolder()
|
||||
|
|
@ -274,6 +275,7 @@ internal class StakingModel @Inject constructor(
|
|||
appCurrencyProvider = Provider { appCurrency },
|
||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
fee = gasEstimate,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
)
|
||||
updateNotifications()
|
||||
|
|
@ -293,6 +295,7 @@ internal class StakingModel @Inject constructor(
|
|||
appCurrencyProvider = Provider { appCurrency },
|
||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
fee = fee,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
)
|
||||
updateNotifications()
|
||||
|
|
@ -312,25 +315,26 @@ internal class StakingModel @Inject constructor(
|
|||
},
|
||||
onConstructError = { error ->
|
||||
stakingEventFactory.createStakingErrorAlert(error)
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer(cryptoCurrencyStatus))
|
||||
},
|
||||
onSendSuccess = { txUrl ->
|
||||
stakingAnalyticSender.sendTransactionStakingAnalytics(stateController.value)
|
||||
transactionsInProgress.clear()
|
||||
stateController.update(SetConfirmationStateCompletedTransformer(txUrl))
|
||||
stateController.update(SetConfirmationStateCompletedTransformer(txUrl, cryptoCurrencyStatus))
|
||||
},
|
||||
onSendError = { error ->
|
||||
analyticsEventHandler.send(StakingAnalyticsEvent.TransactionError)
|
||||
stakingEventFactory.createSendTransactionErrorAlert(error)
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer(cryptoCurrencyStatus))
|
||||
},
|
||||
onFeeIncreased = { increasedFee ->
|
||||
stateController.updateAll(
|
||||
SetConfirmationStateResetAssentTransformer,
|
||||
SetConfirmationStateResetAssentTransformer(cryptoCurrencyStatus),
|
||||
SetConfirmationStateAssentTransformer(
|
||||
appCurrencyProvider = Provider { appCurrency },
|
||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
fee = increasedFee,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
)
|
||||
stateController.updateEvent(
|
||||
|
|
@ -355,7 +359,9 @@ internal class StakingModel @Inject constructor(
|
|||
}
|
||||
if (!isApprovalInProgress) {
|
||||
stakingStateRouter.onPrevClick()
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
stateController.update(
|
||||
SetConfirmationStateResetAssentTransformer(cryptoCurrencyStatus = cryptoCurrencyStatus),
|
||||
)
|
||||
}
|
||||
}
|
||||
null,
|
||||
|
|
@ -545,6 +551,7 @@ internal class StakingModel @Inject constructor(
|
|||
stateController.update(SetApprovalBottomSheetTypeChangeTransformer(approveType))
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
override fun onApprovalClick() {
|
||||
modelScope.launch {
|
||||
stateController.update(
|
||||
|
|
@ -581,10 +588,13 @@ internal class StakingModel @Inject constructor(
|
|||
appCurrencyProvider = Provider { appCurrency },
|
||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
fee = TransactionFee.Single(fee),
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
)
|
||||
stakingEventFactory.createGenericErrorAlert(error.message ?: error.toString())
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
stateController.update(
|
||||
SetConfirmationStateResetAssentTransformer(cryptoCurrencyStatus = cryptoCurrencyStatus),
|
||||
)
|
||||
return@launch
|
||||
},
|
||||
ifRight = { it },
|
||||
|
|
@ -603,10 +613,13 @@ internal class StakingModel @Inject constructor(
|
|||
appCurrencyProvider = Provider { appCurrency },
|
||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
fee = TransactionFee.Single(fee),
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
)
|
||||
stakingEventFactory.createSendTransactionErrorAlert(error)
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
stateController.update(
|
||||
SetConfirmationStateResetAssentTransformer(cryptoCurrencyStatus = cryptoCurrencyStatus),
|
||||
)
|
||||
},
|
||||
ifRight = {
|
||||
stakingAnalyticSender.sendTransactionApprovalAnalytics(tokenCryptoCurrency)
|
||||
|
|
@ -851,10 +864,16 @@ internal class StakingModel @Inject constructor(
|
|||
},
|
||||
ifLeft = {
|
||||
stakingEventFactory.createGenericErrorAlert(it.toString())
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
stateController.update(
|
||||
SetConfirmationStateResetAssentTransformer(cryptoCurrencyStatus = cryptoCurrencyStatus),
|
||||
)
|
||||
},
|
||||
)
|
||||
getCurrencyStatusUpdatesUseCase(userWalletId, cryptoCurrencyId, false)
|
||||
getCurrencyStatusUpdatesUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = cryptoCurrencyId,
|
||||
isSingleWalletWithTokens = false,
|
||||
)
|
||||
.conflate()
|
||||
.distinctUntilChangedBy { it.getOrNull()?.value?.yieldBalance }
|
||||
.filter { value.currentStep == StakingStep.InitialInfo }
|
||||
|
|
@ -888,12 +907,14 @@ internal class StakingModel @Inject constructor(
|
|||
setupApprovalNeeded()
|
||||
setupIsAnyTokenStaked()
|
||||
checkIfSubtractAvailable()
|
||||
subscribeOnActionsUpdates()
|
||||
subscribeOnStepChanges()
|
||||
subscribeOnActionsUpdates(status)
|
||||
subscribeOnStepChanges(status)
|
||||
},
|
||||
ifLeft = { error ->
|
||||
stakingEventFactory.createGenericErrorAlert(error.toString())
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
stateController.update(
|
||||
SetConfirmationStateResetAssentTransformer(cryptoCurrencyStatus = cryptoCurrencyStatus),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -923,13 +944,13 @@ internal class StakingModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun subscribeOnStepChanges() {
|
||||
private fun subscribeOnStepChanges(status: CryptoCurrencyStatus) {
|
||||
uiState
|
||||
.distinctUntilChangedBy { it.currentStep }
|
||||
.onEach {
|
||||
when {
|
||||
isInitState() -> {
|
||||
updateInitialData()
|
||||
updateInitialData(status)
|
||||
balanceUpdater.initialUpdate()
|
||||
}
|
||||
isAssentState() -> {
|
||||
|
|
@ -950,32 +971,30 @@ internal class StakingModel @Inject constructor(
|
|||
.saveIn(stepChangesJobHolder)
|
||||
}
|
||||
|
||||
private fun subscribeOnActionsUpdates() {
|
||||
getActionsUseCase(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencyId = cryptoCurrencyId,
|
||||
)
|
||||
private fun subscribeOnActionsUpdates(status: CryptoCurrencyStatus) {
|
||||
getActionsUseCase(userWalletId = userWalletId, cryptoCurrencyId = cryptoCurrencyId)
|
||||
.conflate()
|
||||
.distinctUntilChanged()
|
||||
.onEach { result ->
|
||||
result.getOrNull()?.let { actions ->
|
||||
processingActions = actions
|
||||
if (isInitState()) {
|
||||
updateInitialData()
|
||||
updateInitialData(status)
|
||||
}
|
||||
}
|
||||
}
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(modelScope)
|
||||
.saveIn(actionsJobHolder)
|
||||
}
|
||||
|
||||
private fun updateInitialData() {
|
||||
private fun updateInitialData(status: CryptoCurrencyStatus) {
|
||||
stateController.updateAll(
|
||||
SetInitialDataStateTransformer(
|
||||
clickIntents = this@StakingModel,
|
||||
yield = yield,
|
||||
isAnyTokenStaked = isAnyTokenStaked,
|
||||
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
|
||||
cryptoCurrencyStatus = status,
|
||||
userWalletProvider = Provider { userWallet },
|
||||
appCurrencyProvider = Provider { appCurrency },
|
||||
balancesToShowProvider = Provider { balancesToShow },
|
||||
|
|
|
|||
|
|
@ -21,13 +21,12 @@ import org.joda.time.DateTime
|
|||
import java.util.Calendar
|
||||
|
||||
internal class BalanceItemConverter(
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val yield: Yield,
|
||||
) : Converter<BalanceItem, BalanceState?> {
|
||||
|
||||
override fun convert(value: BalanceItem): BalanceState? {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val appCurrency = appCurrencyProvider()
|
||||
val cryptoCurrency = cryptoCurrencyStatus.currency
|
||||
|
||||
|
|
|
|||
|
|
@ -20,13 +20,11 @@ import org.joda.time.DateTime
|
|||
import java.math.BigDecimal
|
||||
|
||||
internal class RewardsValidatorStateConverter(
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val yield: Yield,
|
||||
) : Converter<Unit, StakingStates.RewardsValidatorsState> {
|
||||
override fun convert(value: Unit): StakingStates.RewardsValidatorsState {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
|
||||
val yieldBalance = cryptoCurrencyStatus.value.yieldBalance
|
||||
return if (yieldBalance is YieldBalance.Data) {
|
||||
val balances = yieldBalance.balance.items
|
||||
|
|
|
|||
|
|
@ -15,18 +15,17 @@ import com.tangem.utils.converter.Converter
|
|||
import kotlinx.collections.immutable.toPersistentList
|
||||
|
||||
internal class YieldBalancesConverter(
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val balancesToShowProvider: Provider<List<BalanceItem>>,
|
||||
private val yield: Yield,
|
||||
) : Converter<Unit, InnerYieldBalanceState> {
|
||||
|
||||
private val balanceItemConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
BalanceItemConverter(cryptoCurrencyStatusProvider, appCurrencyProvider, yield)
|
||||
BalanceItemConverter(cryptoCurrencyStatus, appCurrencyProvider, yield)
|
||||
}
|
||||
|
||||
override fun convert(value: Unit): InnerYieldBalanceState {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val appCurrency = appCurrencyProvider()
|
||||
|
||||
val cryptoCurrency = cryptoCurrencyStatus.currency
|
||||
|
|
@ -68,7 +67,6 @@ internal class YieldBalancesConverter(
|
|||
.toPersistentList()
|
||||
|
||||
private fun getRewardBlockType(): Pair<RewardBlockType, Boolean> {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val blockchainId = cryptoCurrencyStatus.currency.network.id.value
|
||||
val yieldBalance = cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data
|
||||
val rewards = yieldBalance?.balance?.items
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.helpers
|
||||
|
||||
import com.tangem.domain.staking.FetchStakingYieldBalanceUseCase
|
||||
import com.tangem.domain.staking.FetchActionsUseCase
|
||||
import com.tangem.domain.staking.FetchStakingYieldBalanceUseCase
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionStatus
|
||||
import com.tangem.domain.tokens.FetchPendingTransactionsUseCase
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ internal class SetConfirmationStateAssentTransformer(
|
|||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||
private val fee: Fee,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
|
|
@ -32,7 +33,9 @@ internal class SetConfirmationStateAssentTransformer(
|
|||
appCurrency = appCurrencyProvider(),
|
||||
isFeeApproximate = false,
|
||||
),
|
||||
isPrimaryButtonEnabled = true,
|
||||
isPrimaryButtonEnabled = with(cryptoCurrencyStatus.value) {
|
||||
sources.yieldBalanceSource.isActual() && sources.networkSource.isActual()
|
||||
},
|
||||
)
|
||||
} else {
|
||||
return this
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.staking.impl.presentation.state.*
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.staking.impl.presentation.state.InnerConfirmationStakingState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.features.staking.impl.presentation.state.TransactionDoneState
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
internal class SetConfirmationStateCompletedTransformer(
|
||||
private val txUrl: String,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
|
|
@ -18,7 +23,9 @@ internal class SetConfirmationStateCompletedTransformer(
|
|||
private fun StakingStates.ConfirmationState.copyWrapped(): StakingStates.ConfirmationState {
|
||||
return if (this is StakingStates.ConfirmationState.Data) {
|
||||
copy(
|
||||
isPrimaryButtonEnabled = true,
|
||||
isPrimaryButtonEnabled = with(cryptoCurrencyStatus.value) {
|
||||
sources.yieldBalanceSource.isActual() && sources.networkSource.isActual()
|
||||
},
|
||||
innerState = InnerConfirmationStakingState.COMPLETED,
|
||||
footerText = TextReference.EMPTY,
|
||||
notifications = persistentListOf(),
|
||||
|
|
|
|||
|
|
@ -63,7 +63,9 @@ internal class SetConfirmationStateInitTransformer(
|
|||
actionType = actionType,
|
||||
balanceState = balanceState,
|
||||
confirmationState = StakingStates.ConfirmationState.Data(
|
||||
isPrimaryButtonEnabled = false,
|
||||
isPrimaryButtonEnabled = with(cryptoCurrencyStatus.value) {
|
||||
sources.yieldBalanceSource.isActual() && sources.networkSource.isActual()
|
||||
},
|
||||
innerState = InnerConfirmationStakingState.ASSENT,
|
||||
feeState = FeeState.Loading,
|
||||
notifications = persistentListOf(),
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers
|
||||
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.staking.impl.presentation.state.InnerConfirmationStakingState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal object SetConfirmationStateResetAssentTransformer : Transformer<StakingUiState> {
|
||||
internal class SetConfirmationStateResetAssentTransformer(
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
) : Transformer<StakingUiState> {
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
val confirmationState = prevState.confirmationState
|
||||
return prevState.copy(
|
||||
confirmationState = if (confirmationState is StakingStates.ConfirmationState.Data) {
|
||||
confirmationState.copy(
|
||||
isPrimaryButtonEnabled = true,
|
||||
isPrimaryButtonEnabled = with(cryptoCurrencyStatus.value) {
|
||||
sources.yieldBalanceSource.isActual() && sources.networkSource.isActual()
|
||||
},
|
||||
innerState = InnerConfirmationStakingState.ASSENT,
|
||||
)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -5,25 +5,28 @@ import com.tangem.common.ui.amountScreen.converters.AmountStateConverter
|
|||
import com.tangem.common.ui.amountScreen.models.AmountParameters
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.components.list.RoundedListWithDividersItemData
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.format.bigdecimal.percent
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.staking.model.stakekit.BalanceItem
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.state.*
|
||||
import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
||||
import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStep
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType
|
||||
import com.tangem.features.staking.impl.presentation.state.converters.RewardsValidatorStateConverter
|
||||
import com.tangem.features.staking.impl.presentation.state.converters.YieldBalancesConverter
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.getRewardScheduleText
|
||||
import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isPolkadot
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.isNullOrZero
|
||||
|
|
@ -37,7 +40,7 @@ internal class SetInitialDataStateTransformer(
|
|||
private val clickIntents: StakingClickIntents,
|
||||
private val yield: Yield,
|
||||
private val isAnyTokenStaked: Boolean,
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val userWalletProvider: Provider<UserWallet>,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val balancesToShowProvider: Provider<List<BalanceItem>>,
|
||||
|
|
@ -46,20 +49,20 @@ internal class SetInitialDataStateTransformer(
|
|||
private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter)
|
||||
|
||||
private val rewardsValidatorStateConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
RewardsValidatorStateConverter(cryptoCurrencyStatusProvider, appCurrencyProvider, yield)
|
||||
RewardsValidatorStateConverter(cryptoCurrencyStatus, appCurrencyProvider, yield)
|
||||
}
|
||||
|
||||
private val yieldBalancesConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
YieldBalancesConverter(
|
||||
cryptoCurrencyStatusProvider,
|
||||
appCurrencyProvider,
|
||||
balancesToShowProvider,
|
||||
yield,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
balancesToShowProvider = balancesToShowProvider,
|
||||
yield = yield,
|
||||
)
|
||||
}
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
val cryptoCurrency = cryptoCurrencyStatusProvider().currency
|
||||
val cryptoCurrency = cryptoCurrencyStatus.currency
|
||||
return prevState.copy(
|
||||
title = TextReference.EMPTY,
|
||||
cryptoCurrencyName = cryptoCurrency.name,
|
||||
|
|
@ -77,8 +80,12 @@ internal class SetInitialDataStateTransformer(
|
|||
|
||||
private fun createInitialInfoState(): StakingStates.InitialInfoState.Data {
|
||||
val yieldBalance = yieldBalancesConverter.convert(Unit)
|
||||
|
||||
val status = cryptoCurrencyStatus.value
|
||||
return StakingStates.InitialInfoState.Data(
|
||||
isPrimaryButtonEnabled = !cryptoCurrencyStatusProvider().value.amount.isNullOrZero(),
|
||||
isPrimaryButtonEnabled = with(status) {
|
||||
!amount.isNullOrZero() && sources.yieldBalanceSource.isActual() && sources.networkSource.isActual()
|
||||
},
|
||||
showBanner = !isAnyTokenStaked && yieldBalance == InnerYieldBalanceState.Empty,
|
||||
aprRange = getAprRange(yield.preferredValidators),
|
||||
infoItems = getInfoItems(),
|
||||
|
|
@ -92,8 +99,6 @@ internal class SetInitialDataStateTransformer(
|
|||
}
|
||||
|
||||
private fun getInfoItems(): PersistentList<RoundedListWithDividersItemData> {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
|
||||
return listOfNotNull(
|
||||
createAnnualPercentageRateItem(),
|
||||
createAvailableItem(cryptoCurrencyStatus),
|
||||
|
|
@ -187,7 +192,7 @@ internal class SetInitialDataStateTransformer(
|
|||
private fun createRewardScheduleItem(): RoundedListWithDividersItemData? {
|
||||
val endTextReference = getRewardScheduleText(
|
||||
rewardSchedule = yield.metadata.rewardSchedule,
|
||||
networkId = cryptoCurrencyStatusProvider().currency.network.id.value,
|
||||
networkId = cryptoCurrencyStatus.currency.network.id.value,
|
||||
decapitalize = false,
|
||||
) ?: return null
|
||||
|
||||
|
|
@ -200,7 +205,7 @@ internal class SetInitialDataStateTransformer(
|
|||
}
|
||||
|
||||
private fun createInitialAmountState(): AmountState {
|
||||
val cryptoBalanceValue = cryptoCurrencyStatusProvider().value
|
||||
val cryptoBalanceValue = cryptoCurrencyStatus.value
|
||||
val maxEnterAmount = EnterAmountBoundary(
|
||||
amount = cryptoBalanceValue.amount,
|
||||
fiatAmount = cryptoBalanceValue.fiatAmount,
|
||||
|
|
@ -208,7 +213,7 @@ internal class SetInitialDataStateTransformer(
|
|||
)
|
||||
return AmountStateConverter(
|
||||
clickIntents = clickIntents,
|
||||
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
|
||||
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
iconStateConverter = iconStateConverter,
|
||||
maxEnterAmount = maxEnterAmount,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ internal class SetConfirmationStateAssentApprovalTransformer(
|
|||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||
private val fee: TransactionFee,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
|
|
@ -35,7 +36,9 @@ internal class SetConfirmationStateAssentApprovalTransformer(
|
|||
appCurrency = appCurrencyProvider(),
|
||||
isFeeApproximate = false,
|
||||
),
|
||||
isPrimaryButtonEnabled = true,
|
||||
isPrimaryButtonEnabled = with(cryptoCurrencyStatus.value) {
|
||||
sources.yieldBalanceSource.isActual() && sources.networkSource.isActual()
|
||||
},
|
||||
isApprovalNeeded = true,
|
||||
)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -114,6 +114,10 @@ internal class AddStakingNotificationsTransformer(
|
|||
)
|
||||
}.toImmutableList()
|
||||
|
||||
val isActualSources = with(cryptoCurrencyStatus.value) {
|
||||
sources.yieldBalanceSource.isActual() && sources.networkSource.isActual()
|
||||
}
|
||||
|
||||
return prevState.copy(
|
||||
confirmationState = confirmationState.copy(
|
||||
notifications = notifications.toImmutableList(),
|
||||
|
|
@ -122,7 +126,7 @@ internal class AddStakingNotificationsTransformer(
|
|||
it is NotificationUM.Error ||
|
||||
it is NotificationUM.Warning.NetworkFeeUnreachable ||
|
||||
it is StakingNotification.Warning.TransactionInProgress
|
||||
},
|
||||
} && isActualSources,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,14 @@ internal class TokenDetailsBalanceSelectStateConverter(
|
|||
|
||||
override fun convert(value: TokenBalanceSegmentedButtonConfig): TokenDetailsState {
|
||||
return with(currentStateProvider()) {
|
||||
if (stakingBlocksState !is StakingBlockUM.Staked) return this
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider() ?: return this
|
||||
|
||||
if (stakingBlocksState !is StakingBlockUM.Staked &&
|
||||
stakingBlocksState !is StakingBlockUM.TemporaryUnavailable
|
||||
) {
|
||||
return this
|
||||
}
|
||||
|
||||
val yieldBalance = cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data
|
||||
val stakingCryptoAmount = yieldBalance?.getTotalWithRewardsStakingBalance()
|
||||
val stakingFiatAmount = stakingCryptoAmount?.let { cryptoCurrencyStatus.value.fiatRate?.multiply(it) }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue