Updated on 2026-08-14
This commit is contained in:
parent
cab885e39f
commit
043602ebd6
9 changed files with 987 additions and 221 deletions
|
|
@ -8,12 +8,12 @@ import com.tangem.blockchainsdk.utils.toNetworkId
|
||||||
import com.tangem.common.test.domain.card.MockScanResponseFactory
|
import com.tangem.common.test.domain.card.MockScanResponseFactory
|
||||||
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
|
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
|
||||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||||
import com.tangem.domain.wallets.derivations.DerivationStyleProvider
|
|
||||||
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
|
||||||
import com.tangem.domain.card.configs.GenericCardConfig
|
import com.tangem.domain.card.configs.GenericCardConfig
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.wallets.derivations.DerivationStyleProvider
|
||||||
|
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
|
|
@ -110,7 +110,7 @@ class MockCryptoCurrencyFactory(private val userWallet: UserWallet.Cold = defaul
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createToken(blockchain: Blockchain): CryptoCurrency {
|
fun createToken(blockchain: Blockchain): CryptoCurrency.Token {
|
||||||
return factory.createToken(
|
return factory.createToken(
|
||||||
sdkToken = Token(
|
sdkToken = Token(
|
||||||
name = "NEVER-MIND",
|
name = "NEVER-MIND",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.tangem.data.swap
|
package com.tangem.data.swap
|
||||||
|
|
||||||
import arrow.core.right
|
import arrow.core.none
|
||||||
|
import arrow.core.some
|
||||||
|
import arrow.core.toOption
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
import com.tangem.data.common.api.safeApiCall
|
import com.tangem.data.common.api.safeApiCall
|
||||||
import com.tangem.data.swap.converter.SwapDataConverter
|
import com.tangem.data.swap.converter.SwapDataConverter
|
||||||
|
|
@ -28,7 +30,7 @@ import com.tangem.domain.quotes.single.SingleQuoteStatusProducer
|
||||||
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
||||||
import com.tangem.domain.swap.SwapRepositoryV2
|
import com.tangem.domain.swap.SwapRepositoryV2
|
||||||
import com.tangem.domain.swap.models.*
|
import com.tangem.domain.swap.models.*
|
||||||
import com.tangem.domain.tokens.utils.CurrencyStatusProxyCreator
|
import com.tangem.domain.tokens.operations.CryptoCurrencyStatusFactory
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
|
|
@ -49,7 +51,6 @@ internal class DefaultSwapRepositoryV2 @Inject constructor(
|
||||||
private val dataSignatureVerifier: DataSignatureVerifier,
|
private val dataSignatureVerifier: DataSignatureVerifier,
|
||||||
private val singleQuoteStatusSupplier: SingleQuoteStatusSupplier,
|
private val singleQuoteStatusSupplier: SingleQuoteStatusSupplier,
|
||||||
private val singleQuoteStatusFetcher: SingleQuoteStatusFetcher,
|
private val singleQuoteStatusFetcher: SingleQuoteStatusFetcher,
|
||||||
private val currencyStatusProxyCreator: CurrencyStatusProxyCreator,
|
|
||||||
@NetworkMoshi moshi: Moshi,
|
@NetworkMoshi moshi: Moshi,
|
||||||
) : SwapRepositoryV2 {
|
) : SwapRepositoryV2 {
|
||||||
|
|
||||||
|
|
@ -391,17 +392,19 @@ internal class DefaultSwapRepositoryV2 @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return currencyStatusProxyCreator.createCurrencyStatus(
|
val quoteStatus = quote ?: singleQuoteStatusSupplier.getSyncOrNull(
|
||||||
|
params = SingleQuoteStatusProducer.Params(rawCurrencyId = rawCurrencyId),
|
||||||
|
)
|
||||||
|
|
||||||
|
return CryptoCurrencyStatusFactory.create(
|
||||||
currency = cryptoCurrency,
|
currency = cryptoCurrency,
|
||||||
maybeQuoteStatus = quote?.right() ?: singleQuoteStatusSupplier.getSyncOrNull(
|
|
||||||
params = SingleQuoteStatusProducer.Params(rawCurrencyId = rawCurrencyId),
|
|
||||||
).right(),
|
|
||||||
maybeNetworkStatus = NetworkStatus(
|
maybeNetworkStatus = NetworkStatus(
|
||||||
network = cryptoCurrency.network,
|
network = cryptoCurrency.network,
|
||||||
value = NetworkStatus.MissedDerivation, // Caution!!! Do not change this status
|
value = NetworkStatus.MissedDerivation, // Caution!!! Do not change this status
|
||||||
).right(),
|
).some(),
|
||||||
maybeYieldBalance = null,
|
maybeQuoteStatus = quoteStatus.toOption(),
|
||||||
).getOrNull()
|
maybeYieldBalance = none(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseTxDetails(txDetailsJson: String): TxDetails? {
|
private fun parseTxDetails(txDetailsJson: String): TxDetails? {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
||||||
import com.tangem.domain.swap.SwapErrorResolver
|
import com.tangem.domain.swap.SwapErrorResolver
|
||||||
import com.tangem.domain.swap.SwapRepositoryV2
|
import com.tangem.domain.swap.SwapRepositoryV2
|
||||||
import com.tangem.domain.swap.SwapTransactionRepository
|
import com.tangem.domain.swap.SwapTransactionRepository
|
||||||
import com.tangem.domain.tokens.utils.CurrencyStatusProxyCreator
|
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
|
@ -59,7 +58,6 @@ internal object SwapDataModule {
|
||||||
moshi = moshi,
|
moshi = moshi,
|
||||||
singleQuoteStatusSupplier = singleQuoteStatusSupplier,
|
singleQuoteStatusSupplier = singleQuoteStatusSupplier,
|
||||||
singleQuoteStatusFetcher = singleQuoteStatusFetcher,
|
singleQuoteStatusFetcher = singleQuoteStatusFetcher,
|
||||||
currencyStatusProxyCreator = CurrencyStatusProxyCreator(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ abstract class BaseCurrencyStatusOperations(
|
||||||
private val stakingIdFactory: StakingIdFactory,
|
private val stakingIdFactory: StakingIdFactory,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
protected val currencyStatusProxyCreator = CurrencyStatusProxyCreator()
|
private val currencyStatusProxyCreator = CurrencyStatusProxyCreator()
|
||||||
|
|
||||||
abstract fun getCurrenciesStatuses(userWalletId: UserWalletId): LceFlow<TokenListError, List<CryptoCurrencyStatus>>
|
abstract fun getCurrenciesStatuses(userWalletId: UserWalletId): LceFlow<TokenListError, List<CryptoCurrencyStatus>>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -171,29 +171,22 @@ class CachedCurrenciesStatusesOperations(
|
||||||
): Lce<TokenListError, List<CryptoCurrencyStatus>> = lce {
|
): Lce<TokenListError, List<CryptoCurrencyStatus>> = lce {
|
||||||
isLoading.set(isUpdating)
|
isLoading.set(isUpdating)
|
||||||
|
|
||||||
var quotesRetrievingFailed = false
|
|
||||||
|
|
||||||
val networksStatuses = maybeNetworkStatuses?.bindEither()?.toNonEmptySetOrNull()
|
val networksStatuses = maybeNetworkStatuses?.bindEither()?.toNonEmptySetOrNull()
|
||||||
val yieldBalances = maybeYieldBalances?.bindEither()
|
val yieldBalances = maybeYieldBalances?.bindEither()
|
||||||
val quotes = recover({ maybeQuotes?.bind()?.toNonEmptySetOrNull() }) {
|
val quotes = recover({ maybeQuotes?.bind()?.toNonEmptySetOrNull() }) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quotes == null) {
|
|
||||||
quotesRetrievingFailed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
currencies.map { currency ->
|
currencies.map { currency ->
|
||||||
val quote = quotes?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }
|
val quote = quotes?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }
|
||||||
val networkStatus = networksStatuses?.firstOrNull { it.network == currency.network }
|
val networkStatus = networksStatuses?.firstOrNull { it.network == currency.network }
|
||||||
val yieldBalance = findYieldBalanceOrNull(yieldBalances, currency, networkStatus)
|
val yieldBalance = findYieldBalanceOrNull(yieldBalances, currency, networkStatus)
|
||||||
|
|
||||||
val currencyStatus = currencyStatusProxyCreator.createCurrencyStatus(
|
val currencyStatus = CryptoCurrencyStatusFactory.create(
|
||||||
currency = currency,
|
currency = currency,
|
||||||
quoteStatus = quote,
|
maybeNetworkStatus = networkStatus.toOption(),
|
||||||
networkStatus = networkStatus,
|
maybeQuoteStatus = quote.toOption(),
|
||||||
yieldBalance = yieldBalance,
|
maybeYieldBalance = yieldBalance.toOption(),
|
||||||
ignoreQuote = quotesRetrievingFailed,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
currencyStatus
|
currencyStatus
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,266 @@
|
||||||
|
package com.tangem.domain.tokens.operations
|
||||||
|
|
||||||
|
import arrow.core.Option
|
||||||
|
import com.tangem.domain.models.StatusSource
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
|
import com.tangem.domain.models.network.NetworkAddress
|
||||||
|
import com.tangem.domain.models.network.NetworkStatus
|
||||||
|
import com.tangem.domain.models.network.TxInfo
|
||||||
|
import com.tangem.domain.models.quote.QuoteStatus
|
||||||
|
import com.tangem.domain.models.staking.YieldBalance
|
||||||
|
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory to create [CryptoCurrencyStatus] from [NetworkStatus], [QuoteStatus] and [YieldBalance].
|
||||||
|
*
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
object CryptoCurrencyStatusFactory {
|
||||||
|
|
||||||
|
private val QuoteStatus?.fiatRate: BigDecimal?
|
||||||
|
get() = (this?.value as? QuoteStatus.Data)?.fiatRate
|
||||||
|
|
||||||
|
private val QuoteStatus?.priceChange: BigDecimal?
|
||||||
|
get() = (this?.value as? QuoteStatus.Data)?.priceChange
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates [CryptoCurrencyStatus] from [NetworkStatus], [QuoteStatus] and [YieldBalance].
|
||||||
|
*
|
||||||
|
|
||||||
|
* @param maybeNetworkStatus An optional network status containing blockchain information.
|
||||||
|
* @param maybeQuoteStatus An optional quote status containing price information.
|
||||||
|
* @param maybeYieldBalance An optional yield balance containing staking information.
|
||||||
|
*/
|
||||||
|
fun create(
|
||||||
|
currency: CryptoCurrency,
|
||||||
|
maybeNetworkStatus: Option<NetworkStatus>,
|
||||||
|
maybeQuoteStatus: Option<QuoteStatus>,
|
||||||
|
maybeYieldBalance: Option<YieldBalance>,
|
||||||
|
): CryptoCurrencyStatus {
|
||||||
|
return CryptoCurrencyStatus(
|
||||||
|
currency = currency,
|
||||||
|
value = createStatus(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = maybeNetworkStatus,
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
maybeQuoteStatus = maybeQuoteStatus,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createStatus(
|
||||||
|
currency: CryptoCurrency,
|
||||||
|
maybeNetworkStatus: Option<NetworkStatus>,
|
||||||
|
maybeQuoteStatus: Option<QuoteStatus>,
|
||||||
|
maybeYieldBalance: Option<YieldBalance>,
|
||||||
|
): CryptoCurrencyStatus.Value {
|
||||||
|
val quoteStatus = maybeQuoteStatus.getOrNull()
|
||||||
|
|
||||||
|
return when (val status = maybeNetworkStatus.getOrNull()?.value) {
|
||||||
|
is NetworkStatus.MissedDerivation -> createMissedDerivation(quoteStatus)
|
||||||
|
is NetworkStatus.Unreachable -> createUnreachable(status, quoteStatus)
|
||||||
|
is NetworkStatus.NoAccount -> createNoAccount(status, quoteStatus)
|
||||||
|
is NetworkStatus.Verified -> createStatus(currency, status, quoteStatus, maybeYieldBalance)
|
||||||
|
null -> CryptoCurrencyStatus.Loading
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMissedDerivation(quoteStatus: QuoteStatus?): CryptoCurrencyStatus.MissedDerivation {
|
||||||
|
return CryptoCurrencyStatus.MissedDerivation(
|
||||||
|
priceChange = quoteStatus.priceChange,
|
||||||
|
fiatRate = quoteStatus.fiatRate,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createUnreachable(
|
||||||
|
status: NetworkStatus.Unreachable,
|
||||||
|
quoteStatus: QuoteStatus?,
|
||||||
|
): CryptoCurrencyStatus.Unreachable {
|
||||||
|
return CryptoCurrencyStatus.Unreachable(
|
||||||
|
priceChange = quoteStatus.priceChange,
|
||||||
|
fiatRate = quoteStatus.fiatRate,
|
||||||
|
networkAddress = status.address,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createNoAccount(
|
||||||
|
status: NetworkStatus.NoAccount,
|
||||||
|
quoteStatus: QuoteStatus?,
|
||||||
|
): CryptoCurrencyStatus.NoAccount {
|
||||||
|
return CryptoCurrencyStatus.NoAccount(
|
||||||
|
amountToCreateAccount = status.amountToCreateAccount,
|
||||||
|
fiatAmount = BigDecimal.ZERO,
|
||||||
|
priceChange = quoteStatus.priceChange,
|
||||||
|
fiatRate = quoteStatus.fiatRate,
|
||||||
|
networkAddress = status.address,
|
||||||
|
sources = CryptoCurrencyStatus.Sources(
|
||||||
|
networkSource = status.source,
|
||||||
|
quoteSource = quoteStatus?.value?.source ?: StatusSource.ACTUAL,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createStatus(
|
||||||
|
currency: CryptoCurrency,
|
||||||
|
status: NetworkStatus.Verified,
|
||||||
|
quoteStatus: QuoteStatus?,
|
||||||
|
maybeYieldBalance: Option<YieldBalance>,
|
||||||
|
): CryptoCurrencyStatus.Value {
|
||||||
|
val amount = when (val amount = status.amounts[currency.id]) {
|
||||||
|
is NetworkStatus.Amount.Loaded -> amount.value
|
||||||
|
is NetworkStatus.Amount.NotFound -> {
|
||||||
|
return createNoAmount(quoteStatus = quoteStatus)
|
||||||
|
}
|
||||||
|
null -> {
|
||||||
|
return CryptoCurrencyStatus.Loading
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val yieldBalance = maybeYieldBalance.getOrNull(id = currency.id, address = status.address)
|
||||||
|
|
||||||
|
if (currency is CryptoCurrency.Token && currency.isCustom) {
|
||||||
|
return createCustom(
|
||||||
|
id = currency.id,
|
||||||
|
status = status,
|
||||||
|
amount = amount,
|
||||||
|
quoteStatus = quoteStatus,
|
||||||
|
yieldBalance = yieldBalance,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// order is important for correct total balance calculation
|
||||||
|
return when (val quoteValue = quoteStatus?.value) {
|
||||||
|
is QuoteStatus.Empty -> {
|
||||||
|
createNoQuote(
|
||||||
|
id = currency.id,
|
||||||
|
status = status,
|
||||||
|
amount = amount,
|
||||||
|
quoteStatus = quoteStatus,
|
||||||
|
yieldBalance = yieldBalance,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is QuoteStatus.Data -> {
|
||||||
|
createLoaded(
|
||||||
|
id = currency.id,
|
||||||
|
status = status,
|
||||||
|
amount = amount,
|
||||||
|
quoteStatus = quoteValue,
|
||||||
|
yieldBalance = yieldBalance,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
null -> CryptoCurrencyStatus.Loading
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createNoAmount(quoteStatus: QuoteStatus?): CryptoCurrencyStatus.NoAmount {
|
||||||
|
return CryptoCurrencyStatus.NoAmount(
|
||||||
|
priceChange = quoteStatus.priceChange,
|
||||||
|
fiatRate = quoteStatus.fiatRate,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCustom(
|
||||||
|
id: CryptoCurrency.ID,
|
||||||
|
status: NetworkStatus.Verified,
|
||||||
|
amount: BigDecimal,
|
||||||
|
quoteStatus: QuoteStatus?,
|
||||||
|
yieldBalance: YieldBalance.Data?,
|
||||||
|
): CryptoCurrencyStatus.Custom {
|
||||||
|
return CryptoCurrencyStatus.Custom(
|
||||||
|
amount = amount,
|
||||||
|
fiatAmount = quoteStatus.fiatRate?.let { calculateFiatAmount(amount, it) },
|
||||||
|
fiatRate = quoteStatus.fiatRate,
|
||||||
|
priceChange = quoteStatus.priceChange,
|
||||||
|
hasCurrentNetworkTransactions = status.hasCurrentNetworkTransactions(),
|
||||||
|
pendingTransactions = status.getCurrentTransactions(id),
|
||||||
|
networkAddress = status.address,
|
||||||
|
yieldBalance = yieldBalance,
|
||||||
|
yieldSupplyStatus = status.getYieldSupplyStatus(id),
|
||||||
|
sources = CryptoCurrencyStatus.Sources(
|
||||||
|
networkSource = status.source,
|
||||||
|
yieldBalanceSource = yieldBalance?.source ?: StatusSource.ACTUAL,
|
||||||
|
quoteSource = quoteStatus?.value?.source ?: StatusSource.ACTUAL,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createNoQuote(
|
||||||
|
id: CryptoCurrency.ID,
|
||||||
|
status: NetworkStatus.Verified,
|
||||||
|
amount: BigDecimal,
|
||||||
|
quoteStatus: QuoteStatus?,
|
||||||
|
yieldBalance: YieldBalance.Data?,
|
||||||
|
): CryptoCurrencyStatus.NoQuote {
|
||||||
|
return CryptoCurrencyStatus.NoQuote(
|
||||||
|
amount = amount,
|
||||||
|
hasCurrentNetworkTransactions = status.hasCurrentNetworkTransactions(),
|
||||||
|
pendingTransactions = status.getCurrentTransactions(id),
|
||||||
|
networkAddress = status.address,
|
||||||
|
yieldBalance = yieldBalance,
|
||||||
|
yieldSupplyStatus = status.getYieldSupplyStatus(id),
|
||||||
|
sources = CryptoCurrencyStatus.Sources(
|
||||||
|
networkSource = status.source,
|
||||||
|
yieldBalanceSource = yieldBalance?.source ?: StatusSource.ACTUAL,
|
||||||
|
quoteSource = quoteStatus?.value?.source ?: StatusSource.ACTUAL,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createLoaded(
|
||||||
|
id: CryptoCurrency.ID,
|
||||||
|
status: NetworkStatus.Verified,
|
||||||
|
amount: BigDecimal,
|
||||||
|
quoteStatus: QuoteStatus.Data,
|
||||||
|
yieldBalance: YieldBalance.Data?,
|
||||||
|
): CryptoCurrencyStatus.Loaded {
|
||||||
|
return CryptoCurrencyStatus.Loaded(
|
||||||
|
amount = amount,
|
||||||
|
fiatAmount = calculateFiatAmount(amount, quoteStatus.fiatRate),
|
||||||
|
fiatRate = quoteStatus.fiatRate,
|
||||||
|
priceChange = quoteStatus.priceChange,
|
||||||
|
hasCurrentNetworkTransactions = status.hasCurrentNetworkTransactions(),
|
||||||
|
pendingTransactions = status.getCurrentTransactions(id),
|
||||||
|
networkAddress = status.address,
|
||||||
|
yieldBalance = yieldBalance,
|
||||||
|
yieldSupplyStatus = status.getYieldSupplyStatus(id),
|
||||||
|
sources = CryptoCurrencyStatus.Sources(
|
||||||
|
networkSource = status.source,
|
||||||
|
yieldBalanceSource = yieldBalance?.source ?: StatusSource.ACTUAL,
|
||||||
|
quoteSource = quoteStatus.source,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NetworkStatus.Verified.hasCurrentNetworkTransactions() = pendingTransactions.isNotEmpty()
|
||||||
|
|
||||||
|
private fun NetworkStatus.Verified.getCurrentTransactions(id: CryptoCurrency.ID): Set<TxInfo> {
|
||||||
|
return pendingTransactions.getOrElse(key = id, defaultValue = ::emptySet)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NetworkStatus.Verified.getYieldSupplyStatus(id: CryptoCurrency.ID): YieldSupplyStatus? {
|
||||||
|
return yieldSupplyStatuses[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Option<YieldBalance>.getOrNull(id: CryptoCurrency.ID, address: NetworkAddress): YieldBalance.Data? {
|
||||||
|
val yieldBalance = this.getOrNull() as? YieldBalance.Data ?: return null
|
||||||
|
|
||||||
|
val isCurrentAddressStaking = yieldBalance.stakingId.address == address.defaultAddress.value
|
||||||
|
val filteredTokenBalances = yieldBalance.balance.items.filter {
|
||||||
|
it.token.coinGeckoId == id.rawCurrencyId?.value
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (isCurrentAddressStaking && filteredTokenBalances.isNotEmpty()) {
|
||||||
|
yieldBalance.copy(
|
||||||
|
balance = yieldBalance.balance.copy(items = filteredTokenBalances),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateFiatAmount(amount: BigDecimal, fiatRate: BigDecimal): BigDecimal {
|
||||||
|
return amount * fiatRate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
package com.tangem.domain.tokens.operations
|
|
||||||
|
|
||||||
import com.tangem.domain.models.StatusSource
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
|
||||||
import com.tangem.domain.models.network.NetworkStatus
|
|
||||||
import com.tangem.domain.models.quote.QuoteStatus
|
|
||||||
import com.tangem.domain.models.staking.YieldBalance
|
|
||||||
import java.math.BigDecimal
|
|
||||||
|
|
||||||
internal class CurrencyStatusOperations(
|
|
||||||
private val currency: CryptoCurrency,
|
|
||||||
private val quoteStatus: QuoteStatus?,
|
|
||||||
private val networkStatus: NetworkStatus?,
|
|
||||||
private val yieldBalance: YieldBalance?,
|
|
||||||
private val ignoreQuote: Boolean,
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val QuoteStatus?.fiatRate: BigDecimal?
|
|
||||||
get() = (this?.value as? QuoteStatus.Data)?.fiatRate
|
|
||||||
|
|
||||||
private val QuoteStatus?.priceChange: BigDecimal?
|
|
||||||
get() = (this?.value as? QuoteStatus.Data)?.priceChange
|
|
||||||
|
|
||||||
fun createTokenStatus(): CryptoCurrencyStatus = CryptoCurrencyStatus(currency, createStatus())
|
|
||||||
|
|
||||||
private fun createStatus(): CryptoCurrencyStatus.Value {
|
|
||||||
return when (val status = networkStatus?.value) {
|
|
||||||
null -> CryptoCurrencyStatus.Loading
|
|
||||||
is NetworkStatus.MissedDerivation -> createMissedDerivationStatus()
|
|
||||||
is NetworkStatus.Unreachable -> createUnreachableStatus(status)
|
|
||||||
is NetworkStatus.NoAccount -> createNoAccountStatus(status)
|
|
||||||
is NetworkStatus.Verified -> createStatus(status, yieldBalance)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createMissedDerivationStatus(): CryptoCurrencyStatus.MissedDerivation =
|
|
||||||
CryptoCurrencyStatus.MissedDerivation(priceChange = quoteStatus?.priceChange, fiatRate = quoteStatus?.fiatRate)
|
|
||||||
|
|
||||||
private fun createUnreachableStatus(status: NetworkStatus.Unreachable): CryptoCurrencyStatus.Unreachable {
|
|
||||||
return CryptoCurrencyStatus.Unreachable(
|
|
||||||
priceChange = quoteStatus?.priceChange,
|
|
||||||
fiatRate = quoteStatus?.fiatRate,
|
|
||||||
networkAddress = status.address,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createNoAccountStatus(status: NetworkStatus.NoAccount): CryptoCurrencyStatus.NoAccount {
|
|
||||||
return CryptoCurrencyStatus.NoAccount(
|
|
||||||
amountToCreateAccount = status.amountToCreateAccount,
|
|
||||||
fiatAmount = if (quoteStatus == null) null else BigDecimal.ZERO,
|
|
||||||
priceChange = quoteStatus?.priceChange,
|
|
||||||
fiatRate = quoteStatus?.fiatRate,
|
|
||||||
networkAddress = status.address,
|
|
||||||
sources = CryptoCurrencyStatus.Sources(
|
|
||||||
networkSource = status.source,
|
|
||||||
quoteSource = quoteStatus?.value?.source ?: StatusSource.ACTUAL,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("CyclomaticComplexMethod", "LongMethod")
|
|
||||||
private fun createStatus(
|
|
||||||
networkStatusValue: NetworkStatus.Verified,
|
|
||||||
yieldBalance: YieldBalance?,
|
|
||||||
): CryptoCurrencyStatus.Value {
|
|
||||||
val amount = when (val amount = networkStatusValue.amounts[currency.id]) {
|
|
||||||
null -> {
|
|
||||||
return CryptoCurrencyStatus.Loading
|
|
||||||
}
|
|
||||||
is NetworkStatus.Amount.NotFound -> {
|
|
||||||
return CryptoCurrencyStatus.NoAmount(
|
|
||||||
priceChange = quoteStatus?.priceChange,
|
|
||||||
fiatRate = quoteStatus?.fiatRate,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is NetworkStatus.Amount.Loaded -> amount.value
|
|
||||||
}
|
|
||||||
|
|
||||||
val hasCurrentNetworkTransactions = networkStatusValue.pendingTransactions.isNotEmpty()
|
|
||||||
val currentTransactions = networkStatusValue.pendingTransactions.getOrElse(currency.id, ::emptySet)
|
|
||||||
val yieldBalanceData = yieldBalance as? YieldBalance.Data
|
|
||||||
val isCurrentAddressStaking =
|
|
||||||
yieldBalanceData?.stakingId?.address == networkStatusValue.address.defaultAddress.value
|
|
||||||
val filteredTokenBalances = yieldBalanceData?.balance?.items?.filter {
|
|
||||||
it.token.coinGeckoId == currency.id.rawCurrencyId?.value
|
|
||||||
}
|
|
||||||
val currentYieldBalance = if (isCurrentAddressStaking && filteredTokenBalances?.isNotEmpty() == true) {
|
|
||||||
yieldBalanceData.copy(
|
|
||||||
balance = yieldBalanceData.balance.copy(
|
|
||||||
items = filteredTokenBalances,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
val yieldSupplyStatus = networkStatusValue.yieldSupplyStatuses[currency.id]
|
|
||||||
|
|
||||||
val quoteValue = quoteStatus?.value
|
|
||||||
|
|
||||||
// order is important for correct total balance calculation
|
|
||||||
return when {
|
|
||||||
currency is CryptoCurrency.Token && currency.isCustom -> CryptoCurrencyStatus.Custom(
|
|
||||||
amount = amount,
|
|
||||||
fiatAmount = calculateFiatAmountOrNull(amount, quoteStatus?.fiatRate),
|
|
||||||
fiatRate = quoteStatus?.fiatRate,
|
|
||||||
priceChange = quoteStatus?.priceChange,
|
|
||||||
hasCurrentNetworkTransactions = hasCurrentNetworkTransactions,
|
|
||||||
pendingTransactions = currentTransactions,
|
|
||||||
networkAddress = networkStatusValue.address,
|
|
||||||
yieldBalance = currentYieldBalance,
|
|
||||||
yieldSupplyStatus = yieldSupplyStatus,
|
|
||||||
sources = CryptoCurrencyStatus.Sources(
|
|
||||||
networkSource = networkStatusValue.source,
|
|
||||||
quoteSource = quoteStatus?.value?.source ?: StatusSource.ACTUAL,
|
|
||||||
yieldBalanceSource = currentYieldBalance?.source ?: StatusSource.ACTUAL,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
quoteValue is QuoteStatus.Empty || ignoreQuote -> CryptoCurrencyStatus.NoQuote(
|
|
||||||
amount = amount,
|
|
||||||
hasCurrentNetworkTransactions = hasCurrentNetworkTransactions,
|
|
||||||
pendingTransactions = currentTransactions,
|
|
||||||
networkAddress = networkStatusValue.address,
|
|
||||||
yieldBalance = currentYieldBalance,
|
|
||||||
yieldSupplyStatus = yieldSupplyStatus,
|
|
||||||
sources = CryptoCurrencyStatus.Sources(
|
|
||||||
networkSource = networkStatusValue.source,
|
|
||||||
quoteSource = quoteStatus?.value?.source ?: StatusSource.ACTUAL,
|
|
||||||
yieldBalanceSource = currentYieldBalance?.source ?: StatusSource.ACTUAL,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
quoteValue is QuoteStatus.Data -> CryptoCurrencyStatus.Loaded(
|
|
||||||
amount = amount,
|
|
||||||
fiatAmount = calculateFiatAmount(amount, quoteValue.fiatRate),
|
|
||||||
fiatRate = quoteValue.fiatRate,
|
|
||||||
priceChange = quoteValue.priceChange,
|
|
||||||
hasCurrentNetworkTransactions = hasCurrentNetworkTransactions,
|
|
||||||
pendingTransactions = currentTransactions,
|
|
||||||
networkAddress = networkStatusValue.address,
|
|
||||||
yieldBalance = currentYieldBalance,
|
|
||||||
yieldSupplyStatus = yieldSupplyStatus,
|
|
||||||
sources = CryptoCurrencyStatus.Sources(
|
|
||||||
networkSource = networkStatusValue.source,
|
|
||||||
quoteSource = quoteValue.source,
|
|
||||||
yieldBalanceSource = currentYieldBalance?.source ?: StatusSource.ACTUAL,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else -> CryptoCurrencyStatus.Loading
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun calculateFiatAmountOrNull(amount: BigDecimal, fiatRate: BigDecimal?): BigDecimal? {
|
|
||||||
if (fiatRate == null) return null
|
|
||||||
|
|
||||||
return calculateFiatAmount(amount, fiatRate)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun calculateFiatAmount(amount: BigDecimal, fiatRate: BigDecimal): BigDecimal {
|
|
||||||
return amount * fiatRate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,7 +3,9 @@ package com.tangem.domain.tokens.utils
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import arrow.core.NonEmptyList
|
import arrow.core.NonEmptyList
|
||||||
import arrow.core.raise.either
|
import arrow.core.raise.either
|
||||||
|
import arrow.core.raise.recover
|
||||||
import arrow.core.toNonEmptySetOrNull
|
import arrow.core.toNonEmptySetOrNull
|
||||||
|
import arrow.core.toOption
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
import com.tangem.domain.models.network.NetworkStatus
|
import com.tangem.domain.models.network.NetworkStatus
|
||||||
|
|
@ -12,11 +14,11 @@ import com.tangem.domain.models.quote.QuoteStatus
|
||||||
import com.tangem.domain.models.staking.StakingID
|
import com.tangem.domain.models.staking.StakingID
|
||||||
import com.tangem.domain.models.staking.YieldBalance
|
import com.tangem.domain.models.staking.YieldBalance
|
||||||
import com.tangem.domain.staking.model.StakingIntegrationID
|
import com.tangem.domain.staking.model.StakingIntegrationID
|
||||||
|
import com.tangem.domain.tokens.operations.CryptoCurrencyStatusFactory
|
||||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations.Error
|
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations.Error
|
||||||
import com.tangem.domain.tokens.operations.CurrencyStatusOperations
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Proxy creator of [CryptoCurrencyStatus]. Used [CurrencyStatusOperations] to create statuses.
|
* Proxy creator of [CryptoCurrencyStatus]. Used [CryptoCurrencyStatusFactory] to create statuses.
|
||||||
*
|
*
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
*/
|
*/
|
||||||
|
|
@ -28,20 +30,17 @@ class CurrencyStatusProxyCreator {
|
||||||
maybeNetworkStatus: Either<Error, NetworkStatus?>,
|
maybeNetworkStatus: Either<Error, NetworkStatus?>,
|
||||||
maybeYieldBalance: Either<Error, YieldBalance>?,
|
maybeYieldBalance: Either<Error, YieldBalance>?,
|
||||||
): Either<Error, CryptoCurrencyStatus> = either {
|
): Either<Error, CryptoCurrencyStatus> = either {
|
||||||
var quoteRetrievingFailed = false
|
|
||||||
|
|
||||||
val networkStatus = maybeNetworkStatus.bind()
|
val networkStatus = maybeNetworkStatus.bind()
|
||||||
val quote = arrow.core.raise.recover({ maybeQuoteStatus.bind() }) {
|
val quote = recover(
|
||||||
quoteRetrievingFailed = true
|
block = { maybeQuoteStatus.bind() },
|
||||||
null
|
recover = { null },
|
||||||
}
|
)
|
||||||
val yieldBalance = maybeYieldBalance?.getOrNull()
|
val yieldBalance = maybeYieldBalance?.getOrNull()
|
||||||
|
|
||||||
createCurrencyStatus(
|
createCurrencyStatus(
|
||||||
currency = currency,
|
currency = currency,
|
||||||
quoteStatus = quote,
|
quoteStatus = quote,
|
||||||
networkStatus = networkStatus,
|
networkStatus = networkStatus,
|
||||||
ignoreQuote = quoteRetrievingFailed,
|
|
||||||
yieldBalance = yieldBalance,
|
yieldBalance = yieldBalance,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -52,21 +51,8 @@ class CurrencyStatusProxyCreator {
|
||||||
maybeNetworkStatuses: Either<Error, Set<NetworkStatus>>,
|
maybeNetworkStatuses: Either<Error, Set<NetworkStatus>>,
|
||||||
maybeYieldBalances: Either<Error, List<YieldBalance>>,
|
maybeYieldBalances: Either<Error, List<YieldBalance>>,
|
||||||
): Either<Error, List<CryptoCurrencyStatus>> = either {
|
): Either<Error, List<CryptoCurrencyStatus>> = either {
|
||||||
var quotesRetrievingFailed = false
|
|
||||||
|
|
||||||
val networksStatuses = maybeNetworkStatuses.bind().toNonEmptySetOrNull()
|
val networksStatuses = maybeNetworkStatuses.bind().toNonEmptySetOrNull()
|
||||||
val quoteStatuses: Set<QuoteStatus>? = maybeQuotes?.fold(
|
val quoteStatuses: Set<QuoteStatus>? = maybeQuotes?.getOrNull()?.ifEmpty { null }
|
||||||
ifLeft = {
|
|
||||||
quotesRetrievingFailed = true
|
|
||||||
null
|
|
||||||
},
|
|
||||||
ifRight = {
|
|
||||||
it.ifEmpty {
|
|
||||||
quotesRetrievingFailed = true
|
|
||||||
null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
val yieldBalances = maybeYieldBalances.getOrNull()
|
val yieldBalances = maybeYieldBalances.getOrNull()
|
||||||
|
|
||||||
|
|
@ -90,27 +76,22 @@ class CurrencyStatusProxyCreator {
|
||||||
currency = currency,
|
currency = currency,
|
||||||
quoteStatus = quote,
|
quoteStatus = quote,
|
||||||
networkStatus = networkStatus,
|
networkStatus = networkStatus,
|
||||||
ignoreQuote = quotesRetrievingFailed,
|
|
||||||
yieldBalance = yieldBalance,
|
yieldBalance = yieldBalance,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createCurrencyStatus(
|
private fun createCurrencyStatus(
|
||||||
currency: CryptoCurrency,
|
currency: CryptoCurrency,
|
||||||
quoteStatus: QuoteStatus?,
|
quoteStatus: QuoteStatus?,
|
||||||
networkStatus: NetworkStatus?,
|
networkStatus: NetworkStatus?,
|
||||||
ignoreQuote: Boolean,
|
|
||||||
yieldBalance: YieldBalance?,
|
yieldBalance: YieldBalance?,
|
||||||
): CryptoCurrencyStatus {
|
): CryptoCurrencyStatus {
|
||||||
val currencyStatusOperations = CurrencyStatusOperations(
|
return CryptoCurrencyStatusFactory.create(
|
||||||
currency = currency,
|
currency = currency,
|
||||||
quoteStatus = quoteStatus,
|
maybeNetworkStatus = networkStatus.toOption(),
|
||||||
networkStatus = networkStatus,
|
maybeQuoteStatus = quoteStatus.toOption(),
|
||||||
ignoreQuote = ignoreQuote,
|
maybeYieldBalance = yieldBalance.toOption(),
|
||||||
yieldBalance = yieldBalance,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return currencyStatusOperations.createTokenStatus()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,686 @@
|
||||||
|
package com.tangem.domain.tokens.operations
|
||||||
|
|
||||||
|
import arrow.core.none
|
||||||
|
import arrow.core.some
|
||||||
|
import com.google.common.truth.Truth
|
||||||
|
import com.tangem.blockchain.common.Blockchain
|
||||||
|
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
||||||
|
import com.tangem.domain.models.StatusSource
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||||
|
import com.tangem.domain.models.network.NetworkAddress
|
||||||
|
import com.tangem.domain.models.network.NetworkStatus
|
||||||
|
import com.tangem.domain.models.network.NetworkStatus.Amount
|
||||||
|
import com.tangem.domain.models.network.TxInfo
|
||||||
|
import com.tangem.domain.models.quote.QuoteStatus
|
||||||
|
import com.tangem.domain.models.staking.BalanceItem
|
||||||
|
import com.tangem.domain.models.staking.StakingID
|
||||||
|
import com.tangem.domain.models.staking.YieldBalance
|
||||||
|
import com.tangem.domain.models.staking.YieldBalanceItem
|
||||||
|
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
|
||||||
|
import com.tangem.domain.staking.model.StakingIntegrationID
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import org.junit.jupiter.api.Nested
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.TestInstance
|
||||||
|
import java.math.BigDecimal
|
||||||
|
|
||||||
|
/**
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
class CryptoCurrencyStatusFactoryTest {
|
||||||
|
|
||||||
|
private val cryptoCurrencyFactory = MockCryptoCurrencyFactory()
|
||||||
|
private val currency = cryptoCurrencyFactory.cardano
|
||||||
|
|
||||||
|
private val networkAddress = NetworkAddress.Single(
|
||||||
|
defaultAddress = NetworkAddress.Address(
|
||||||
|
value = "0x123",
|
||||||
|
type = NetworkAddress.Address.Type.Primary,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val fullQuote = QuoteStatus.Data(
|
||||||
|
fiatRate = 1800.0.toBigDecimal(),
|
||||||
|
priceChange = (-2.5).toBigDecimal(),
|
||||||
|
source = StatusSource.ACTUAL,
|
||||||
|
)
|
||||||
|
private val emptyQuoteStatus = QuoteStatus.Empty.toStatus()
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
inner class MissedDerivation {
|
||||||
|
|
||||||
|
private val networkStatus = NetworkStatus.MissedDerivation.toStatus()
|
||||||
|
private val maybeYieldBalance = none<YieldBalance>() // not relevant for this test
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is MissedDerivation and QuoteStatus is Data`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = fullQuote.toStatus().some(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.MissedDerivation(
|
||||||
|
fiatRate = fullQuote.fiatRate,
|
||||||
|
priceChange = fullQuote.priceChange,
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is MissedDerivation and QuoteStatus is Empty`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = emptyQuoteStatus.some(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.MissedDerivation(fiatRate = null, priceChange = null).toStatus()
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is MissedDerivation and QuoteStatus is null`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = none(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.MissedDerivation(fiatRate = null, priceChange = null).toStatus()
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
inner class Unreachable {
|
||||||
|
|
||||||
|
private val networkStatus = NetworkStatus.Unreachable(address = networkAddress).toStatus()
|
||||||
|
|
||||||
|
private val maybeYieldBalance = none<YieldBalance>() // not relevant for this test
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Unreachable and QuoteStatus is Data`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = fullQuote.toStatus().some(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.Unreachable(
|
||||||
|
fiatRate = fullQuote.fiatRate,
|
||||||
|
priceChange = fullQuote.priceChange,
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Unreachable and QuoteStatus is Empty`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = emptyQuoteStatus.some(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.Unreachable(
|
||||||
|
fiatRate = null,
|
||||||
|
priceChange = null,
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
)
|
||||||
|
.toStatus()
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Unreachable and QuoteStatus is null`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = none(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.Unreachable(
|
||||||
|
fiatRate = null,
|
||||||
|
priceChange = null,
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
).toStatus()
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
inner class NoAccount {
|
||||||
|
|
||||||
|
private val networkStatus = NetworkStatus.NoAccount(
|
||||||
|
address = networkAddress,
|
||||||
|
amountToCreateAccount = BigDecimal.ONE,
|
||||||
|
errorMessage = "error message",
|
||||||
|
source = StatusSource.ACTUAL,
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
private val maybeYieldBalance = none<YieldBalance>() // not relevant for this test
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is NoAccount and QuoteStatus is Data`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = fullQuote.toStatus().some(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.NoAccount(
|
||||||
|
amountToCreateAccount = BigDecimal.ONE,
|
||||||
|
fiatAmount = BigDecimal.ZERO,
|
||||||
|
priceChange = fullQuote.priceChange,
|
||||||
|
fiatRate = fullQuote.fiatRate,
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
sources = CryptoCurrencyStatus.Sources(),
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is NoAccount and QuoteStatus is Empty`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = emptyQuoteStatus.some(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.NoAccount(
|
||||||
|
amountToCreateAccount = BigDecimal.ONE,
|
||||||
|
fiatAmount = BigDecimal.ZERO,
|
||||||
|
priceChange = null,
|
||||||
|
fiatRate = null,
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
sources = CryptoCurrencyStatus.Sources(),
|
||||||
|
).toStatus()
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is NoAccount and QuoteStatus is null`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = none(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.NoAccount(
|
||||||
|
amountToCreateAccount = BigDecimal.ONE,
|
||||||
|
fiatAmount = BigDecimal.ZERO,
|
||||||
|
priceChange = null,
|
||||||
|
fiatRate = null,
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
sources = CryptoCurrencyStatus.Sources(),
|
||||||
|
).toStatus()
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
inner class NoAmount {
|
||||||
|
|
||||||
|
private val networkStatus = createVerified(amounts = mapOf(currency.id to Amount.NotFound)).toStatus()
|
||||||
|
|
||||||
|
private val maybeYieldBalance = none<YieldBalance>() // not relevant for this test
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Verified with Amount is NotFound and QuoteStatus is Data`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = fullQuote.toStatus().some(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.NoAmount(
|
||||||
|
priceChange = fullQuote.priceChange,
|
||||||
|
fiatRate = fullQuote.fiatRate,
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Verified with Amount is NotFound and QuoteStatus is Empty`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = emptyQuoteStatus.some(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.NoAmount(priceChange = null, fiatRate = null).toStatus()
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Verified with Amount is NotFound and QuoteStatus is null`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = none(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.NoAmount(priceChange = null, fiatRate = null).toStatus()
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
inner class Loading {
|
||||||
|
|
||||||
|
private val maybeYieldBalance = none<YieldBalance>() // not relevant for this test
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is null`() {
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = none(),
|
||||||
|
maybeQuoteStatus = none(), // not relevant for this test,
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.Loading.toStatus()
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Verified with Amount is null`() {
|
||||||
|
// Arrange
|
||||||
|
val networkStatus = createVerified().toStatus()
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = none(), // not relevant for this test,
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.Loading.toStatus()
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Verified and QuoteStatus is null`() {
|
||||||
|
// Arrange
|
||||||
|
val networkStatus = createVerified(
|
||||||
|
amounts = mapOf(currency.id to Amount.Loaded(value = BigDecimal.ZERO)),
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = none(),
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.Loading.toStatus()
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
inner class Custom {
|
||||||
|
|
||||||
|
private val currency = cryptoCurrencyFactory.createToken(blockchain = Blockchain.Cardano).copy(isCustom = true)
|
||||||
|
|
||||||
|
private val networkStatus = createVerified(
|
||||||
|
amounts = mapOf(currency.id to Amount.Loaded(value = BigDecimal.TEN)),
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Verified, QuoteStatus is null, YieldBalance is null`() {
|
||||||
|
// Arrange
|
||||||
|
val maybeQuoteStatus = none<QuoteStatus>()
|
||||||
|
val maybeYieldBalance = none<YieldBalance>()
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = maybeQuoteStatus,
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus(
|
||||||
|
currency = currency,
|
||||||
|
value = CryptoCurrencyStatus.Custom(
|
||||||
|
amount = BigDecimal.TEN,
|
||||||
|
fiatAmount = null,
|
||||||
|
fiatRate = null,
|
||||||
|
priceChange = null,
|
||||||
|
yieldBalance = null,
|
||||||
|
yieldSupplyStatus = null,
|
||||||
|
hasCurrentNetworkTransactions = false,
|
||||||
|
pendingTransactions = emptySet(),
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
sources = CryptoCurrencyStatus.Sources(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Verified, QuoteStatus is Data, YieldBalance is Data`() {
|
||||||
|
// Arrange
|
||||||
|
val yieldBalance = YieldBalance.Data(
|
||||||
|
stakingId = StakingID(
|
||||||
|
integrationId = StakingIntegrationID.Coin.Cardano.value,
|
||||||
|
address = networkAddress.defaultAddress.value,
|
||||||
|
),
|
||||||
|
source = StatusSource.ACTUAL,
|
||||||
|
balance = YieldBalanceItem(
|
||||||
|
items = listOf(
|
||||||
|
mockk<BalanceItem> {
|
||||||
|
every { this@mockk.token.coinGeckoId } returns currency.id.rawCurrencyId?.value
|
||||||
|
},
|
||||||
|
mockk<BalanceItem> {
|
||||||
|
every { this@mockk.token.coinGeckoId } returns "unknown"
|
||||||
|
},
|
||||||
|
),
|
||||||
|
integrationId = StakingIntegrationID.Coin.Cardano.value,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = fullQuote.toStatus().some(),
|
||||||
|
maybeYieldBalance = yieldBalance.some(),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus(
|
||||||
|
currency = currency,
|
||||||
|
value = CryptoCurrencyStatus.Custom(
|
||||||
|
amount = BigDecimal.TEN,
|
||||||
|
fiatAmount = BigDecimal.TEN * fullQuote.fiatRate,
|
||||||
|
fiatRate = fullQuote.fiatRate,
|
||||||
|
priceChange = fullQuote.priceChange,
|
||||||
|
yieldBalance = yieldBalance.copy(
|
||||||
|
balance = yieldBalance.balance.copy(
|
||||||
|
items = yieldBalance.balance.items.subList(0, 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
yieldSupplyStatus = null,
|
||||||
|
hasCurrentNetworkTransactions = false,
|
||||||
|
pendingTransactions = emptySet(),
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
sources = CryptoCurrencyStatus.Sources(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
inner class NoQuote {
|
||||||
|
|
||||||
|
private val pendingTransactions = mapOf(currency.id to setOf(mockk<TxInfo>()))
|
||||||
|
private val yieldSupplyStatuses = mapOf(currency.id to mockk<YieldSupplyStatus>())
|
||||||
|
|
||||||
|
private val networkStatus = createVerified(
|
||||||
|
amounts = mapOf(currency.id to Amount.Loaded(value = BigDecimal.TEN)),
|
||||||
|
pendingTransactions = pendingTransactions,
|
||||||
|
yieldSupplyStatuses = yieldSupplyStatuses,
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
private val maybeQuoteStatus = emptyQuoteStatus.some()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Verified and YieldBalance is null`() {
|
||||||
|
// Arrange
|
||||||
|
val maybeYieldBalance = none<YieldBalance>()
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = maybeQuoteStatus,
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.NoQuote(
|
||||||
|
amount = BigDecimal.TEN,
|
||||||
|
yieldBalance = null,
|
||||||
|
yieldSupplyStatus = yieldSupplyStatuses[currency.id]!!,
|
||||||
|
hasCurrentNetworkTransactions = true,
|
||||||
|
pendingTransactions = pendingTransactions[currency.id]!!,
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
sources = CryptoCurrencyStatus.Sources(),
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Verified and YieldBalance is Data`() {
|
||||||
|
// Arrange
|
||||||
|
val yieldBalance = YieldBalance.Data(
|
||||||
|
stakingId = StakingID(
|
||||||
|
integrationId = StakingIntegrationID.Coin.Cardano.value,
|
||||||
|
address = networkAddress.defaultAddress.value,
|
||||||
|
),
|
||||||
|
source = StatusSource.ACTUAL,
|
||||||
|
balance = YieldBalanceItem(
|
||||||
|
items = listOf(
|
||||||
|
mockk<BalanceItem> {
|
||||||
|
every { this@mockk.token.coinGeckoId } returns currency.id.rawCurrencyId?.value
|
||||||
|
},
|
||||||
|
mockk<BalanceItem> {
|
||||||
|
every { this@mockk.token.coinGeckoId } returns "unknown"
|
||||||
|
},
|
||||||
|
),
|
||||||
|
integrationId = StakingIntegrationID.Coin.Cardano.value,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = maybeQuoteStatus,
|
||||||
|
maybeYieldBalance = yieldBalance.some(),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.NoQuote(
|
||||||
|
amount = BigDecimal.TEN,
|
||||||
|
yieldBalance = yieldBalance.copy(
|
||||||
|
balance = yieldBalance.balance.copy(
|
||||||
|
items = yieldBalance.balance.items.subList(0, 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
yieldSupplyStatus = yieldSupplyStatuses[currency.id]!!,
|
||||||
|
hasCurrentNetworkTransactions = true,
|
||||||
|
pendingTransactions = pendingTransactions[currency.id]!!,
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
sources = CryptoCurrencyStatus.Sources(),
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
inner class Loaded {
|
||||||
|
|
||||||
|
private val networkStatus = createVerified(
|
||||||
|
amounts = mapOf(currency.id to Amount.Loaded(value = BigDecimal.TEN)),
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
private val maybeQuoteStatus = fullQuote.toStatus().some()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Verified and YieldBalance is null`() {
|
||||||
|
// Arrange
|
||||||
|
val maybeYieldBalance = none<YieldBalance>()
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = maybeQuoteStatus,
|
||||||
|
maybeYieldBalance = maybeYieldBalance,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.Loaded(
|
||||||
|
amount = BigDecimal.TEN,
|
||||||
|
fiatAmount = BigDecimal.TEN * fullQuote.fiatRate,
|
||||||
|
fiatRate = fullQuote.fiatRate,
|
||||||
|
priceChange = fullQuote.priceChange,
|
||||||
|
yieldBalance = null,
|
||||||
|
yieldSupplyStatus = null,
|
||||||
|
hasCurrentNetworkTransactions = false,
|
||||||
|
pendingTransactions = emptySet(),
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
sources = CryptoCurrencyStatus.Sources(),
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `network is Verified and YieldBalance is Data`() {
|
||||||
|
// Arrange
|
||||||
|
val yieldBalance = YieldBalance.Data(
|
||||||
|
stakingId = StakingID(
|
||||||
|
integrationId = StakingIntegrationID.Coin.Cardano.value,
|
||||||
|
address = networkAddress.defaultAddress.value,
|
||||||
|
),
|
||||||
|
source = StatusSource.ACTUAL,
|
||||||
|
balance = YieldBalanceItem(
|
||||||
|
items = listOf(
|
||||||
|
mockk<BalanceItem> {
|
||||||
|
every { this@mockk.token.coinGeckoId } returns currency.id.rawCurrencyId?.value
|
||||||
|
},
|
||||||
|
mockk<BalanceItem> {
|
||||||
|
every { this@mockk.token.coinGeckoId } returns "unknown"
|
||||||
|
},
|
||||||
|
),
|
||||||
|
integrationId = StakingIntegrationID.Coin.Cardano.value,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val actual = CryptoCurrencyStatusFactory.create(
|
||||||
|
currency = currency,
|
||||||
|
maybeNetworkStatus = networkStatus.some(),
|
||||||
|
maybeQuoteStatus = fullQuote.toStatus().some(),
|
||||||
|
maybeYieldBalance = yieldBalance.some(),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
val expected = CryptoCurrencyStatus.Loaded(
|
||||||
|
amount = BigDecimal.TEN,
|
||||||
|
fiatAmount = BigDecimal.TEN * fullQuote.fiatRate,
|
||||||
|
fiatRate = fullQuote.fiatRate,
|
||||||
|
priceChange = fullQuote.priceChange,
|
||||||
|
yieldBalance = yieldBalance.copy(
|
||||||
|
balance = yieldBalance.balance.copy(
|
||||||
|
items = yieldBalance.balance.items.subList(0, 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
yieldSupplyStatus = null,
|
||||||
|
hasCurrentNetworkTransactions = false,
|
||||||
|
pendingTransactions = emptySet(),
|
||||||
|
networkAddress = networkAddress,
|
||||||
|
sources = CryptoCurrencyStatus.Sources(),
|
||||||
|
).toStatus()
|
||||||
|
|
||||||
|
Truth.assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createVerified(
|
||||||
|
amounts: Map<CryptoCurrency.ID, Amount> = emptyMap(),
|
||||||
|
pendingTransactions: Map<CryptoCurrency.ID, Set<TxInfo>> = emptyMap(),
|
||||||
|
yieldSupplyStatuses: Map<CryptoCurrency.ID, YieldSupplyStatus?> = emptyMap(),
|
||||||
|
): NetworkStatus.Verified {
|
||||||
|
return NetworkStatus.Verified(
|
||||||
|
address = networkAddress,
|
||||||
|
amounts = amounts,
|
||||||
|
pendingTransactions = pendingTransactions,
|
||||||
|
yieldSupplyStatuses = yieldSupplyStatuses,
|
||||||
|
source = StatusSource.ACTUAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NetworkStatus.Value.toStatus(): NetworkStatus {
|
||||||
|
return NetworkStatus(network = currency.network, value = this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CryptoCurrencyStatus.Value.toStatus(): CryptoCurrencyStatus {
|
||||||
|
return CryptoCurrencyStatus(currency = currency, value = this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun QuoteStatus.Value.toStatus(): QuoteStatus {
|
||||||
|
return when (this) {
|
||||||
|
is QuoteStatus.Data -> QuoteStatus(rawCurrencyId = currency.id.rawCurrencyId!!, value = this)
|
||||||
|
is QuoteStatus.Empty -> QuoteStatus(rawCurrencyId = currency.id.rawCurrencyId!!, value = this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue