Updated on 2026-08-14
This commit is contained in:
parent
b90a305734
commit
190e5ee2c6
5 changed files with 197 additions and 3 deletions
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
|
|||
import com.tangem.domain.tokens.repository.MarketCryptoCurrencyRepository
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -58,6 +59,24 @@ internal object TokensDomainModule {
|
|||
return GetCurrencyStatusUpdatesUseCase(currenciesRepository, quotesRepository, networksRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetCurrencyWarningsUseCase(
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetCurrencyWarningsUseCase {
|
||||
return GetCurrencyWarningsUseCase(
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetPrimaryCurrencyUseCase(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.tangem.domain.walletmanager
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider
|
||||
import com.tangem.blockchain.blockchains.solana.RentProvider
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.address.Address
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
|
|
@ -13,14 +13,17 @@ import com.tangem.domain.common.util.hasDerivation
|
|||
import com.tangem.domain.demo.DemoConfig
|
||||
import com.tangem.domain.tokens.models.CryptoCurrency
|
||||
import com.tangem.domain.tokens.models.Network
|
||||
import com.tangem.domain.tokens.models.warnings.CryptoCurrencyWarning
|
||||
import com.tangem.domain.txhistory.models.PaginationWrapper
|
||||
import com.tangem.domain.txhistory.models.TxHistoryItem
|
||||
import com.tangem.domain.txhistory.models.TxHistoryState
|
||||
import com.tangem.domain.walletmanager.model.UpdateWalletManagerResult
|
||||
import com.tangem.domain.walletmanager.utils.*
|
||||
import com.tangem.domain.walletmanager.utils.WalletManagerFactory
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
|
||||
// FIXME: Move to its own module and make internal
|
||||
@Deprecated("Inject the WalletManagerFacade interface using DI instead")
|
||||
|
|
@ -218,6 +221,49 @@ class DefaultWalletManagersFacade(
|
|||
.orEmpty()
|
||||
}
|
||||
|
||||
override suspend fun getRentInfo(userWalletId: UserWalletId, network: Network): CryptoCurrencyWarning.Rent? {
|
||||
val userWallet = getUserWallet(userWalletId)
|
||||
val blockchain = Blockchain.fromId(network.id.value)
|
||||
val manager = getOrCreateWalletManager(
|
||||
userWallet = userWallet,
|
||||
blockchain = blockchain,
|
||||
derivationPath = network.derivationPath.value,
|
||||
)
|
||||
if (manager !is RentProvider) return null
|
||||
|
||||
return when (val result = manager.minimalBalanceForRentExemption()) {
|
||||
is Result.Success -> {
|
||||
val balance = manager.wallet.fundsAvailable(AmountType.Coin)
|
||||
val outgoingTxs = manager.wallet.recentTransactions
|
||||
.filter { it.sourceAddress == manager.wallet.address && it.amount.type == AmountType.Coin }
|
||||
|
||||
val rentExempt = result.data
|
||||
val setRent = if (outgoingTxs.isEmpty()) {
|
||||
balance < rentExempt
|
||||
} else {
|
||||
val outgoingAmount = outgoingTxs.sumOf { it.amount.value ?: BigDecimal.ZERO }
|
||||
val rest = balance.minus(outgoingAmount)
|
||||
balance < rest
|
||||
}
|
||||
|
||||
if (setRent) CryptoCurrencyWarning.Rent(manager.rentAmount(), rentExempt) else null
|
||||
}
|
||||
is Result.Failure -> null
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getExistentialDeposit(userWalletId: UserWalletId, network: Network): BigDecimal? {
|
||||
val userWallet = getUserWallet(userWalletId)
|
||||
val blockchain = Blockchain.fromId(network.id.value)
|
||||
val manager = getOrCreateWalletManager(
|
||||
userWallet = userWallet,
|
||||
blockchain = blockchain,
|
||||
derivationPath = network.derivationPath.value,
|
||||
)
|
||||
|
||||
return if (manager is ExistentialDepositProvider) manager.getExistentialDeposit() else null
|
||||
}
|
||||
|
||||
private fun updateWalletManagerTokensIfNeeded(walletManager: WalletManager, tokens: Set<CryptoCurrency.Token>) {
|
||||
if (tokens.isEmpty()) return
|
||||
|
||||
|
|
|
|||
|
|
@ -3,14 +3,17 @@ package com.tangem.domain.walletmanager
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.address.Address
|
||||
import com.tangem.blockchain.blockchains.solana.RentProvider
|
||||
import com.tangem.domain.tokens.models.CryptoCurrency
|
||||
import com.tangem.domain.tokens.models.Network
|
||||
import com.tangem.domain.tokens.models.warnings.CryptoCurrencyWarning
|
||||
import com.tangem.domain.txhistory.models.PaginationWrapper
|
||||
import com.tangem.domain.txhistory.models.TxHistoryItem
|
||||
import com.tangem.domain.txhistory.models.TxHistoryState
|
||||
import com.tangem.domain.walletmanager.model.UpdateWalletManagerResult
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import java.math.BigDecimal
|
||||
|
||||
// TODO: Move to its own module
|
||||
/**
|
||||
|
|
@ -79,4 +82,18 @@ interface WalletManagersFacade {
|
|||
* @param network network of currency
|
||||
*/
|
||||
suspend fun getAddress(userWalletId: UserWalletId, network: Network): List<Address>
|
||||
|
||||
/**
|
||||
* Returns info about rent if wallet manager implemented [RentProvider], otherwise null
|
||||
*
|
||||
* @param userWalletId selected wallet id
|
||||
* @param network network of currency
|
||||
*/
|
||||
suspend fun getRentInfo(userWalletId: UserWalletId, network: Network): CryptoCurrencyWarning.Rent?
|
||||
|
||||
/**
|
||||
* Returns value which indicates if the account balance drops below the existential deposit value, it will be
|
||||
* deactivated and any remaining funds will be destroyed.
|
||||
*/
|
||||
suspend fun getExistentialDeposit(userWalletId: UserWalletId, network: Network): BigDecimal?
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.domain.tokens.models.warnings
|
||||
|
||||
import com.tangem.domain.tokens.models.CryptoCurrency
|
||||
import java.math.BigDecimal
|
||||
|
||||
sealed class CryptoCurrencyWarning {
|
||||
|
||||
data class ExistentialDeposit(
|
||||
val currencyName: String,
|
||||
val edStringValueWithSymbol: String,
|
||||
) : CryptoCurrencyWarning()
|
||||
|
||||
data class BalanceNotEnoughForFee(
|
||||
val currency: CryptoCurrency,
|
||||
val blockchainFullName: String,
|
||||
val blockchainSymbol: String,
|
||||
) : CryptoCurrencyWarning()
|
||||
|
||||
object SomeNetworksUnreachable : CryptoCurrencyWarning()
|
||||
|
||||
/**
|
||||
* Represents wallet blockchain rent
|
||||
* @param rent Amount that will be charged in overtime if the blockchain does not have an amount greater than
|
||||
* the [exemptionAmount]
|
||||
* @param exemptionAmount Amount that should be on the blockchain balance not to pay rent
|
||||
*/
|
||||
data class Rent(val rent: BigDecimal, val exemptionAmount: BigDecimal) : CryptoCurrencyWarning()
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import com.tangem.domain.tokens.models.CryptoCurrency
|
||||
import com.tangem.domain.tokens.models.Network
|
||||
import com.tangem.domain.tokens.models.warnings.CryptoCurrencyWarning
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
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.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
import java.math.BigDecimal
|
||||
|
||||
class GetCurrencyWarningsUseCase(
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(userWallet: UserWallet, currency: CryptoCurrency): Flow<Set<CryptoCurrencyWarning>> {
|
||||
return combine(
|
||||
getFeeWarningFlow(
|
||||
userWalletId = userWallet.walletId,
|
||||
networkId = currency.network.id,
|
||||
currencyId = currency.id,
|
||||
),
|
||||
flowOf(walletManagersFacade.getRentInfo(userWallet.walletId, currency.network)),
|
||||
flowOf(walletManagersFacade.getExistentialDeposit(userWallet.walletId, currency.network)),
|
||||
) { maybeFeeWarning, maybeRentWarning, maybeEdWarning ->
|
||||
setOfNotNull(
|
||||
maybeRentWarning,
|
||||
maybeEdWarning?.let {
|
||||
CryptoCurrencyWarning.ExistentialDeposit(
|
||||
currencyName = currency.name,
|
||||
edStringValueWithSymbol = "${it.toPlainString()} ${currency.symbol}",
|
||||
)
|
||||
},
|
||||
maybeFeeWarning,
|
||||
)
|
||||
}.flowOn(dispatchers.io)
|
||||
}
|
||||
|
||||
private suspend fun getFeeWarningFlow(
|
||||
userWalletId: UserWalletId,
|
||||
networkId: Network.ID,
|
||||
currencyId: CryptoCurrency.ID,
|
||||
): Flow<CryptoCurrencyWarning?> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
|
||||
return combine(
|
||||
operations.getCurrencyStatusFlow(currencyId).map { it.getOrNull() },
|
||||
operations.getNetworkCoinFlow(networkId).map { it.getOrNull() },
|
||||
) { tokenStatus, coinStatus ->
|
||||
when {
|
||||
tokenStatus != null && coinStatus != null -> {
|
||||
if (!tokenStatus.value.amount.isZero() && coinStatus.value.amount.isZero()) {
|
||||
CryptoCurrencyWarning.BalanceNotEnoughForFee(
|
||||
currency = tokenStatus.currency,
|
||||
blockchainFullName = coinStatus.currency.name,
|
||||
blockchainSymbol = coinStatus.currency.symbol,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
else -> CryptoCurrencyWarning.SomeNetworksUnreachable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun BigDecimal?.isZero(): Boolean {
|
||||
return this?.compareTo(BigDecimal.ZERO) == 0
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue