Updated on 2026-08-14
This commit is contained in:
parent
f2abb0ee1c
commit
731fd53e3d
15 changed files with 369 additions and 49 deletions
|
|
@ -1,10 +1,14 @@
|
|||
package com.tangem.data.tokens.utils
|
||||
|
||||
import com.tangem.domain.tokens.model.NetworkAddress
|
||||
import com.tangem.domain.tokens.model.NetworkStatus
|
||||
import com.tangem.domain.tokens.model.PendingTransaction
|
||||
import com.tangem.domain.tokens.models.CryptoCurrency
|
||||
import com.tangem.domain.tokens.models.Network
|
||||
import com.tangem.domain.walletmanager.model.CryptoCurrencyAmount
|
||||
import com.tangem.domain.walletmanager.model.CryptoCurrencyTransaction
|
||||
import com.tangem.domain.walletmanager.model.UpdateWalletManagerResult
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class NetworkStatusFactory {
|
||||
|
|
@ -19,10 +23,18 @@ internal class NetworkStatusFactory {
|
|||
value = when (result) {
|
||||
is UpdateWalletManagerResult.MissedDerivation -> NetworkStatus.MissedDerivation
|
||||
is UpdateWalletManagerResult.Unreachable -> NetworkStatus.Unreachable
|
||||
is UpdateWalletManagerResult.NoAccount -> NetworkStatus.NoAccount(result.amountToCreateAccount)
|
||||
is UpdateWalletManagerResult.NoAccount -> NetworkStatus.NoAccount(
|
||||
address = getNetworkAddress(result.defaultAddress, result.addresses),
|
||||
amountToCreateAccount = result.amountToCreateAccount,
|
||||
)
|
||||
is UpdateWalletManagerResult.Verified -> NetworkStatus.Verified(
|
||||
amounts = formatAmounts(result.tokensAmounts, currencies),
|
||||
hasTransactionsInProgress = result.hasTransactionsInProgress,
|
||||
address = getNetworkAddress(result.defaultAddress, result.addresses),
|
||||
amounts = formatAmounts(result.currenciesAmounts, currencies),
|
||||
pendingTransactions = formatTransactions(
|
||||
networksAddresses = result.addresses,
|
||||
transactions = result.currentTransactions,
|
||||
currencies = currencies,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -39,13 +51,91 @@ internal class NetworkStatusFactory {
|
|||
is CryptoCurrencyAmount.Coin -> currencies.singleOrNull { it is CryptoCurrency.Coin }
|
||||
is CryptoCurrencyAmount.Token -> currencies.firstOrNull {
|
||||
it is CryptoCurrency.Token &&
|
||||
it.id.rawCurrencyId == amount.id &&
|
||||
it.id.rawCurrencyId == amount.tokenId &&
|
||||
it.contractAddress == amount.tokenContractAddress
|
||||
}
|
||||
}
|
||||
|
||||
currency?.id?.let { it to amount.value }
|
||||
if (currency == null) {
|
||||
Timber.e("Unable to find cryptocurrency for amount: $amount")
|
||||
null
|
||||
} else {
|
||||
currency.id to amount.value
|
||||
}
|
||||
}
|
||||
.toMap()
|
||||
}
|
||||
|
||||
private fun formatTransactions(
|
||||
networksAddresses: Set<String>,
|
||||
transactions: Set<CryptoCurrencyTransaction>,
|
||||
currencies: Set<CryptoCurrency>,
|
||||
): Map<CryptoCurrency.ID, Set<PendingTransaction>> {
|
||||
if (transactions.isEmpty()) return emptyMap()
|
||||
|
||||
return currencies
|
||||
.asSequence()
|
||||
.map { currency ->
|
||||
val currencyTransactions = when (currency) {
|
||||
is CryptoCurrency.Coin -> transactions.filterTo(hashSetOf()) { transaction ->
|
||||
transaction is CryptoCurrencyTransaction.Coin
|
||||
}
|
||||
is CryptoCurrency.Token -> transactions.filterTo(hashSetOf()) { transaction ->
|
||||
transaction is CryptoCurrencyTransaction.Token &&
|
||||
transaction.tokenId == currency.id.rawCurrencyId &&
|
||||
transaction.tokenContractAddress == currency.contractAddress
|
||||
}
|
||||
}
|
||||
|
||||
currency.id to createCurrentTransactions(networksAddresses, currencyTransactions)
|
||||
}
|
||||
.toMap()
|
||||
}
|
||||
|
||||
private fun createCurrentTransactions(
|
||||
networksAddresses: Set<String>,
|
||||
transactions: Set<CryptoCurrencyTransaction>,
|
||||
): Set<PendingTransaction> {
|
||||
return transactions.mapNotNullTo(hashSetOf()) { createCurrentTransaction(networksAddresses, it) }
|
||||
}
|
||||
|
||||
private fun createCurrentTransaction(
|
||||
networksAddresses: Set<String>,
|
||||
transaction: CryptoCurrencyTransaction,
|
||||
): PendingTransaction? {
|
||||
val direction = when {
|
||||
transaction.toAddress in networksAddresses -> PendingTransaction.Direction.Incoming(
|
||||
fromAddress = transaction.fromAddress,
|
||||
)
|
||||
transaction.fromAddress in networksAddresses -> PendingTransaction.Direction.Outgoing(
|
||||
toAddress = transaction.toAddress,
|
||||
)
|
||||
else -> {
|
||||
Timber.e(
|
||||
"""
|
||||
Unable to find transaction direction
|
||||
|- To address: ${transaction.toAddress}
|
||||
|- From address: ${transaction.fromAddress}
|
||||
|- Network addresses: $networksAddresses
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
return PendingTransaction(
|
||||
amount = transaction.amount,
|
||||
direction = direction,
|
||||
sentAt = transaction.sentAt,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getNetworkAddress(defaultAddress: String, availableAddresses: Set<String>): NetworkAddress {
|
||||
return if (availableAddresses.size != 1) {
|
||||
NetworkAddress.Selectable(defaultAddress, availableAddresses)
|
||||
} else {
|
||||
NetworkAddress.Single(defaultAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@ dependencies {
|
|||
implementation(deps.moshi.kotlin)
|
||||
implementation(deps.timber)
|
||||
implementation(deps.kotlin.coroutines)
|
||||
implementation(deps.jodatime)
|
||||
|
||||
/** Testing libraries */
|
||||
testImplementation(deps.test.junit)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ sealed class CryptoCurrencyAmount {
|
|||
data class Coin(override val value: BigDecimal) : CryptoCurrencyAmount()
|
||||
|
||||
data class Token(
|
||||
val id: String?,
|
||||
val tokenId: String?,
|
||||
val tokenContractAddress: String,
|
||||
override val value: BigDecimal,
|
||||
) : CryptoCurrencyAmount()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.domain.walletmanager.model
|
||||
|
||||
import org.joda.time.DateTime
|
||||
import java.math.BigDecimal
|
||||
|
||||
sealed class CryptoCurrencyTransaction {
|
||||
|
||||
abstract val amount: BigDecimal
|
||||
abstract val fromAddress: String?
|
||||
abstract val toAddress: String?
|
||||
abstract val sentAt: DateTime
|
||||
|
||||
data class Coin(
|
||||
override val amount: BigDecimal,
|
||||
override val fromAddress: String?,
|
||||
override val toAddress: String?,
|
||||
override val sentAt: DateTime,
|
||||
) : CryptoCurrencyTransaction()
|
||||
|
||||
data class Token(
|
||||
val tokenId: String?,
|
||||
val tokenContractAddress: String,
|
||||
override val amount: BigDecimal,
|
||||
override val fromAddress: String?,
|
||||
override val toAddress: String?,
|
||||
override val sentAt: DateTime,
|
||||
) : CryptoCurrencyTransaction()
|
||||
}
|
||||
|
|
@ -9,9 +9,15 @@ sealed class UpdateWalletManagerResult {
|
|||
object Unreachable : UpdateWalletManagerResult()
|
||||
|
||||
data class Verified(
|
||||
val tokensAmounts: Set<CryptoCurrencyAmount>,
|
||||
val hasTransactionsInProgress: Boolean, // TODO: May be add recent transactions
|
||||
val defaultAddress: String,
|
||||
val addresses: Set<String>,
|
||||
val currenciesAmounts: Set<CryptoCurrencyAmount>,
|
||||
val currentTransactions: Set<CryptoCurrencyTransaction>,
|
||||
) : UpdateWalletManagerResult()
|
||||
|
||||
data class NoAccount(val amountToCreateAccount: BigDecimal) : UpdateWalletManagerResult()
|
||||
data class NoAccount(
|
||||
val defaultAddress: String,
|
||||
val addresses: Set<String>,
|
||||
val amountToCreateAccount: BigDecimal,
|
||||
) : UpdateWalletManagerResult()
|
||||
}
|
||||
|
|
@ -1,31 +1,39 @@
|
|||
package com.tangem.domain.walletmanager.utils
|
||||
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.address.Address
|
||||
import com.tangem.domain.common.extensions.amountToCreateAccount
|
||||
import com.tangem.domain.walletmanager.model.CryptoCurrencyAmount
|
||||
import com.tangem.domain.walletmanager.model.CryptoCurrencyTransaction
|
||||
import com.tangem.domain.walletmanager.model.UpdateWalletManagerResult
|
||||
import org.joda.time.DateTime
|
||||
import org.joda.time.DateTimeZone
|
||||
import org.joda.time.Instant
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import java.util.Calendar
|
||||
|
||||
internal class UpdateWalletManagerResultFactory {
|
||||
|
||||
fun getResult(walletManager: WalletManager): UpdateWalletManagerResult.Verified {
|
||||
val hasNotConfirmedTransactions = walletManager.wallet
|
||||
.recentTransactions
|
||||
.any { it.status != TransactionStatus.Confirmed }
|
||||
|
||||
val amounts = walletManager.wallet.amounts
|
||||
val wallet = walletManager.wallet
|
||||
|
||||
return UpdateWalletManagerResult.Verified(
|
||||
tokensAmounts = getTokensAmounts(amounts.values.toSet()),
|
||||
hasTransactionsInProgress = hasNotConfirmedTransactions,
|
||||
defaultAddress = wallet.address,
|
||||
addresses = getAvailableAddresses(wallet.addresses),
|
||||
currenciesAmounts = getTokensAmounts(wallet.amounts.values.toSet()),
|
||||
currentTransactions = getCurrentTransactions(wallet.recentTransactions.toSet()),
|
||||
)
|
||||
}
|
||||
|
||||
fun getDemoResult(walletManager: WalletManager, demoAmount: Amount): UpdateWalletManagerResult.Verified {
|
||||
val wallet = walletManager.wallet
|
||||
|
||||
return UpdateWalletManagerResult.Verified(
|
||||
tokensAmounts = getDemoTokensAmounts(demoAmount, walletManager.cardTokens),
|
||||
hasTransactionsInProgress = false,
|
||||
defaultAddress = wallet.address,
|
||||
addresses = getAvailableAddresses(wallet.addresses),
|
||||
currenciesAmounts = getDemoTokensAmounts(demoAmount, walletManager.cardTokens),
|
||||
currentTransactions = getCurrentTransactions(wallet.recentTransactions.toSet()),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -40,13 +48,17 @@ internal class UpdateWalletManagerResultFactory {
|
|||
"Unable to get required amount to create account for: $blockchain"
|
||||
}
|
||||
|
||||
return UpdateWalletManagerResult.NoAccount(amountToCreateAccount)
|
||||
return UpdateWalletManagerResult.NoAccount(
|
||||
defaultAddress = wallet.address,
|
||||
addresses = getAvailableAddresses(wallet.addresses),
|
||||
amountToCreateAccount = amountToCreateAccount,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getTokensAmounts(amounts: Set<Amount>): Set<CryptoCurrencyAmount> {
|
||||
val mutableAmounts = hashSetOf<CryptoCurrencyAmount>()
|
||||
|
||||
return amounts.mapNotNullTo(mutableAmounts, ::getTokenAmount)
|
||||
return amounts.mapNotNullTo(mutableAmounts, ::createCurrencyAmount)
|
||||
}
|
||||
|
||||
private fun getDemoTokensAmounts(demoAmount: Amount, tokens: Set<Token>): Set<CryptoCurrencyAmount> {
|
||||
|
|
@ -58,27 +70,94 @@ internal class UpdateWalletManagerResultFactory {
|
|||
}
|
||||
}
|
||||
|
||||
private fun getTokenAmount(amount: Amount): CryptoCurrencyAmount? {
|
||||
private fun getCurrentTransactions(recentTransactions: Set<TransactionData>): Set<CryptoCurrencyTransaction> {
|
||||
val unconfirmedTransactions = recentTransactions.filter {
|
||||
it.status == TransactionStatus.Unconfirmed
|
||||
}
|
||||
|
||||
return unconfirmedTransactions.mapNotNullTo(hashSetOf(), ::createCurrencyTransaction)
|
||||
}
|
||||
|
||||
private fun createCurrencyAmount(amount: Amount): CryptoCurrencyAmount? {
|
||||
return when (val type = amount.type) {
|
||||
is AmountType.Token -> CryptoCurrencyAmount.Token(
|
||||
id = type.token.id,
|
||||
tokenId = type.token.id,
|
||||
tokenContractAddress = type.token.contractAddress,
|
||||
value = getAmountValue(amount) ?: return null,
|
||||
value = getCurrencyAmountValue(amount) ?: return null,
|
||||
)
|
||||
is AmountType.Coin -> CryptoCurrencyAmount.Coin(
|
||||
value = getAmountValue(amount) ?: return null,
|
||||
value = getCurrencyAmountValue(amount) ?: return null,
|
||||
)
|
||||
is AmountType.Reserve -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAmountValue(amount: Amount): BigDecimal? {
|
||||
private fun createCurrencyTransaction(data: TransactionData): CryptoCurrencyTransaction? {
|
||||
val fromAddress = takeAddressIfNotUnknown(data.sourceAddress)
|
||||
val toAddress = takeAddressIfNotUnknown(data.destinationAddress)
|
||||
val amount = getTransactionAmountValue(data.amount) ?: return null
|
||||
val sentAt = getTransactionSentTime(data.date) ?: return null
|
||||
|
||||
return when (val type = data.amount.type) {
|
||||
is AmountType.Coin -> CryptoCurrencyTransaction.Coin(
|
||||
amount = amount,
|
||||
fromAddress = fromAddress,
|
||||
toAddress = toAddress,
|
||||
sentAt = sentAt,
|
||||
)
|
||||
is AmountType.Token -> CryptoCurrencyTransaction.Token(
|
||||
tokenId = type.token.id,
|
||||
tokenContractAddress = type.token.contractAddress,
|
||||
amount = amount,
|
||||
fromAddress = fromAddress,
|
||||
toAddress = toAddress,
|
||||
sentAt = sentAt,
|
||||
)
|
||||
is AmountType.Reserve -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAvailableAddresses(addresses: Set<Address>): Set<String> {
|
||||
return addresses.mapTo(hashSetOf()) { it.value }
|
||||
}
|
||||
|
||||
private fun getCurrencyAmountValue(amount: Amount): BigDecimal? {
|
||||
val value = amount.value
|
||||
|
||||
if (value == null) {
|
||||
Timber.e("Amount not found for currency: ${amount.currencySymbol}")
|
||||
Timber.e("Currency amount must not be null: ${amount.currencySymbol}")
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
private fun getTransactionAmountValue(amount: Amount): BigDecimal? {
|
||||
val value = amount.value
|
||||
|
||||
if (value == null) {
|
||||
Timber.e("Transaction amount must not be null: ${amount.currencySymbol}")
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
private fun getTransactionSentTime(date: Calendar?): DateTime? {
|
||||
if (date == null) {
|
||||
Timber.e("Transaction date must not be null")
|
||||
return null
|
||||
}
|
||||
|
||||
val instant = Instant.ofEpochMilli(date.timeInMillis)
|
||||
val timeZone = DateTimeZone.forTimeZone(date.timeZone)
|
||||
|
||||
return instant.toDateTime(timeZone)
|
||||
}
|
||||
|
||||
private fun takeAddressIfNotUnknown(address: String): String? {
|
||||
return address.takeIf { it.isNotBlank() && it != UNKNOWN_TRANSACTION_ADDRESS }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val UNKNOWN_TRANSACTION_ADDRESS = "unknown"
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,9 @@ dependencies {
|
|||
/** Project - Other */
|
||||
implementation(projects.core.utils)
|
||||
|
||||
/** Utils */
|
||||
implementation(deps.jodatime)
|
||||
|
||||
/** Tests */
|
||||
testImplementation(deps.test.junit)
|
||||
testImplementation(deps.test.coroutine)
|
||||
|
|
|
|||
|
|
@ -35,8 +35,11 @@ data class CryptoCurrencyStatus(
|
|||
/** The change in price of the token. */
|
||||
open val priceChange: BigDecimal? = null
|
||||
|
||||
/** Indicates if there are any transactions in progress related to the token. */
|
||||
open val hasTransactionsInProgress: Boolean = false
|
||||
/** Indicates if there are any transactions in progress related to the cryptocurrency network. */
|
||||
open val hasCurrentNetworkTransactions: Boolean = false
|
||||
|
||||
/** The pending cryptocurrency transactions. */
|
||||
open val pendingTransactions: Set<PendingTransaction> = emptySet()
|
||||
}
|
||||
|
||||
/** Represents the Loading state of a token, typically while fetching its details. */
|
||||
|
|
@ -58,15 +61,17 @@ data class CryptoCurrencyStatus(
|
|||
* @property fiatAmount The fiat equivalent of the token's amount.
|
||||
* @property fiatRate The exchange rate used for converting the token amount to fiat.
|
||||
* @property priceChange The change in price of the token.
|
||||
* @property hasTransactionsInProgress Indicates if there are any transactions in progress related to the token
|
||||
* network.
|
||||
* @property hasCurrentNetworkTransactions Indicates if there are any transactions in progress related to the
|
||||
* cryptocurrency network.
|
||||
* @property pendingTransactions The current cryptocurrency transactions.
|
||||
*/
|
||||
data class Loaded(
|
||||
override val amount: BigDecimal,
|
||||
override val fiatAmount: BigDecimal,
|
||||
override val fiatRate: BigDecimal,
|
||||
override val priceChange: BigDecimal,
|
||||
override val hasTransactionsInProgress: Boolean,
|
||||
override val hasCurrentNetworkTransactions: Boolean,
|
||||
override val pendingTransactions: Set<PendingTransaction>,
|
||||
) : Status()
|
||||
|
||||
/**
|
||||
|
|
@ -76,25 +81,30 @@ data class CryptoCurrencyStatus(
|
|||
* @property fiatAmount The fiat equivalent of the token's amount (optional).
|
||||
* @property fiatRate The exchange rate used for converting the token amount to fiat (optional).
|
||||
* @property priceChange The change in price of the token (optional).
|
||||
* @property hasTransactionsInProgress Indicates if there are any transactions in progress related to the token
|
||||
* network.
|
||||
* @property hasCurrentNetworkTransactions Indicates if there are any transactions in progress related to the
|
||||
* cryptocurrency network.
|
||||
* @property pendingTransactions The current cryptocurrency transactions.
|
||||
*/
|
||||
data class Custom(
|
||||
override val amount: BigDecimal,
|
||||
override val fiatAmount: BigDecimal?,
|
||||
override val fiatRate: BigDecimal?,
|
||||
override val priceChange: BigDecimal?,
|
||||
override val hasTransactionsInProgress: Boolean,
|
||||
override val hasCurrentNetworkTransactions: Boolean,
|
||||
override val pendingTransactions: Set<PendingTransaction>,
|
||||
) : Status()
|
||||
|
||||
/**
|
||||
* Represents a state where the token is available, but there is no current quote available for it.
|
||||
*
|
||||
* @property amount The amount of the token.
|
||||
* @property hasTransactionsInProgress Indicates if there are any transactions in progress related to the token.
|
||||
* @property hasCurrentNetworkTransactions Indicates if there are any transactions in progress related to the
|
||||
* cryptocurrency network.
|
||||
* @property pendingTransactions The current cryptocurrency transactions.
|
||||
*/
|
||||
data class NoQuote(
|
||||
override val amount: BigDecimal,
|
||||
override val hasTransactionsInProgress: Boolean,
|
||||
override val hasCurrentNetworkTransactions: Boolean,
|
||||
override val pendingTransactions: Set<PendingTransaction>,
|
||||
) : Status()
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.tangem.domain.tokens.model
|
||||
|
||||
/**
|
||||
* Represents a network address configuration.
|
||||
*/
|
||||
sealed class NetworkAddress {
|
||||
|
||||
/** The default or currently selected network address. */
|
||||
abstract val defaultAddress: String
|
||||
|
||||
/**
|
||||
* Represents a single static network address.
|
||||
*
|
||||
* @property defaultAddress The static network address.
|
||||
*/
|
||||
data class Single(override val defaultAddress: String) : NetworkAddress() {
|
||||
|
||||
init {
|
||||
checkDefaultAddress()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a network configuration where an address can be chosen from a set of available addresses.
|
||||
*
|
||||
* @property defaultAddress The currently selected or default network address.
|
||||
* @property availableAddresses The set of available network addresses to choose from.
|
||||
*/
|
||||
data class Selectable(
|
||||
override val defaultAddress: String,
|
||||
val availableAddresses: Set<String>,
|
||||
) : NetworkAddress() {
|
||||
|
||||
init {
|
||||
checkDefaultAddress()
|
||||
require(availableAddresses.isNotEmpty()) { "Available network addresses must not be empty" }
|
||||
}
|
||||
}
|
||||
|
||||
protected fun checkDefaultAddress() {
|
||||
require(defaultAddress.isNotBlank()) { "Selected network address must not be blank" }
|
||||
}
|
||||
}
|
||||
|
|
@ -33,20 +33,28 @@ data class NetworkStatus(
|
|||
object MissedDerivation : Status()
|
||||
|
||||
/**
|
||||
* Represents the verified state of the network, including the amounts associated with different cryptocurrencies and whether there are transactions in progress.
|
||||
* Represents the verified state of the network, including the amounts associated with different cryptocurrencies
|
||||
* and whether there are transactions in progress.
|
||||
*
|
||||
* @property address Network addresses.
|
||||
* @property amounts A map containing the amounts associated with different cryptocurrencies within the network.
|
||||
* @property hasTransactionsInProgress A boolean indicating whether there are transactions in progress within the network.
|
||||
* @property pendingTransactions A map containing pending transactions associated with different cryptocurrencies
|
||||
* within the network.
|
||||
*/
|
||||
data class Verified(
|
||||
val address: NetworkAddress,
|
||||
val amounts: Map<CryptoCurrency.ID, BigDecimal>,
|
||||
val hasTransactionsInProgress: Boolean,
|
||||
val pendingTransactions: Map<CryptoCurrency.ID, Set<PendingTransaction>>,
|
||||
) : Status()
|
||||
|
||||
/**
|
||||
* Represents the state where there is no account, and an amount is required to create one.
|
||||
*
|
||||
* @property address Network addresses.
|
||||
* @property amountToCreateAccount The amount required to create an account within the network.
|
||||
*/
|
||||
data class NoAccount(val amountToCreateAccount: BigDecimal) : Status()
|
||||
data class NoAccount(
|
||||
val address: NetworkAddress,
|
||||
val amountToCreateAccount: BigDecimal,
|
||||
) : Status()
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.tangem.domain.tokens.model
|
||||
|
||||
import org.joda.time.DateTime
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
* Represents a cryptocurrency transaction that is currently in progress.
|
||||
*
|
||||
* @property amount The monetary amount involved in the transaction.
|
||||
* @property direction The direction of the transaction, indicating if it's an incoming or outgoing transaction.
|
||||
* @property sentAt The timestamp when the transaction was executed.
|
||||
*/
|
||||
data class PendingTransaction(
|
||||
val amount: BigDecimal,
|
||||
val direction: Direction,
|
||||
val sentAt: DateTime,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Represents the direction of the transaction.
|
||||
*/
|
||||
sealed class Direction {
|
||||
|
||||
/**
|
||||
* Represents an incoming transaction.
|
||||
*
|
||||
* @property fromAddress The source address from which the assets are being received. May be `null` if
|
||||
* transaction received from unknown address.
|
||||
*/
|
||||
data class Incoming(val fromAddress: String?) : Direction()
|
||||
|
||||
/**
|
||||
* Represents an outgoing transaction.
|
||||
*
|
||||
* @property toAddress The destination address to which the assets are being sent. May be `null` if transaction
|
||||
* sent to unknown address.
|
||||
*/
|
||||
data class Outgoing(val toAddress: String?) : Direction()
|
||||
}
|
||||
}
|
||||
|
|
@ -27,18 +27,22 @@ internal class CurrencyStatusOperations(
|
|||
|
||||
private fun createStatus(status: NetworkStatus.Verified): CryptoCurrencyStatus.Status {
|
||||
val amount = status.amounts[currency.id] ?: return CryptoCurrencyStatus.Unreachable
|
||||
val hasCurrentNetworkTransactions = status.pendingTransactions.isNotEmpty()
|
||||
val currentTransactions = status.pendingTransactions.getOrElse(currency.id, ::emptySet)
|
||||
|
||||
return when {
|
||||
ignoreQuote -> CryptoCurrencyStatus.NoQuote(
|
||||
amount = amount,
|
||||
hasTransactionsInProgress = status.hasTransactionsInProgress,
|
||||
hasCurrentNetworkTransactions = hasCurrentNetworkTransactions,
|
||||
pendingTransactions = currentTransactions,
|
||||
)
|
||||
currency is CryptoCurrency.Token && currency.isCustom -> CryptoCurrencyStatus.Custom(
|
||||
amount = amount,
|
||||
fiatAmount = calculateFiatAmountOrNull(amount, quote?.fiatRate),
|
||||
fiatRate = quote?.fiatRate,
|
||||
priceChange = quote?.priceChange,
|
||||
hasTransactionsInProgress = status.hasTransactionsInProgress,
|
||||
hasCurrentNetworkTransactions = hasCurrentNetworkTransactions,
|
||||
pendingTransactions = currentTransactions,
|
||||
)
|
||||
quote == null -> CryptoCurrencyStatus.Loading
|
||||
else -> CryptoCurrencyStatus.Loaded(
|
||||
|
|
@ -46,7 +50,8 @@ internal class CurrencyStatusOperations(
|
|||
fiatAmount = calculateFiatAmount(amount, quote.fiatRate),
|
||||
fiatRate = quote.fiatRate,
|
||||
priceChange = quote.priceChange,
|
||||
hasTransactionsInProgress = status.hasTransactionsInProgress,
|
||||
hasCurrentNetworkTransactions = hasCurrentNetworkTransactions,
|
||||
pendingTransactions = currentTransactions,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.domain.tokens.mock
|
|||
|
||||
import arrow.core.NonEmptySet
|
||||
import arrow.core.nonEmptySetOf
|
||||
import com.tangem.domain.tokens.model.NetworkAddress
|
||||
import com.tangem.domain.tokens.model.NetworkStatus
|
||||
import com.tangem.domain.tokens.models.Network
|
||||
import java.math.BigDecimal
|
||||
|
|
@ -48,6 +49,7 @@ internal object MockNetworks {
|
|||
networkId = network3.id,
|
||||
value = NetworkStatus.NoAccount(
|
||||
amountToCreateAccount = amountToCreateAccount,
|
||||
address = NetworkAddress.Single(defaultAddress = "mock"),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -61,7 +63,8 @@ internal object MockNetworks {
|
|||
MockTokens.token2.id to BigDecimal.TEN,
|
||||
MockTokens.token3.id to BigDecimal.TEN,
|
||||
),
|
||||
hasTransactionsInProgress = false,
|
||||
pendingTransactions = emptyMap(),
|
||||
address = NetworkAddress.Single(defaultAddress = "mock"),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -73,7 +76,8 @@ internal object MockNetworks {
|
|||
MockTokens.token5.id to BigDecimal.TEN,
|
||||
MockTokens.token6.id to BigDecimal.TEN,
|
||||
),
|
||||
hasTransactionsInProgress = false,
|
||||
pendingTransactions = emptyMap(),
|
||||
address = NetworkAddress.Single(defaultAddress = "mock"),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -86,7 +90,8 @@ internal object MockNetworks {
|
|||
MockTokens.token9.id to BigDecimal.TEN,
|
||||
MockTokens.token10.id to BigDecimal.TEN,
|
||||
),
|
||||
hasTransactionsInProgress = false,
|
||||
pendingTransactions = emptyMap(),
|
||||
address = NetworkAddress.Single(defaultAddress = "mock"),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,8 @@ internal object MockTokensStates {
|
|||
fiatAmount = fiatAmount,
|
||||
fiatRate = quote.fiatRate,
|
||||
priceChange = quote.priceChange,
|
||||
hasTransactionsInProgress = false,
|
||||
pendingTransactions = emptySet(),
|
||||
hasCurrentNetworkTransactions = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -92,7 +93,8 @@ internal object MockTokensStates {
|
|||
currency.copy(
|
||||
value = CryptoCurrencyStatus.NoQuote(
|
||||
amount = currency.value.amount!!,
|
||||
hasTransactionsInProgress = false,
|
||||
pendingTransactions = emptySet(),
|
||||
hasCurrentNetworkTransactions = false,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ internal class CryptoCurrencyStatusToTokenItemConverter(
|
|||
tokenIconResId = currency.iconResId,
|
||||
networkBadgeIconResId = currency.networkBadgeIconResId,
|
||||
amount = getFormattedAmount(),
|
||||
hasPending = value.hasTransactionsInProgress,
|
||||
hasPending = value.hasCurrentNetworkTransactions,
|
||||
tokenOptions = if (isWalletContentHidden) {
|
||||
TokenItemState.TokenOptionsState.Hidden(getPriceChangeConfig())
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue