Updated on 2026-08-14
This commit is contained in:
commit
e7bbd950dd
18 changed files with 217 additions and 158 deletions
|
|
@ -158,8 +158,9 @@ internal object TokensDomainModule {
|
|||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
): FetchCurrencyStatusUseCase {
|
||||
return FetchCurrencyStatusUseCase(currenciesRepository, networksRepository, quotesRepository)
|
||||
return FetchCurrencyStatusUseCase(currenciesRepository, networksRepository, quotesRepository, stakingRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ interface StakeKitApi {
|
|||
@POST("yields/balances")
|
||||
suspend fun getMultipleYieldBalances(
|
||||
@Body body: List<YieldBalanceRequestBody>,
|
||||
): ApiResponse<List<YieldBalanceWrapperDTO>>
|
||||
): ApiResponse<Set<YieldBalanceWrapperDTO>>
|
||||
|
||||
@POST("yields/{integrationId}/balances")
|
||||
suspend fun getSingleYieldBalance(
|
||||
|
|
|
|||
|
|
@ -3,49 +3,53 @@ package com.tangem.datasource.local.token
|
|||
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
internal class DefaultStakingBalanceStore(
|
||||
private val dataStore: StringKeyDataStore<List<YieldBalanceWrapperDTO>>,
|
||||
private val dataStore: StringKeyDataStore<Set<YieldBalanceWrapperDTO>>,
|
||||
) : StakingBalanceStore {
|
||||
|
||||
override fun get(): Flow<List<YieldBalanceWrapperDTO>> {
|
||||
return dataStore.get(STAKING_BALANCE_KEY)
|
||||
private val mutex = Mutex()
|
||||
|
||||
override fun get(userWalletId: UserWalletId): Flow<Set<YieldBalanceWrapperDTO>> {
|
||||
return dataStore.get(userWalletId.stringValue)
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(): List<YieldBalanceWrapperDTO>? {
|
||||
return dataStore.getSyncOrNull(STAKING_BALANCE_KEY)
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId): Set<YieldBalanceWrapperDTO>? {
|
||||
return dataStore.getSyncOrNull(userWalletId.stringValue)
|
||||
}
|
||||
|
||||
override suspend fun store(items: List<YieldBalanceWrapperDTO>) {
|
||||
return dataStore.store(STAKING_BALANCE_KEY, items)
|
||||
override suspend fun store(userWalletId: UserWalletId, items: Set<YieldBalanceWrapperDTO>) {
|
||||
mutex.withLock {
|
||||
dataStore.store(userWalletId.stringValue, items)
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(integrationId: String): Flow<List<BalanceDTO>> {
|
||||
return dataStore.get(STAKING_BALANCE_KEY)
|
||||
override fun get(userWalletId: UserWalletId, integrationId: String): Flow<List<BalanceDTO>> {
|
||||
return dataStore.get(userWalletId.stringValue)
|
||||
.map { balances ->
|
||||
balances.filter { it.integrationId == integrationId }
|
||||
.flatMap { it.balances }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(integrationId: String): List<BalanceDTO>? {
|
||||
return dataStore.getSyncOrNull(STAKING_BALANCE_KEY)
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId, integrationId: String): List<BalanceDTO>? {
|
||||
return dataStore.getSyncOrNull(userWalletId.stringValue)
|
||||
?.firstOrNull { it.integrationId == integrationId }?.balances
|
||||
}
|
||||
|
||||
override suspend fun store(integrationId: String, item: YieldBalanceWrapperDTO) {
|
||||
val balances = dataStore.getSyncOrNull(STAKING_BALANCE_KEY)
|
||||
?.toMutableList()
|
||||
?.addOrReplace(item) { item.integrationId == integrationId }
|
||||
?: listOf(item)
|
||||
override suspend fun store(userWalletId: UserWalletId, integrationId: String, item: YieldBalanceWrapperDTO) {
|
||||
mutex.withLock {
|
||||
val balances = dataStore.getSyncOrNull(userWalletId.stringValue)
|
||||
?.addOrReplace(item) { it.integrationId == integrationId }
|
||||
?: setOf(item)
|
||||
|
||||
return dataStore.store(STAKING_BALANCE_KEY, balances)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val STAKING_BALANCE_KEY = "STAKING_BALANCE_KEY"
|
||||
dataStore.store(userWalletId.stringValue, balances)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,19 +2,20 @@ package com.tangem.datasource.local.token
|
|||
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface StakingBalanceStore {
|
||||
|
||||
fun get(): Flow<List<YieldBalanceWrapperDTO>>
|
||||
fun get(userWalletId: UserWalletId): Flow<Set<YieldBalanceWrapperDTO>>
|
||||
|
||||
suspend fun getSyncOrNull(): List<YieldBalanceWrapperDTO>?
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId): Set<YieldBalanceWrapperDTO>?
|
||||
|
||||
suspend fun store(items: List<YieldBalanceWrapperDTO>)
|
||||
suspend fun store(userWalletId: UserWalletId, items: Set<YieldBalanceWrapperDTO>)
|
||||
|
||||
fun get(integrationId: String): Flow<List<BalanceDTO>>
|
||||
fun get(userWalletId: UserWalletId, integrationId: String): Flow<List<BalanceDTO>>
|
||||
|
||||
suspend fun getSyncOrNull(integrationId: String): List<BalanceDTO>?
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId, integrationId: String): List<BalanceDTO>?
|
||||
|
||||
suspend fun store(integrationId: String, item: YieldBalanceWrapperDTO)
|
||||
suspend fun store(userWalletId: UserWalletId, integrationId: String, item: YieldBalanceWrapperDTO)
|
||||
}
|
||||
|
|
@ -45,7 +45,6 @@ import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate
|
|||
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyAddress
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -261,25 +260,27 @@ internal class DefaultStakingRepository(
|
|||
|
||||
override suspend fun fetchSingleYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
address: CryptoCurrencyAddress,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
refresh: Boolean,
|
||||
) = withContext(dispatchers.io) {
|
||||
if (!stakingFeatureToggle.isStakingEnabled) return@withContext
|
||||
|
||||
val cryptoCurrency = address.cryptoCurrency
|
||||
val integrationId = integrationIdMap[cryptoCurrency.id.getIntegrationKey()] ?: return@withContext
|
||||
|
||||
val address = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network).orEmpty()
|
||||
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = getYieldBalancesKey(userWalletId),
|
||||
skipCache = refresh,
|
||||
block = {
|
||||
val requestBody = getBalanceRequestData(address.address, integrationId)
|
||||
val requestBody = getBalanceRequestData(address, integrationId)
|
||||
val result = stakeKitApi.getSingleYieldBalance(
|
||||
integrationId = requestBody.integrationId,
|
||||
body = requestBody,
|
||||
).getOrThrow()
|
||||
|
||||
stakingBalanceStore.store(
|
||||
userWalletId,
|
||||
requestBody.integrationId,
|
||||
YieldBalanceWrapperDTO(
|
||||
balances = result,
|
||||
|
|
@ -292,15 +293,15 @@ internal class DefaultStakingRepository(
|
|||
|
||||
override fun getSingleYieldBalanceFlow(
|
||||
userWalletId: UserWalletId,
|
||||
address: CryptoCurrencyAddress,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): Flow<YieldBalance> = channelFlow {
|
||||
if (!stakingFeatureToggle.isStakingEnabled) {
|
||||
send(YieldBalance.Empty)
|
||||
} else {
|
||||
launch(dispatchers.io) {
|
||||
val integrationId = integrationIdMap[address.cryptoCurrency.id.getIntegrationKey()]
|
||||
val integrationId = integrationIdMap[cryptoCurrency.id.getIntegrationKey()]
|
||||
?: error("Could not get integrationId")
|
||||
stakingBalanceStore.get(integrationId)
|
||||
stakingBalanceStore.get(userWalletId, integrationId)
|
||||
.collectLatest {
|
||||
send(
|
||||
yieldBalanceConverter.convert(
|
||||
|
|
@ -316,7 +317,7 @@ internal class DefaultStakingRepository(
|
|||
withContext(dispatchers.io) {
|
||||
fetchSingleYieldBalance(
|
||||
userWalletId,
|
||||
address,
|
||||
cryptoCurrency,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -324,16 +325,18 @@ internal class DefaultStakingRepository(
|
|||
|
||||
override suspend fun getSingleYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
address: CryptoCurrencyAddress,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): YieldBalance = withContext(dispatchers.io) {
|
||||
if (!stakingFeatureToggle.isStakingEnabled) {
|
||||
YieldBalance.Empty
|
||||
} else {
|
||||
fetchSingleYieldBalance(userWalletId, address)
|
||||
fetchSingleYieldBalance(userWalletId, cryptoCurrency)
|
||||
|
||||
val integrationId = integrationIdMap[address.cryptoCurrency.id.getIntegrationKey()]
|
||||
val integrationId = integrationIdMap[cryptoCurrency.id.getIntegrationKey()]
|
||||
?: error("Could not get integrationId")
|
||||
val result = stakingBalanceStore.getSyncOrNull(integrationId) ?: return@withContext YieldBalance.Error
|
||||
val result = stakingBalanceStore.getSyncOrNull(userWalletId, integrationId)
|
||||
?: return@withContext YieldBalance.Error
|
||||
|
||||
yieldBalanceConverter.convert(
|
||||
YieldBalanceConverter.Data(
|
||||
balance = result,
|
||||
|
|
@ -345,7 +348,7 @@ internal class DefaultStakingRepository(
|
|||
|
||||
override suspend fun fetchMultiYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
refresh: Boolean,
|
||||
) = withContext(dispatchers.io) {
|
||||
if (!stakingFeatureToggle.isStakingEnabled) return@withContext
|
||||
|
|
@ -357,23 +360,23 @@ internal class DefaultStakingRepository(
|
|||
key = getYieldBalancesKey(userWalletId),
|
||||
skipCache = refresh,
|
||||
block = {
|
||||
val result = stakeKitApi.getMultipleYieldBalances(
|
||||
addresses
|
||||
.mapNotNull { networkAddress ->
|
||||
val cryptoCurrency = networkAddress.cryptoCurrency
|
||||
val integrationId = integrationIdMap[cryptoCurrency.id.getIntegrationKey()]
|
||||
val availableCurrencies = cryptoCurrencies
|
||||
.mapNotNull { currency ->
|
||||
val address = walletManagersFacade.getDefaultAddress(userWalletId, currency.network)
|
||||
val integrationId = integrationIdMap[currency.id.getIntegrationKey()]
|
||||
|
||||
if (integrationId != null) {
|
||||
networkAddress.address to integrationId
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (integrationId != null && address != null) {
|
||||
address to integrationId
|
||||
} else {
|
||||
null
|
||||
}
|
||||
.distinct()
|
||||
.map { getBalanceRequestData(it.first, it.second) },
|
||||
).getOrThrow()
|
||||
}
|
||||
.distinct()
|
||||
.map { getBalanceRequestData(it.first, it.second) }
|
||||
.ifEmpty { return@invokeOnExpire }
|
||||
val result = stakeKitApi.getMultipleYieldBalances(availableCurrencies).getOrThrow()
|
||||
|
||||
stakingBalanceStore.store(result)
|
||||
stakingBalanceStore.store(userWalletId, result)
|
||||
},
|
||||
)
|
||||
} finally {
|
||||
|
|
@ -385,20 +388,20 @@ internal class DefaultStakingRepository(
|
|||
|
||||
override fun getMultiYieldBalanceFlow(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Flow<YieldBalanceList> = channelFlow {
|
||||
if (!stakingFeatureToggle.isStakingEnabled) {
|
||||
send(YieldBalanceList.Empty)
|
||||
} else {
|
||||
launch(dispatchers.io) {
|
||||
stakingBalanceStore.get()
|
||||
stakingBalanceStore.get(userWalletId)
|
||||
.collectLatest { send(yieldBalanceListConverter.convert(it)) }
|
||||
}
|
||||
|
||||
withContext(dispatchers.io) {
|
||||
fetchMultiYieldBalance(
|
||||
userWalletId,
|
||||
addresses,
|
||||
cryptoCurrencies,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -406,14 +409,14 @@ internal class DefaultStakingRepository(
|
|||
|
||||
override fun getMultiYieldBalanceLce(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): LceFlow<Throwable, YieldBalanceList> = lceFlow {
|
||||
if (!stakingFeatureToggle.isStakingEnabled) {
|
||||
send(YieldBalanceList.Empty)
|
||||
} else {
|
||||
launch(dispatchers.io) {
|
||||
combine(
|
||||
stakingBalanceStore.get(),
|
||||
stakingBalanceStore.get(userWalletId),
|
||||
isYieldBalanceFetching.map { it.getOrElse(userWalletId) { false } },
|
||||
) { result, isFetching ->
|
||||
val balances = yieldBalanceListConverter.convert(result)
|
||||
|
|
@ -422,7 +425,7 @@ internal class DefaultStakingRepository(
|
|||
}
|
||||
withContext(dispatchers.io) {
|
||||
catch(
|
||||
block = { fetchMultiYieldBalance(userWalletId, addresses, refresh = false) },
|
||||
block = { fetchMultiYieldBalance(userWalletId, cryptoCurrencies, refresh = false) },
|
||||
catch = { raise(it) },
|
||||
)
|
||||
}
|
||||
|
|
@ -431,13 +434,13 @@ internal class DefaultStakingRepository(
|
|||
|
||||
override suspend fun getMultiYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): YieldBalanceList = withContext(dispatchers.io) {
|
||||
if (!stakingFeatureToggle.isStakingEnabled) {
|
||||
YieldBalanceList.Empty
|
||||
} else {
|
||||
fetchMultiYieldBalance(userWalletId, addresses)
|
||||
val result = stakingBalanceStore.getSyncOrNull() ?: return@withContext YieldBalanceList.Error
|
||||
fetchMultiYieldBalance(userWalletId, cryptoCurrencies)
|
||||
val result = stakingBalanceStore.getSyncOrNull(userWalletId) ?: return@withContext YieldBalanceList.Error
|
||||
yieldBalanceListConverter.convert(result)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrap
|
|||
import com.tangem.domain.staking.model.stakekit.YieldBalanceList
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class YieldBalanceListConverter : Converter<List<YieldBalanceWrapperDTO>, YieldBalanceList> {
|
||||
internal class YieldBalanceListConverter : Converter<Set<YieldBalanceWrapperDTO>, YieldBalanceList> {
|
||||
|
||||
internal val converter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
YieldBalanceConverter()
|
||||
}
|
||||
|
||||
override fun convert(value: List<YieldBalanceWrapperDTO>): YieldBalanceList {
|
||||
override fun convert(value: Set<YieldBalanceWrapperDTO>): YieldBalanceList {
|
||||
return if (value.isEmpty()) {
|
||||
YieldBalanceList.Empty
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -376,15 +376,12 @@ class DefaultWalletManagersFacade(
|
|||
return walletManagersStore.getAllSync(userWalletId)
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"Use NetworkAddress from CryptoCurrencyStatus",
|
||||
ReplaceWith("cryptoCurrencyStatus.value.networkAddress"),
|
||||
)
|
||||
override suspend fun getAddress(userWalletId: UserWalletId, network: Network): List<Address> {
|
||||
return getAddresses(userWalletId, network).sortedBy { it.type }
|
||||
override suspend fun getDefaultAddress(userWalletId: UserWalletId, network: Network): String? {
|
||||
return getAddresses(userWalletId, network)
|
||||
.firstOrNull { it.type == AddressType.Default }
|
||||
?.value
|
||||
}
|
||||
|
||||
@Deprecated("Use NetworkAddress from CryptoCurrencyStatus")
|
||||
override suspend fun getAddresses(userWalletId: UserWalletId, network: Network): Set<Address> {
|
||||
val manager = getOrCreateWalletManager(
|
||||
userWalletId = userWalletId,
|
||||
|
|
|
|||
|
|
@ -117,20 +117,18 @@ interface WalletManagersFacade {
|
|||
suspend fun getStoredWalletManagers(userWalletId: UserWalletId): List<WalletManager>
|
||||
|
||||
/**
|
||||
* Returns ordered list of addresses for selected wallet for given currency
|
||||
* Returns default network address for selected wallet in given network
|
||||
*
|
||||
* @param userWalletId selected wallet id
|
||||
* @param network network of currency
|
||||
*/
|
||||
@Deprecated("Use NetworkAddress from CryptoCurrencyStatus")
|
||||
suspend fun getAddress(userWalletId: UserWalletId, network: Network): List<Address>
|
||||
suspend fun getDefaultAddress(userWalletId: UserWalletId, network: Network): String?
|
||||
|
||||
/** Returns list of all addresses for all currencies in selected wallet
|
||||
*
|
||||
* @param userWalletId selected wallet id
|
||||
* @param network required to create wallet manager
|
||||
*/
|
||||
@Deprecated("Use NetworkAddress from CryptoCurrencyStatus")
|
||||
suspend fun getAddresses(userWalletId: UserWalletId, network: Network): Set<Address>
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import arrow.core.raise.either
|
|||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.repositories.StakingErrorResolver
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyAddress
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
class FetchStakingYieldBalanceUseCase(
|
||||
|
|
@ -16,7 +16,7 @@ class FetchStakingYieldBalanceUseCase(
|
|||
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
address: CryptoCurrencyAddress,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
refresh: Boolean = false,
|
||||
): Either<StakingError, Unit> {
|
||||
return either {
|
||||
|
|
@ -24,7 +24,7 @@ class FetchStakingYieldBalanceUseCase(
|
|||
block = {
|
||||
stakingRepository.fetchSingleYieldBalance(
|
||||
userWalletId = userWalletId,
|
||||
address = address,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
refresh = refresh,
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import com.tangem.domain.staking.model.stakekit.StakingError
|
|||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.staking.repositories.StakingErrorResolver
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyAddress
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
|
@ -20,11 +20,11 @@ class GetStakingYieldBalanceUseCase(
|
|||
|
||||
operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
address: CryptoCurrencyAddress,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): EitherFlow<StakingError, YieldBalance> {
|
||||
return stakingRepository.getSingleYieldBalanceFlow(
|
||||
userWalletId = userWalletId,
|
||||
address = address,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
).map<YieldBalance, Either<StakingError, YieldBalance>> { it.right() }
|
||||
.catch { emit(stakingErrorResolver.resolve(it).left()) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
|
|||
import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyAddress
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -38,33 +37,33 @@ interface StakingRepository {
|
|||
|
||||
suspend fun fetchSingleYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
address: CryptoCurrencyAddress,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
refresh: Boolean = false,
|
||||
)
|
||||
|
||||
fun getSingleYieldBalanceFlow(userWalletId: UserWalletId, address: CryptoCurrencyAddress): Flow<YieldBalance>
|
||||
fun getSingleYieldBalanceFlow(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): Flow<YieldBalance>
|
||||
|
||||
suspend fun getSingleYieldBalanceSync(userWalletId: UserWalletId, address: CryptoCurrencyAddress): YieldBalance
|
||||
suspend fun getSingleYieldBalanceSync(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): YieldBalance
|
||||
|
||||
suspend fun fetchMultiYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
refresh: Boolean = false,
|
||||
)
|
||||
|
||||
fun getMultiYieldBalanceFlow(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Flow<YieldBalanceList>
|
||||
|
||||
fun getMultiYieldBalanceLce(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): LceFlow<Throwable, YieldBalanceList>
|
||||
|
||||
suspend fun getMultiYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): YieldBalanceList
|
||||
|
||||
suspend fun createAction(userWalletId: UserWalletId, network: Network, params: ActionParams): StakingAction
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class FetchCardTokenListUseCase(
|
|||
val yieldBalances = async {
|
||||
fetchYieldBalances(
|
||||
userWalletId = userWalletId,
|
||||
currencies = currencies,
|
||||
refresh = refresh,
|
||||
)
|
||||
}
|
||||
|
|
@ -77,10 +78,13 @@ class FetchCardTokenListUseCase(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun fetchYieldBalances(userWalletId: UserWalletId, refresh: Boolean) {
|
||||
val networkAddresses = networksRepository.getNetworkAddresses(userWalletId)
|
||||
private suspend fun fetchYieldBalances(
|
||||
userWalletId: UserWalletId,
|
||||
currencies: List<CryptoCurrency>,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
catch(
|
||||
block = { stakingRepository.fetchMultiYieldBalance(userWalletId, networkAddresses, refresh) },
|
||||
block = { stakingRepository.fetchMultiYieldBalance(userWalletId, currencies, refresh) },
|
||||
catch = { /* Ignore error */ },
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import arrow.core.Either
|
|||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
|
|
@ -29,6 +30,7 @@ class FetchCurrencyStatusUseCase(
|
|||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
) {
|
||||
|
||||
/**
|
||||
|
|
@ -80,8 +82,11 @@ class FetchCurrencyStatusUseCase(
|
|||
val fetchQuote = async {
|
||||
fetchQuote(currency.id, refresh)
|
||||
}
|
||||
val fetchStakingBalance = async {
|
||||
fetchStakingBalance(userWalletId, currency, refresh)
|
||||
}
|
||||
|
||||
awaitAll(fetchStatus, fetchQuote)
|
||||
awaitAll(fetchStatus, fetchQuote, fetchStakingBalance)
|
||||
}
|
||||
|
||||
private suspend fun Raise<CurrencyStatusError>.getCurrency(
|
||||
|
|
@ -122,4 +127,16 @@ class FetchCurrencyStatusUseCase(
|
|||
raise(CurrencyStatusError.DataError(it))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun Raise<CurrencyStatusError>.fetchStakingBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
catch(
|
||||
block = { stakingRepository.fetchSingleYieldBalance(userWalletId, cryptoCurrency, refresh) },
|
||||
) {
|
||||
raise(CurrencyStatusError.DataError(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -69,11 +69,10 @@ internal class CurrenciesStatusesLceOperations(
|
|||
|
||||
val (networks, currenciesIds) = getIds(nonEmptyCurrencies)
|
||||
|
||||
val addresses = networksRepository.getNetworkAddresses(userWalletId)
|
||||
combine(
|
||||
getQuotes(currenciesIds),
|
||||
getNetworksStatuses(userWalletId, networks),
|
||||
getYieldBalances(userWalletId, addresses),
|
||||
getYieldBalances(userWalletId, nonEmptyCurrencies),
|
||||
) { maybeQuotes, maybeNetworksStatuses, maybeYieldBalances ->
|
||||
val statuses = createCurrenciesStatuses(
|
||||
currencies = nonEmptyCurrencies,
|
||||
|
|
@ -196,11 +195,11 @@ internal class CurrenciesStatusesLceOperations(
|
|||
|
||||
private fun getYieldBalances(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): LceFlow<TokenListError, YieldBalanceList> {
|
||||
return stakingRepository.getMultiYieldBalanceLce(
|
||||
userWalletId = userWalletId,
|
||||
addresses = addresses,
|
||||
cryptoCurrencies = cryptoCurrencies,
|
||||
).map { maybeBalances ->
|
||||
maybeBalances.mapError { TokenListError.DataError(it) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
|
|||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
// FIXME: Refactor - [REDACTED_JIRA]
|
||||
|
|
@ -35,7 +34,7 @@ internal class CurrenciesStatusesOperations(
|
|||
val quotes = quotesRepository.getQuotesSync(currenciesIds, false).right()
|
||||
val networkStatuses =
|
||||
networksRepository.getNetworkStatusesSync(userWalletId, networks, false).right()
|
||||
val yieldBalances = getYieldBalancesSync()
|
||||
val yieldBalances = getYieldBalancesSync(nonEmptyCurrencies)
|
||||
|
||||
return createCurrenciesStatuses(nonEmptyCurrencies, quotes, networkStatuses, yieldBalances)
|
||||
},
|
||||
|
|
@ -147,7 +146,7 @@ internal class CurrenciesStatusesOperations(
|
|||
val currenciesFlow = combine(
|
||||
getQuotes(currenciesIds),
|
||||
getNetworksStatuses(networks),
|
||||
getYieldBalances(),
|
||||
getYieldBalances(nonEmptyCurrencies),
|
||||
) { maybeQuotes, maybeNetworksStatuses, maybeYieldBalances ->
|
||||
createCurrenciesStatuses(nonEmptyCurrencies, maybeQuotes, maybeNetworksStatuses, maybeYieldBalances)
|
||||
}
|
||||
|
|
@ -385,25 +384,23 @@ internal class CurrenciesStatusesOperations(
|
|||
.onEmpty { emit(Error.EmptyNetworksStatuses.left()) }
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun getYieldBalances(): EitherFlow<Error, YieldBalanceList> {
|
||||
return networksRepository.getNetworkAddressesFlow(userWalletId).flatMapLatest { addresses ->
|
||||
stakingRepository.getMultiYieldBalanceFlow(
|
||||
userWalletId = userWalletId,
|
||||
addresses = addresses,
|
||||
).map<YieldBalanceList, Either<Error, YieldBalanceList>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
|
||||
}
|
||||
private fun getYieldBalances(cryptoCurrencies: List<CryptoCurrency>): Flow<Either<Error, YieldBalanceList>> {
|
||||
return stakingRepository.getMultiYieldBalanceFlow(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencies = cryptoCurrencies,
|
||||
).map<YieldBalanceList, Either<Error, YieldBalanceList>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
|
||||
}
|
||||
|
||||
private suspend fun getYieldBalancesSync(): Either<Error.EmptyYieldBalances, YieldBalanceList> {
|
||||
private suspend fun getYieldBalancesSync(
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Either<Error.EmptyYieldBalances, YieldBalanceList> {
|
||||
return catch(
|
||||
block = {
|
||||
val networkAddresses = networksRepository.getNetworkAddresses(userWalletId)
|
||||
stakingRepository.getMultiYieldBalanceSync(
|
||||
userWalletId,
|
||||
networkAddresses,
|
||||
cryptoCurrencies,
|
||||
).right()
|
||||
},
|
||||
catch = {
|
||||
|
|
@ -417,10 +414,9 @@ internal class CurrenciesStatusesOperations(
|
|||
): Either<Error.EmptyYieldBalances, YieldBalance> {
|
||||
return catch(
|
||||
block = {
|
||||
val address = networksRepository.getNetworkAddress(userWalletId, cryptoCurrency)
|
||||
stakingRepository.getSingleYieldBalanceSync(
|
||||
userWalletId,
|
||||
address,
|
||||
cryptoCurrency,
|
||||
).right()
|
||||
},
|
||||
catch = {
|
||||
|
|
@ -429,19 +425,13 @@ internal class CurrenciesStatusesOperations(
|
|||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun getYieldBalance(cryptoCurrency: CryptoCurrency): EitherFlow<Error, YieldBalance> {
|
||||
return networksRepository.getNetworkAddressFlow(
|
||||
userWalletId,
|
||||
cryptoCurrency,
|
||||
).flatMapLatest { address ->
|
||||
stakingRepository.getSingleYieldBalanceFlow(
|
||||
userWalletId = userWalletId,
|
||||
address = address,
|
||||
).map<YieldBalance, Either<Error, YieldBalance>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
|
||||
}
|
||||
return stakingRepository.getSingleYieldBalanceFlow(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
).map<YieldBalance, Either<Error, YieldBalance>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
|
||||
}
|
||||
|
||||
private fun getIds(
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import com.tangem.domain.staking.model.stakekit.action.StakingActionType
|
|||
import com.tangem.domain.staking.model.stakekit.transaction.*
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyAddress
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -118,7 +117,7 @@ class MockStakingRepository : StakingRepository {
|
|||
|
||||
override suspend fun fetchSingleYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
address: CryptoCurrencyAddress,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
/* no-op */
|
||||
|
|
@ -126,19 +125,19 @@ class MockStakingRepository : StakingRepository {
|
|||
|
||||
override fun getSingleYieldBalanceFlow(
|
||||
userWalletId: UserWalletId,
|
||||
address: CryptoCurrencyAddress,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): Flow<YieldBalance> = channelFlow {
|
||||
send(YieldBalance.Error)
|
||||
}
|
||||
|
||||
override suspend fun getSingleYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
address: CryptoCurrencyAddress,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): YieldBalance = YieldBalance.Error
|
||||
|
||||
override suspend fun fetchMultiYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
/* no-op */
|
||||
|
|
@ -146,7 +145,7 @@ class MockStakingRepository : StakingRepository {
|
|||
|
||||
override fun getMultiYieldBalanceFlow(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Flow<YieldBalanceList> = channelFlow {
|
||||
send(
|
||||
YieldBalanceList.Data(
|
||||
|
|
@ -157,7 +156,7 @@ class MockStakingRepository : StakingRepository {
|
|||
|
||||
override fun getMultiYieldBalanceLce(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): LceFlow<Throwable, YieldBalanceList> = lceFlow {
|
||||
send(
|
||||
YieldBalanceList.Data(
|
||||
|
|
@ -168,7 +167,7 @@ class MockStakingRepository : StakingRepository {
|
|||
|
||||
override suspend fun getMultiYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
addresses: List<CryptoCurrencyAddress>,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): YieldBalanceList = YieldBalanceList.Data(
|
||||
balances = listOf(YieldBalance.Error),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,16 +25,19 @@ import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
|||
import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransactionType
|
||||
import com.tangem.domain.tokens.FetchPendingTransactionsUseCase
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyAddress
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.transaction.usecase.CreateApprovalTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetAllowanceUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
|
|
@ -54,8 +57,8 @@ import com.tangem.utils.Provider
|
|||
import com.tangem.utils.coroutines.*
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
|
@ -80,12 +83,17 @@ internal class StakingViewModel @Inject constructor(
|
|||
private val submitHashUseCase: SubmitHashUseCase,
|
||||
private val isStakeMoreAvailableUseCase: IsStakeMoreAvailableUseCase,
|
||||
private val stakingYieldBalanceUseCase: FetchStakingYieldBalanceUseCase,
|
||||
private val updateDelayedNetworkStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
||||
private val fetchPendingTransactionsUseCase: FetchPendingTransactionsUseCase,
|
||||
private val getTxHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
|
||||
private val getTxHistoryItemsUseCase: GetTxHistoryItemsUseCase,
|
||||
private val createApprovalTransactionUseCase: CreateApprovalTransactionUseCase,
|
||||
private val getAllowanceUseCase: GetAllowanceUseCase,
|
||||
private val getFeeUseCase: GetFeeUseCase,
|
||||
private val isApproveNeededUseCase: IsApproveNeededUseCase,
|
||||
private val clipboardManager: ClipboardManager,
|
||||
private val vibratorHapticManager: VibratorHapticManager,
|
||||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel(), DefaultLifecycleObserver, StakingClickIntents {
|
||||
|
||||
|
|
@ -575,7 +583,7 @@ internal class StakingViewModel @Inject constructor(
|
|||
},
|
||||
ifRight = { txHash ->
|
||||
submitHash(transactionId, txHash)
|
||||
updateStakeBalance()
|
||||
scheduleUpdates()
|
||||
val txUrl = getExplorerTransactionUrlUseCase(
|
||||
txHash = txHash,
|
||||
networkId = cryptoCurrencyStatus.currency.network.id,
|
||||
|
|
@ -608,14 +616,55 @@ internal class StakingViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateStakeBalance() {
|
||||
viewModelScope.launch {
|
||||
stakingYieldBalanceUseCase(
|
||||
private fun scheduleUpdates() {
|
||||
coroutineScope.launch {
|
||||
listOf(
|
||||
// we should update network to find pending tx after 1 sec
|
||||
async {
|
||||
fetchPendingTransactionsUseCase(userWallet.walletId, setOf(cryptoCurrencyStatus.currency.network))
|
||||
},
|
||||
// we should update tx history and network for new balances
|
||||
async {
|
||||
updateStakeBalance()
|
||||
},
|
||||
async {
|
||||
updateTxHistory()
|
||||
},
|
||||
async {
|
||||
updateNetworkStatuses()
|
||||
},
|
||||
).awaitAll()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateNetworkStatuses() {
|
||||
updateDelayedNetworkStatusUseCase(
|
||||
userWalletId = userWalletId,
|
||||
network = cryptoCurrencyStatus.currency.network,
|
||||
delayMillis = BALANCE_UPDATE_DELAY,
|
||||
refresh = true,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun updateStakeBalance() {
|
||||
stakingYieldBalanceUseCase(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
refresh = true,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun updateTxHistory() {
|
||||
delay(BALANCE_UPDATE_DELAY)
|
||||
val txHistoryItemsCountEither = getTxHistoryItemsCountUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currency = cryptoCurrencyStatus.currency,
|
||||
)
|
||||
|
||||
txHistoryItemsCountEither.onRight {
|
||||
getTxHistoryItemsUseCase(
|
||||
userWalletId = userWalletId,
|
||||
address = CryptoCurrencyAddress(
|
||||
cryptoCurrencyStatus.currency,
|
||||
cryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value.orEmpty(),
|
||||
),
|
||||
currency = cryptoCurrencyStatus.currency,
|
||||
refresh = true,
|
||||
)
|
||||
}
|
||||
|
|
@ -630,5 +679,6 @@ internal class StakingViewModel @Inject constructor(
|
|||
private companion object {
|
||||
const val WHAT_IS_STAKING_ARTICLE_URL = "TODO staking"
|
||||
const val ALLOWANCE_UPDATE_DELAY = 10_000L
|
||||
const val BALANCE_UPDATE_DELAY = 11_000L
|
||||
}
|
||||
}
|
||||
|
|
@ -223,19 +223,16 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
)
|
||||
|
||||
viewModelScope.launch(dispatchers.main) {
|
||||
walletManagersFacade.getAddress(
|
||||
walletManagersFacade.getDefaultAddress(
|
||||
userWalletId = stateHolder.getSelectedWalletId(),
|
||||
network = cryptoCurrencyStatus.currency.network,
|
||||
)
|
||||
.find { it.type == AddressType.Default }
|
||||
?.value
|
||||
?.let {
|
||||
stateHolder.update(CloseBottomSheetTransformer(userWalletId = stateHolder.getSelectedWalletId()))
|
||||
)?.let {
|
||||
stateHolder.update(CloseBottomSheetTransformer(userWalletId = stateHolder.getSelectedWalletId()))
|
||||
|
||||
walletEventSender.send(
|
||||
event = WalletEvent.CopyAddress(address = it),
|
||||
)
|
||||
}
|
||||
walletEventSender.send(
|
||||
event = WalletEvent.CopyAddress(address = it),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue