Updated on 2026-08-14
This commit is contained in:
parent
afddda1198
commit
7b574b2a20
5 changed files with 435 additions and 11 deletions
|
|
@ -7,16 +7,16 @@ fun CryptoCurrency.Token.yieldSupplyKey(): String {
|
|||
}
|
||||
|
||||
fun CryptoCurrencyStatus.hasNotSuppliedAmount(): Boolean {
|
||||
val notSupplied = notSuppliedAmountOrNull() ?: return false
|
||||
val notSupplied = notSuppliedCryptoAmountOrNull() ?: return false
|
||||
return notSupplied > BigDecimal.ZERO
|
||||
}
|
||||
|
||||
fun CryptoCurrencyStatus.shouldShowNotSuppliedInfoIcon(dustAmount: BigDecimal): Boolean {
|
||||
val notSupplied = notSuppliedAmountOrNull() ?: return false
|
||||
fun CryptoCurrencyStatus.shouldShowNotSuppliedNotification(dustAmount: BigDecimal): Boolean {
|
||||
val notSupplied = notSuppliedCryptoAmountOrNull()?.multiply(this.value.fiatRate) ?: return false
|
||||
return notSupplied >= dustAmount
|
||||
}
|
||||
|
||||
fun CryptoCurrencyStatus.notSuppliedAmountOrNull(): BigDecimal? {
|
||||
fun CryptoCurrencyStatus.notSuppliedCryptoAmountOrNull(): BigDecimal? {
|
||||
if (this.currency !is CryptoCurrency.Token) return null
|
||||
|
||||
val supplyStatus = this.value.yieldSupplyStatus
|
||||
|
|
|
|||
|
|
@ -0,0 +1,417 @@
|
|||
package com.tangem.domain.models.currency
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import java.math.BigDecimal
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class CryptoCurrencyExtensionsTest {
|
||||
|
||||
@Test
|
||||
fun `GIVEN currency is Coin WHEN hasNotSuppliedAmount THEN returns false`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Coin>(),
|
||||
)
|
||||
|
||||
val result = status.hasNotSuppliedAmount()
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN yieldSupplyStatus is null WHEN hasNotSuppliedAmount THEN returns false`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = null,
|
||||
)
|
||||
|
||||
val result = status.hasNotSuppliedAmount()
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN yieldSupplyStatus isActive is false WHEN hasNotSuppliedAmount THEN returns false`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = false,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = BigDecimal.TEN,
|
||||
),
|
||||
)
|
||||
|
||||
val result = status.hasNotSuppliedAmount()
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN effectiveProtocolBalance is null WHEN hasNotSuppliedAmount THEN returns false`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = null,
|
||||
),
|
||||
amount = BigDecimal.TEN,
|
||||
)
|
||||
|
||||
val result = status.hasNotSuppliedAmount()
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN amount is null WHEN hasNotSuppliedAmount THEN returns false`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = BigDecimal.TEN,
|
||||
),
|
||||
amount = null,
|
||||
)
|
||||
|
||||
val result = status.hasNotSuppliedAmount()
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN notSupplied is zero WHEN hasNotSuppliedAmount THEN returns false`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = BigDecimal.TEN,
|
||||
),
|
||||
amount = BigDecimal.TEN,
|
||||
)
|
||||
|
||||
val result = status.hasNotSuppliedAmount()
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN notSupplied is negative WHEN hasNotSuppliedAmount THEN returns false`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = BigDecimal.TEN,
|
||||
),
|
||||
amount = BigDecimal.ONE,
|
||||
)
|
||||
|
||||
val result = status.hasNotSuppliedAmount()
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN notSupplied is positive WHEN hasNotSuppliedAmount THEN returns true`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = BigDecimal.ONE,
|
||||
),
|
||||
amount = BigDecimal.TEN,
|
||||
)
|
||||
|
||||
val result = status.hasNotSuppliedAmount()
|
||||
|
||||
assertThat(result).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN currency is Coin WHEN shouldShowNotSuppliedNotification THEN returns false`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Coin>(),
|
||||
)
|
||||
|
||||
val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.ONE)
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN yieldSupplyStatus is null WHEN shouldShowNotSuppliedNotification THEN returns false`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = null,
|
||||
)
|
||||
|
||||
val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.ONE)
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN yieldSupplyStatus isActive is false WHEN shouldShowNotSuppliedNotification THEN returns false`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = false,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = BigDecimal.TEN,
|
||||
),
|
||||
)
|
||||
|
||||
val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.ONE)
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN effectiveProtocolBalance is null WHEN shouldShowNotSuppliedNotification THEN returns false`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = null,
|
||||
),
|
||||
amount = BigDecimal.TEN,
|
||||
fiatRate = BigDecimal.ONE,
|
||||
)
|
||||
|
||||
val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.ONE)
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN notSupplied in fiat is less than dustAmount WHEN shouldShowNotSuppliedNotification THEN returns false`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = BigDecimal("9"),
|
||||
),
|
||||
amount = BigDecimal.TEN,
|
||||
fiatRate = BigDecimal.ONE,
|
||||
)
|
||||
|
||||
val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.TEN)
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN notSupplied in fiat equals dustAmount WHEN shouldShowNotSuppliedNotification THEN returns true`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = BigDecimal("5"),
|
||||
),
|
||||
amount = BigDecimal.TEN,
|
||||
fiatRate = BigDecimal("2"),
|
||||
)
|
||||
|
||||
val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.TEN)
|
||||
|
||||
assertThat(result).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN notSupplied in fiat is greater than dustAmount WHEN shouldShowNotSuppliedNotification THEN returns true`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = BigDecimal.ONE,
|
||||
),
|
||||
amount = BigDecimal.TEN,
|
||||
fiatRate = BigDecimal("2"),
|
||||
)
|
||||
|
||||
val result = status.shouldShowNotSuppliedNotification(dustAmount = BigDecimal.TEN)
|
||||
|
||||
assertThat(result).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN USDT with EUR fiat rate and notSupplied below dust WHEN shouldShowNotSuppliedNotification THEN returns false`() {
|
||||
val usdtToEurRate = BigDecimal("0.93")
|
||||
val notSuppliedUsdt = BigDecimal("0.05")
|
||||
val protocolBalance = BigDecimal("100")
|
||||
val totalAmount = protocolBalance.add(notSuppliedUsdt)
|
||||
val dustAmountEur = BigDecimal("0.1")
|
||||
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = protocolBalance,
|
||||
),
|
||||
amount = totalAmount,
|
||||
fiatRate = usdtToEurRate,
|
||||
)
|
||||
|
||||
val result = status.shouldShowNotSuppliedNotification(dustAmount = dustAmountEur)
|
||||
|
||||
assertThat(result).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN USDT with EUR fiat rate and notSupplied above dust WHEN shouldShowNotSuppliedNotification THEN returns true`() {
|
||||
val usdtToEurRate = BigDecimal("0.93")
|
||||
val notSuppliedUsdt = BigDecimal("0.15")
|
||||
val protocolBalance = BigDecimal("100")
|
||||
val totalAmount = protocolBalance.add(notSuppliedUsdt)
|
||||
val dustAmountEur = BigDecimal("0.1")
|
||||
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = protocolBalance,
|
||||
),
|
||||
amount = totalAmount,
|
||||
fiatRate = usdtToEurRate,
|
||||
)
|
||||
|
||||
val result = status.shouldShowNotSuppliedNotification(dustAmount = dustAmountEur)
|
||||
|
||||
assertThat(result).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN currency is Coin WHEN notSuppliedCryptoAmountOrNull THEN returns null`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Coin>(),
|
||||
)
|
||||
|
||||
val result = status.notSuppliedCryptoAmountOrNull()
|
||||
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN yieldSupplyStatus is null WHEN notSuppliedCryptoAmountOrNull THEN returns null`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = null,
|
||||
)
|
||||
|
||||
val result = status.notSuppliedCryptoAmountOrNull()
|
||||
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN yieldSupplyStatus isActive is false WHEN notSuppliedCryptoAmountOrNull THEN returns null`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = false,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = BigDecimal.TEN,
|
||||
),
|
||||
)
|
||||
|
||||
val result = status.notSuppliedCryptoAmountOrNull()
|
||||
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN effectiveProtocolBalance is null WHEN notSuppliedCryptoAmountOrNull THEN returns null`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = null,
|
||||
),
|
||||
amount = BigDecimal.TEN,
|
||||
)
|
||||
|
||||
val result = status.notSuppliedCryptoAmountOrNull()
|
||||
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN amount is null WHEN notSuppliedCryptoAmountOrNull THEN returns null`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = BigDecimal.TEN,
|
||||
),
|
||||
amount = null,
|
||||
)
|
||||
|
||||
val result = status.notSuppliedCryptoAmountOrNull()
|
||||
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN valid data WHEN notSuppliedCryptoAmountOrNull THEN returns amount minus protocolBalance`() {
|
||||
val status = createCryptoCurrencyStatus(
|
||||
currency = mockk<CryptoCurrency.Token>(),
|
||||
yieldSupplyStatus = YieldSupplyStatus(
|
||||
isActive = true,
|
||||
isInitialized = true,
|
||||
isAllowedToSpend = true,
|
||||
effectiveProtocolBalance = BigDecimal("3"),
|
||||
),
|
||||
amount = BigDecimal.TEN,
|
||||
)
|
||||
|
||||
val result = status.notSuppliedCryptoAmountOrNull()
|
||||
|
||||
assertThat(result).isEqualTo(BigDecimal("7"))
|
||||
}
|
||||
|
||||
private fun createCryptoCurrencyStatus(
|
||||
currency: CryptoCurrency,
|
||||
yieldSupplyStatus: YieldSupplyStatus? = null,
|
||||
amount: BigDecimal? = null,
|
||||
fiatRate: BigDecimal? = null,
|
||||
): CryptoCurrencyStatus {
|
||||
val value = mockk<CryptoCurrencyStatus.Value> {
|
||||
every { this@mockk.yieldSupplyStatus } returns yieldSupplyStatus
|
||||
every { this@mockk.amount } returns amount
|
||||
every { this@mockk.fiatRate } returns fiatRate
|
||||
}
|
||||
return CryptoCurrencyStatus(currency = currency, value = value)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,13 @@ package com.tangem.domain.yield.supply.usecase
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
* Use case for getting dust minimum amount for yield supply.
|
||||
*
|
||||
* Returns the minimum amount based on the selected [AppCurrency].
|
||||
* If [AppCurrency] is in [SUPPORTED_DUST_CURRENCIES], returns [DUST_MIN_AMOUNT],
|
||||
* otherwise returns the original [minAmount] with trailing zeros stripped.
|
||||
*/
|
||||
class YieldSupplyGetDustMinAmountUseCase {
|
||||
|
||||
operator fun invoke(minAmount: BigDecimal, appCurrency: AppCurrency): BigDecimal {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import com.tangem.core.ui.format.bigdecimal.fiat
|
|||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.currency.notSuppliedAmountOrNull
|
||||
import com.tangem.domain.models.currency.shouldShowNotSuppliedInfoIcon
|
||||
import com.tangem.domain.models.currency.notSuppliedCryptoAmountOrNull
|
||||
import com.tangem.domain.models.currency.shouldShowNotSuppliedNotification
|
||||
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
|
||||
import com.tangem.features.yield.supply.impl.R
|
||||
import com.tangem.features.yield.supply.impl.active.entity.YieldSupplyActiveContentUM
|
||||
|
|
@ -91,11 +91,11 @@ internal class YieldSupplyActiveMinAmountTransformer(
|
|||
}
|
||||
|
||||
private fun getNotSuppliedNotification(cryptoCurrencyStatus: CryptoCurrencyStatus): NotificationUM? {
|
||||
return if (cryptoCurrencyStatus.shouldShowNotSuppliedInfoIcon(dustMinAmount)) {
|
||||
return if (cryptoCurrencyStatus.shouldShowNotSuppliedNotification(dustMinAmount)) {
|
||||
val cryptoCurrency = cryptoCurrencyStatus.currency
|
||||
val notDepositedAmount = cryptoCurrencyStatus.notSuppliedAmountOrNull()
|
||||
val notSuppliedAmount = cryptoCurrencyStatus.notSuppliedCryptoAmountOrNull()
|
||||
val formattedAmount =
|
||||
notDepositedAmount.format { crypto(symbol = "", decimals = cryptoCurrencyStatus.currency.decimals) }
|
||||
notSuppliedAmount.format { crypto(symbol = "", decimals = cryptoCurrencyStatus.currency.decimals) }
|
||||
analyticsHandler.send(
|
||||
YieldSupplyAnalytics.NoticeAmountNotDeposited(
|
||||
token = cryptoCurrency.symbol,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ 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.currency.hasNotSuppliedAmount
|
||||
import com.tangem.domain.models.currency.shouldShowNotSuppliedInfoIcon
|
||||
import com.tangem.domain.models.currency.shouldShowNotSuppliedNotification
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.yield.supply.YieldSupplyStatus
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
|
|
@ -351,7 +351,7 @@ internal class YieldSupplyModel @Inject constructor(
|
|||
minAmount = minAmount,
|
||||
appCurrency = appCurrency,
|
||||
)
|
||||
cryptoCurrencyStatus.shouldShowNotSuppliedInfoIcon(dustAmount)
|
||||
cryptoCurrencyStatus.shouldShowNotSuppliedNotification(dustAmount)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue