Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-20 19:47:53 +05:00
parent 305e86960f
commit db03d6d860
17 changed files with 80 additions and 29 deletions

View file

@ -67,10 +67,12 @@ class MockUpdateWalletManagerResultFactory {
value = BigDecimal.ONE,
currencyRawId = CryptoCurrency.RawID("token"),
contractAddress = "0xTokenAddress",
yieldSupplyStatus = YieldSupplyStatus(
yieldSupplyStatus =
YieldSupplyStatus(
isActive = true,
isInitialized = true,
isAllowedToSpend = false,
effectiveProtocolBalance = BigDecimal.ONE,
),
),
),

View file

@ -19,6 +19,7 @@ import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.yieldSupplyKey
import com.tangem.domain.models.currency.yieldSupplyNotAllAmountSupplied
import com.tangem.domain.models.staking.YieldBalance
import com.tangem.domain.staking.utils.getTotalWithRewardsStakingBalance
import com.tangem.utils.StringsSigns.DASH_SIGN
@ -246,7 +247,9 @@ class TokenItemStateConverter(
isFlickering = status.value.isFlickering(),
icons = buildList {
if (status.value.yieldSupplyStatus?.isActive == true &&
status.value.yieldSupplyStatus?.isAllowedToSpend == false) {
status.value.yieldSupplyStatus?.isAllowedToSpend == false ||
status.yieldSupplyNotAllAmountSupplied()
) {
TokenItemState.FiatAmountState.Content.IconUM(
iconRes = R.drawable.ic_alert_triangle_20,
tint = IconTint.Warning,

View file

@ -119,6 +119,7 @@ sealed interface NetworkStatusDM {
@Json(name = "is_active") val isActive: Boolean,
@Json(name = "is_initialized") val isInitialized: Boolean,
@Json(name = "is_allowed_to_spend") val isAllowedToSpend: Boolean,
@Json(name = "effective_protocol_balance") val effectiveProtocolBalance: BigDecimal? = null,
)
@JsonClass(generateAdapter = true)

View file

@ -23,6 +23,7 @@ internal class NetworkYieldSupplyStatusConverter(
isActive = it.isActive,
isInitialized = it.isInitialized,
isAllowedToSpend = it.isAllowedToSpend,
effectiveProtocolBalance = it.effectiveProtocolBalance,
)
id to status
@ -38,6 +39,7 @@ internal class NetworkYieldSupplyStatusConverter(
isActive = yieldSupplyStatus.isActive,
isInitialized = yieldSupplyStatus.isInitialized,
isAllowedToSpend = yieldSupplyStatus.isAllowedToSpend,
effectiveProtocolBalance = yieldSupplyStatus.effectiveProtocolBalance,
)
}
}

View file

@ -62,6 +62,7 @@ internal class NetworkStatusDataModelConverterTest {
isActive = false,
isInitialized = false,
isAllowedToSpend = false,
effectiveProtocolBalance = BigDecimal.ONE,
),
ID(
prefix = Prefix.COIN_PREFIX,
@ -94,6 +95,7 @@ internal class NetworkStatusDataModelConverterTest {
isActive = false,
isInitialized = false,
isAllowedToSpend = false,
effectiveProtocolBalance = BigDecimal.ONE,
),
),
),

View file

@ -8,6 +8,7 @@ import com.tangem.domain.models.network.Network
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import java.math.BigDecimal
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class NetworkYieldSupplyStatusConverterTest {
@ -21,6 +22,7 @@ internal class NetworkYieldSupplyStatusConverterTest {
isActive = true,
isInitialized = true,
isAllowedToSpend = true,
effectiveProtocolBalance = BigDecimal.ONE,
)
@Test
@ -70,6 +72,7 @@ internal class NetworkYieldSupplyStatusConverterTest {
isActive = true,
isInitialized = true,
isAllowedToSpend = true,
effectiveProtocolBalance = BigDecimal.ONE,
)
}
}

View file

@ -68,6 +68,7 @@ internal class SimpleNetworkStatusConverterTest {
isActive = false,
isInitialized = false,
isAllowedToSpend = false,
effectiveProtocolBalance = BigDecimal.ONE,
),
),
),
@ -103,6 +104,7 @@ internal class SimpleNetworkStatusConverterTest {
isActive = false,
isInitialized = false,
isAllowedToSpend = false,
effectiveProtocolBalance = BigDecimal.ONE,
),
),
source = StatusSource.CACHE,

View file

@ -272,6 +272,7 @@ internal class NetworkStatusFactoryTest(private val model: Model) {
isActive = false,
isInitialized = false,
isAllowedToSpend = false,
effectiveProtocolBalance = BigDecimal.ONE,
),
),
),

View file

@ -181,7 +181,7 @@ internal class DefaultCurrencyChecksRepository(
blockchain = token.network.toBlockchain(),
derivationPath = token.network.derivationPath.value,
) ?: error("Wallet manager not found")
walletManager.getProtocolBalance(
walletManager.getEffectiveProtocolBalance(
token = Token(
symbol = token.symbol,
contractAddress = token.contractAddress,

View file

@ -128,6 +128,7 @@ internal class UpdateWalletManagerResultFactory {
isActive = type.isActive,
isInitialized = type.isInitialized,
isAllowedToSpend = type.isAllowedToSpend,
effectiveProtocolBalance = type.effectiveProtocolBalance,
),
)
}

View file

@ -91,8 +91,10 @@ internal class DefaultYieldSupplyTransactionRepository(
)
}
override suspend fun getProtocolBalance(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): BigDecimal? =
withContext(dispatchers.io) {
override suspend fun getEffectiveProtocolBalance(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
): BigDecimal? = withContext(dispatchers.io) {
require(cryptoCurrency is CryptoCurrency.Token)
runCatching {
val walletManager = walletManagersFacade.getOrCreateWalletManager(
@ -100,7 +102,7 @@ internal class DefaultYieldSupplyTransactionRepository(
blockchain = cryptoCurrency.network.toBlockchain(),
derivationPath = cryptoCurrency.network.derivationPath.value,
) ?: error("Wallet manager not found")
walletManager.getProtocolBalance(
walletManager.getEffectiveProtocolBalance(
token = Token(
symbol = cryptoCurrency.symbol,
contractAddress = cryptoCurrency.contractAddress,
@ -222,6 +224,17 @@ internal class DefaultYieldSupplyTransactionRepository(
): YieldSupplyStatus? = withContext(dispatchers.io) {
runCatching {
val sdkSupplyStatus = walletManager.getYieldSupplyStatus(cryptoCurrency.contractAddress)
val protocolBalance = if (sdkSupplyStatus?.isActive == true) {
walletManager.getEffectiveProtocolBalance(
token = Token(
symbol = cryptoCurrency.symbol,
contractAddress = cryptoCurrency.contractAddress,
decimals = cryptoCurrency.decimals,
),
)
} else {
null
}
val isAllowedToSpend = walletManager.isAllowedToSpend(
Token(
symbol = cryptoCurrency.symbol,
@ -234,6 +247,7 @@ internal class DefaultYieldSupplyTransactionRepository(
isActive = sdkSupplyStatus?.isActive == true,
isInitialized = sdkSupplyStatus?.isInitialized == true,
isAllowedToSpend = isAllowedToSpend,
effectiveProtocolBalance = protocolBalance,
)
}.onFailure(Timber::e).getOrNull()
}

View file

@ -3,3 +3,19 @@ package com.tangem.domain.models.currency
fun CryptoCurrency.Token.yieldSupplyKey(): String {
return "${network.backendId}_$contractAddress"
}
fun CryptoCurrencyStatus.yieldSupplyNotAllAmountSupplied(): Boolean {
if (this.currency !is CryptoCurrency.Token) return false
val supplyStatus = this.value.yieldSupplyStatus
if (supplyStatus?.isActive != true) return false
val protocolBalance = supplyStatus.effectiveProtocolBalance
val amount = this.value.amount
return if (protocolBalance != null && amount != null) {
amount > protocolBalance
} else {
false
}
}

View file

@ -1,5 +1,6 @@
package com.tangem.domain.models.yield.supply
import com.tangem.domain.models.serialization.SerializedBigDecimal
import kotlinx.serialization.Serializable
/**
@ -11,10 +12,12 @@ import kotlinx.serialization.Serializable
* @property isActive Indicates if the yield token is currently active.
* @property isInitialized Indicates if the yield token has been initialized.
* @property isAllowedToSpend Indicates if spending from the yield module is permitted.
*/
* @property effectiveProtocolBalance Indicates the balance (excluding service fee)
* */
@Serializable
data class YieldSupplyStatus(
val isActive: Boolean,
val isInitialized: Boolean,
val isAllowedToSpend: Boolean,
val effectiveProtocolBalance: SerializedBigDecimal?,
)

View file

@ -23,5 +23,5 @@ interface YieldSupplyTransactionRepository {
suspend fun getYieldContractAddress(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): String?
suspend fun getProtocolBalance(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): BigDecimal?
suspend fun getEffectiveProtocolBalance(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): BigDecimal?
}

View file

@ -19,7 +19,7 @@ class YieldSupplyGetProtocolBalanceUseCase(
): Either<YieldSupplyError, BigDecimal?> = Either.catch {
requireNotNull(cryptoCurrency as CryptoCurrency.Token)
yieldSupplyTransactionRepository.getProtocolBalance(
yieldSupplyTransactionRepository.getEffectiveProtocolBalance(
userWalletId = userWalletId,
cryptoCurrency = cryptoCurrency,
)

View file

@ -102,7 +102,8 @@ internal class YieldSupplyActiveModel @Inject constructor(
private fun subscribeOnCurrencyUpdates() {
cryptoCurrencyStatusFlow.onEach { cryptoCurrencyStatus ->
val protocolBalance = yieldSupplyGetProtocolBalanceUseCase(
val protocolBalance = cryptoCurrencyStatus.value.yieldSupplyStatus?.effectiveProtocolBalance
?: yieldSupplyGetProtocolBalanceUseCase(
userWalletId = params.userWallet.walletId,
cryptoCurrency = cryptoCurrency,
).getOrNull()

View file

@ -5,7 +5,7 @@
# https://github.com/tangem/tangem-sdk-android/
# https://github.com/tangem/vico
tangemBlockchainSdk = "releases-5.30-1283"
tangemBlockchainSdk = "releases-5.30-1285"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "releases-5.30-567"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^