Updated on 2026-08-14

This commit is contained in:
Tangem 2025-12-17 14:05:58 +03:00
commit 3cbc2dadfb
822 changed files with 12838 additions and 5366 deletions

View file

@ -0,0 +1,27 @@
<?xml version="1.0" ?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>BooleanPropertyNaming:ShortArticle.kt$ShortArticle$val viewed: Boolean</ID>
<ID>BooleanPropertyNaming:TokenReceiveConfig.kt$TokenReceiveConfig$val showMemoDisclaimer: Boolean</ID>
<ID>BooleanPropertyNaming:UserWallet.kt$UserWallet.Hot$val backedUp: Boolean</ID>
<ID>BooleanPropertyNaming:YieldBalanceItem.kt$PendingAction.PendingActionArgs$val signatureVerification: Boolean?</ID>
<ID>BooleanPropertyNaming:YieldBalanceItem.kt$PendingAction.PendingActionArgs$val validatorAddress: Boolean?</ID>
<ID>BooleanPropertyNaming:YieldBalanceItem.kt$PendingAction.PendingActionArgs$val validatorAddresses: Boolean?</ID>
<ID>BooleanPropertyNaming:YieldBalanceItem.kt$PendingAction.PendingActionArgs.Amount$val required: Boolean</ID>
<ID>BooleanPropertyNaming:YieldBalanceItem.kt$PendingAction.PendingActionArgs.Duration$val required: Boolean</ID>
<ID>BooleanPropertyNaming:YieldBalanceItem.kt$PendingAction.PendingActionArgs.TronResource$val required: Boolean</ID>
<ID>CastNullableToNonNullableType:DerivationPathAdapterWithMigration.kt$DerivationPathAdapterWithMigration$as</ID>
<ID>MultilineLambdaItParameter:MobileWallet.kt$MobileWallet${ ExtendedPublicKey( publicKey = publicKey, chainCode = it, ) }</ID>
<ID>NoNameShadowing:Account.kt$Account.CryptoPortfolio.Companion$derivationIndex</ID>
<ID>NullableBooleanCheck:CryptoCurrency.kt$CryptoCurrency$iconUrl?.isNotBlank() ?: true</ID>
<ID>NullableToStringCall:AccountName.kt$AccountName.Error.Empty$${Empty::class.simpleName}</ID>
<ID>NullableToStringCall:AccountName.kt$AccountName.Error.ExceedsMaxLength$${ExceedsMaxLength::class.simpleName}</ID>
<ID>NullableToStringCall:DerivationIndex.kt$DerivationIndex.Error.NegativeDerivationIndex$${this::class.simpleName}</ID>
<ID>UnsafeCallOnNullableType:MobileWalletAsStringSerializer.kt$MobileWalletAsStringSerializer$moshi.adapter(MobileWallet::class.java).fromJson(decoder.decodeString())!!</ID>
<ID>UnsafeCallOnNullableType:ScanResponseAsStringSerializer.kt$ScanResponseAsStringSerializer$moshi.adapter(ScanResponse::class.java).fromJson(decoder.decodeString())!!</ID>
<ID>UseEmptyCounterpart:ScanResponse.kt$ScanResponse$mapOf()</ID>
<ID>UseOrEmpty:CardDTO.kt$CardDTO.FirmwareVersion$type.rawValue ?: ""</ID>
<ID>UseOrEmpty:UserWalletId.kt$UserWalletId$value?.toHexString() ?: ""</ID>
</CurrentIssues>
</SmellBaseline>

View file

@ -5,7 +5,7 @@ import com.tangem.domain.models.getResultStatusSource
import com.tangem.domain.models.network.NetworkAddress
import com.tangem.domain.models.network.TxInfo
import com.tangem.domain.models.serialization.SerializedBigDecimal
import com.tangem.domain.models.staking.YieldBalance
import com.tangem.domain.models.staking.StakingBalance
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
import kotlinx.serialization.Serializable
@ -56,13 +56,10 @@ data class CryptoCurrencyStatus(
/** The network address */
val networkAddress: NetworkAddress? get() = null
/** Staking yield balance */
val yieldBalance: YieldBalance? get() = null
/** Staking balance */
val stakingBalance: StakingBalance? get() = null
/**
* !!! DO NOT CONFUSE with STAKING YIELD BALANCE
* Yield supply status
*/
/** Yield supply status */
val yieldSupplyStatus: YieldSupplyStatus? get() = null
/** Sources */
@ -73,11 +70,11 @@ data class CryptoCurrencyStatus(
data class Sources(
val networkSource: StatusSource = StatusSource.ACTUAL,
val quoteSource: StatusSource = StatusSource.ACTUAL,
val yieldBalanceSource: StatusSource = StatusSource.ACTUAL,
val stakingBalanceSource: StatusSource = StatusSource.ACTUAL,
) {
val total: StatusSource by lazy {
listOf(networkSource, quoteSource, yieldBalanceSource).getResultStatusSource()
listOf(networkSource, quoteSource, stakingBalanceSource).getResultStatusSource()
}
}
@ -163,7 +160,7 @@ data class CryptoCurrencyStatus(
override val fiatAmount: SerializedBigDecimal,
override val fiatRate: SerializedBigDecimal,
override val priceChange: SerializedBigDecimal,
override val yieldBalance: YieldBalance?,
override val stakingBalance: StakingBalance?,
override val yieldSupplyStatus: YieldSupplyStatus?,
override val hasCurrentNetworkTransactions: Boolean,
override val pendingTransactions: Set<TxInfo>,
@ -191,7 +188,7 @@ data class CryptoCurrencyStatus(
override val fiatAmount: SerializedBigDecimal?,
override val fiatRate: SerializedBigDecimal?,
override val priceChange: SerializedBigDecimal?,
override val yieldBalance: YieldBalance?,
override val stakingBalance: StakingBalance?,
override val yieldSupplyStatus: YieldSupplyStatus?,
override val hasCurrentNetworkTransactions: Boolean,
override val pendingTransactions: Set<TxInfo>,
@ -213,7 +210,7 @@ data class CryptoCurrencyStatus(
@Serializable
data class NoQuote(
override val amount: SerializedBigDecimal,
override val yieldBalance: YieldBalance?,
override val stakingBalance: StakingBalance?,
override val yieldSupplyStatus: YieldSupplyStatus?,
override val hasCurrentNetworkTransactions: Boolean,
override val pendingTransactions: Set<TxInfo>,

View file

@ -0,0 +1,19 @@
package com.tangem.domain.models.news
import kotlinx.serialization.Serializable
@Serializable
sealed class NewsError {
abstract val message: String?
abstract val code: Int?
data class ArticleNotFound(
override val message: String?,
override val code: Int?,
) : NewsError()
data class Unknown(
override val message: String?,
override val code: Int?,
) : NewsError()
}

View file

@ -0,0 +1,16 @@
package com.tangem.domain.models.news
import kotlinx.serialization.Serializable
/**
* Represents the result of fetching news.
* Can contain either data or an error.
*/
@Serializable
sealed interface TrendingNews {
@Serializable
data class Data(val articles: List<ShortArticle>) : TrendingNews
@Serializable
data class Error(val throwable: NewsError) : TrendingNews
}

View file

@ -0,0 +1,37 @@
package com.tangem.domain.models.staking
import com.tangem.domain.models.serialization.SerializedBigDecimal
import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable
/** P2P.org staking account */
@Serializable
data class P2PStakingAccount(
val delegatorAddress: String,
val vaultAddress: String,
val stake: P2PStake,
val availableToUnstake: SerializedBigDecimal,
val availableToWithdraw: SerializedBigDecimal,
val exitQueue: P2PExitQueue,
)
@Serializable
data class P2PStake(
val assets: SerializedBigDecimal,
val totalEarnedAssets: SerializedBigDecimal,
)
@Serializable
data class P2PExitQueue(
val total: SerializedBigDecimal,
val requests: List<P2PExitRequest>,
)
@Serializable
data class P2PExitRequest(
val ticket: String,
val totalAssets: SerializedBigDecimal,
val timestamp: Instant,
val withdrawalTimestamp: Instant,
val isClaimable: Boolean,
)

View file

@ -0,0 +1,101 @@
package com.tangem.domain.models.staking
import com.tangem.domain.models.StatusSource
import kotlinx.serialization.Serializable
import java.math.BigDecimal
/**
* Staking balance facade covering StakeKit and P2P balances
*/
@Serializable
sealed interface StakingBalance {
val stakingId: StakingID
val source: StatusSource
val totalStaked: BigDecimal
val totalRewards: BigDecimal?
val unstakingAmount: BigDecimal?
val withdrawableAmount: BigDecimal?
@Serializable
sealed interface Data : StakingBalance {
@Serializable
data class StakeKit(
override val stakingId: StakingID,
override val source: StatusSource,
val balance: YieldBalanceItem,
) : Data {
override val totalStaked: BigDecimal
get() = balance.items
.filter { it.type == BalanceType.STAKED }
.sumOf { it.amount }
override val totalRewards: BigDecimal
get() = balance.items
.filter { it.type == BalanceType.REWARDS }
.sumOf { it.amount }
override val unstakingAmount: BigDecimal
get() = balance.items
.filter { it.type == BalanceType.UNSTAKING || it.type == BalanceType.UNLOCKING }
.sumOf { it.amount }
override val withdrawableAmount: BigDecimal
get() = balance.items
.filter { it.type == BalanceType.UNSTAKED }
.sumOf { it.amount }
}
@Serializable
data class P2P(
override val stakingId: StakingID,
override val source: StatusSource,
val account: P2PStakingAccount,
) : Data {
override val totalStaked: BigDecimal
get() = account.stake.assets
override val totalRewards: BigDecimal
get() = account.stake.totalEarnedAssets
override val unstakingAmount: BigDecimal
get() = account.exitQueue.total
override val withdrawableAmount: BigDecimal
get() = account.availableToWithdraw
}
}
@Serializable
data class Empty(
override val stakingId: StakingID,
override val source: StatusSource,
) : StakingBalance {
override val totalStaked: BigDecimal get() = BigDecimal.ZERO
override val totalRewards: BigDecimal? get() = null
override val unstakingAmount: BigDecimal? get() = null
override val withdrawableAmount: BigDecimal? get() = null
}
@Serializable
data class Error(override val stakingId: StakingID) : StakingBalance {
override val source: StatusSource get() = StatusSource.ACTUAL
override val totalStaked: BigDecimal get() = BigDecimal.ZERO
override val totalRewards: BigDecimal? get() = null
override val unstakingAmount: BigDecimal? get() = null
override val withdrawableAmount: BigDecimal? get() = null
}
fun copySealed(source: StatusSource): StakingBalance {
return when (this) {
is Data.StakeKit -> copy(source = source)
is Data.P2P -> copy(source = source)
is Empty -> copy(source = source)
is Error -> this
}
}
}

View file

@ -3,4 +3,7 @@ package com.tangem.domain.models.staking
import kotlinx.serialization.Serializable
@Serializable
data class StakingID(val integrationId: String, val address: String)
data class StakingID(
val integrationId: String,
val address: String,
)