Updated on 2026-08-14
This commit is contained in:
parent
62d1577a00
commit
9b101c4238
11 changed files with 167 additions and 20 deletions
|
|
@ -179,11 +179,15 @@ sealed class NotificationUM(val config: NotificationConfig) {
|
||||||
subtitle = resourceReference(id = R.string.send_notification_invalid_reserve_amount_text),
|
subtitle = resourceReference(id = R.string.send_notification_invalid_reserve_amount_text),
|
||||||
)
|
)
|
||||||
|
|
||||||
data class NetworkAccountNotFunded(val coinName: String) : Error(
|
data class NetworkAccountNotFunded(
|
||||||
|
val coinName: String,
|
||||||
|
val reserveAmount: String,
|
||||||
|
val reserveSymbol: String,
|
||||||
|
) : Error(
|
||||||
title = resourceReference(R.string.alert_failed_to_send_transaction_title),
|
title = resourceReference(R.string.alert_failed_to_send_transaction_title),
|
||||||
subtitle = resourceReference(
|
subtitle = resourceReference(
|
||||||
id = R.string.no_account_generic,
|
id = R.string.no_account_generic,
|
||||||
formatArgs = wrappedList(coinName),
|
formatArgs = wrappedList(coinName, reserveAmount, reserveSymbol),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -191,6 +195,11 @@ sealed class NotificationUM(val config: NotificationConfig) {
|
||||||
title = resourceReference(id = R.string.send_validation_destination_tag_required_title),
|
title = resourceReference(id = R.string.send_validation_destination_tag_required_title),
|
||||||
subtitle = resourceReference(id = R.string.send_validation_destination_tag_required_description),
|
subtitle = resourceReference(id = R.string.send_validation_destination_tag_required_description),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data object RequiredTrustline : Error(
|
||||||
|
title = resourceReference(id = R.string.common_error),
|
||||||
|
subtitle = resourceReference(id = R.string.no_trustline_xlm_asset),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
open class Warning(
|
open class Warning(
|
||||||
|
|
|
||||||
|
|
@ -120,40 +120,66 @@ object NotificationsFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
fun MutableList<NotificationUM>.addReserveAmountErrorNotification(
|
fun MutableList<NotificationUM>.addReserveAmountErrorNotification(
|
||||||
reserveAmount: BigDecimal?,
|
reserveAmount: BigDecimal?,
|
||||||
sendingAmount: BigDecimal,
|
sendingAmount: BigDecimal,
|
||||||
cryptoCurrency: CryptoCurrency,
|
cryptoCurrency: CryptoCurrency,
|
||||||
feeCryptoCurrency: CryptoCurrency?,
|
feeCryptoCurrency: CryptoCurrency?,
|
||||||
isAccountFunded: Boolean,
|
isAccountFunded: Boolean,
|
||||||
|
hasRequiredTrustline: Boolean,
|
||||||
) {
|
) {
|
||||||
val sendingCoinAmount = when (cryptoCurrency) {
|
val sendingCoinAmount = when (cryptoCurrency) {
|
||||||
is CryptoCurrency.Coin -> sendingAmount
|
is CryptoCurrency.Coin -> sendingAmount
|
||||||
is CryptoCurrency.Token -> BigDecimal.ZERO
|
is CryptoCurrency.Token -> BigDecimal.ZERO
|
||||||
}
|
}
|
||||||
|
|
||||||
if (feeCryptoCurrency == null && cryptoCurrency is CryptoCurrency.Token) {
|
when {
|
||||||
// No need to show reserve amount warning if fee currency is unknown for token transfer
|
// No need to show reserve amount warning if fee currency is unknown for token transfer
|
||||||
return
|
feeCryptoCurrency == null && cryptoCurrency is CryptoCurrency.Token -> Unit
|
||||||
} else if (!isAccountFunded && reserveAmount != null && reserveAmount > sendingCoinAmount) {
|
|
||||||
// account not funded, sending coin amount < reserve (send coin with less amount OR send any token)
|
// account not funded, sending coin amount < reserve (send coin with less amount OR send any token)
|
||||||
|
!isAccountFunded && reserveAmount != null && reserveAmount > sendingCoinAmount ->
|
||||||
|
addAccountNotFundedNotification(
|
||||||
|
reserveAmount = reserveAmount,
|
||||||
|
cryptoCurrency = cryptoCurrency,
|
||||||
|
feeCryptoCurrency = feeCryptoCurrency,
|
||||||
|
)
|
||||||
|
hasRequiredTrustline -> addTrustlineRequiredNotification()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (cryptoCurrency is CryptoCurrency.Coin) {
|
private fun MutableList<NotificationUM>.addAccountNotFundedNotification(
|
||||||
// Try to send coin amount less than reserve amount (e.g. less than 1 XLM in Stellar)
|
reserveAmount: BigDecimal,
|
||||||
|
cryptoCurrency: CryptoCurrency,
|
||||||
|
feeCryptoCurrency: CryptoCurrency?,
|
||||||
|
) {
|
||||||
|
when (cryptoCurrency) {
|
||||||
|
// Try to send coin amount less than reserve amount (e.g. less than 1 XLM in Stellar)
|
||||||
|
is CryptoCurrency.Coin -> add(
|
||||||
|
NotificationUM.Error.ReserveAmount(
|
||||||
|
reserveAmount.format {
|
||||||
|
crypto(feeCryptoCurrency ?: cryptoCurrency)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// Try to send any token (e.g. USDC in Stellar, but account not funded -> user must send XLM at first)
|
||||||
|
is CryptoCurrency.Token -> {
|
||||||
|
checkNotNull(feeCryptoCurrency)
|
||||||
add(
|
add(
|
||||||
NotificationUM.Error.ReserveAmount(
|
NotificationUM.Error.NetworkAccountNotFunded(
|
||||||
reserveAmount.format {
|
coinName = feeCryptoCurrency.name,
|
||||||
crypto(feeCryptoCurrency ?: cryptoCurrency)
|
reserveAmount = reserveAmount.format {
|
||||||
|
crypto(symbol = "", decimals = feeCryptoCurrency.decimals)
|
||||||
},
|
},
|
||||||
|
reserveSymbol = feeCryptoCurrency.symbol,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
checkNotNull(feeCryptoCurrency)
|
|
||||||
// Try to send any token (e.g. USDC in Stellar, but account not funded -> user must send XLM at first)
|
|
||||||
add(NotificationUM.Error.NetworkAccountNotFunded(coinName = feeCryptoCurrency.name))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: check the RECEIVER account trustline before sending
|
}
|
||||||
|
|
||||||
|
private fun MutableList<NotificationUM>.addTrustlineRequiredNotification() {
|
||||||
|
add(NotificationUM.Error.RequiredTrustline)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MutableList<NotificationUM>.addMinimumAmountErrorNotification(
|
fun MutableList<NotificationUM>.addMinimumAmountErrorNotification(
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,17 @@ import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.model.Model
|
import com.tangem.core.decompose.model.Model
|
||||||
import com.tangem.core.decompose.model.ParamsContainer
|
import com.tangem.core.decompose.model.ParamsContainer
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
|
import com.tangem.domain.account.status.usecase.GetAccountCurrencyByAddressUseCase
|
||||||
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.notifications.GetTronFeeNotificationShowCountUseCase
|
import com.tangem.domain.notifications.GetTronFeeNotificationShowCountUseCase
|
||||||
import com.tangem.domain.notifications.IncrementNotificationsShowCountUseCase
|
import com.tangem.domain.notifications.IncrementNotificationsShowCountUseCase
|
||||||
|
import com.tangem.domain.tokens.GetAssetRequirementsUseCase
|
||||||
import com.tangem.domain.tokens.GetBalanceNotEnoughForFeeWarningUseCase
|
import com.tangem.domain.tokens.GetBalanceNotEnoughForFeeWarningUseCase
|
||||||
import com.tangem.domain.tokens.GetCurrencyCheckUseCase
|
import com.tangem.domain.tokens.GetCurrencyCheckUseCase
|
||||||
import com.tangem.domain.tokens.IsAmountSubtractAvailableUseCase
|
import com.tangem.domain.tokens.IsAmountSubtractAvailableUseCase
|
||||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
|
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
|
||||||
|
import com.tangem.domain.transaction.models.AssetRequirementsCondition
|
||||||
import com.tangem.domain.transaction.usecase.ValidateTransactionUseCase
|
import com.tangem.domain.transaction.usecase.ValidateTransactionUseCase
|
||||||
import com.tangem.domain.utils.convertToSdkAmount
|
import com.tangem.domain.utils.convertToSdkAmount
|
||||||
import com.tangem.features.send.api.SendNotificationsComponent
|
import com.tangem.features.send.api.SendNotificationsComponent
|
||||||
|
|
@ -70,9 +73,11 @@ internal class NotificationsModel @Inject constructor(
|
||||||
private val validateTransactionUseCase: ValidateTransactionUseCase,
|
private val validateTransactionUseCase: ValidateTransactionUseCase,
|
||||||
private val getTronFeeNotificationShowCountUseCase: GetTronFeeNotificationShowCountUseCase,
|
private val getTronFeeNotificationShowCountUseCase: GetTronFeeNotificationShowCountUseCase,
|
||||||
private val incrementNotificationsShowCountUseCase: IncrementNotificationsShowCountUseCase,
|
private val incrementNotificationsShowCountUseCase: IncrementNotificationsShowCountUseCase,
|
||||||
|
private val getAssetRequirementsUseCase: GetAssetRequirementsUseCase,
|
||||||
|
private val getAccountCurrencyByAddressUseCase: GetAccountCurrencyByAddressUseCase,
|
||||||
private val notificationsUpdateTrigger: SendNotificationsUpdateTrigger,
|
private val notificationsUpdateTrigger: SendNotificationsUpdateTrigger,
|
||||||
private val notificationsUpdateListener: SendNotificationsUpdateListener,
|
private val notificationsUpdateListener: SendNotificationsUpdateListener,
|
||||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
analyticsEventHandler: AnalyticsEventHandler,
|
||||||
) : Model() {
|
) : Model() {
|
||||||
|
|
||||||
private val params: SendNotificationsComponent.Params = paramsContainer.require()
|
private val params: SendNotificationsComponent.Params = paramsContainer.require()
|
||||||
|
|
@ -295,6 +300,7 @@ internal class NotificationsModel @Inject constructor(
|
||||||
cryptoCurrency = currency,
|
cryptoCurrency = currency,
|
||||||
feeCryptoCurrency = feeCryptoCurrencyStatus.currency,
|
feeCryptoCurrency = feeCryptoCurrencyStatus.currency,
|
||||||
isAccountFunded = currencyCheck.isAccountFunded,
|
isAccountFunded = currencyCheck.isAccountFunded,
|
||||||
|
hasRequiredTrustline = recipientRequiresTrustline(notificationData.destinationAddress),
|
||||||
)
|
)
|
||||||
addMinimumAmountErrorNotification(
|
addMinimumAmountErrorNotification(
|
||||||
minimumSendAmount = currencyCheck.minimumSendAmount,
|
minimumSendAmount = currencyCheck.minimumSendAmount,
|
||||||
|
|
@ -303,6 +309,24 @@ internal class NotificationsModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun recipientRequiresTrustline(destinationAddress: String?): Boolean {
|
||||||
|
val recipientAccount = destinationAddress
|
||||||
|
?.let { getAccountCurrencyByAddressUseCase(it).getOrNull() }
|
||||||
|
?.account
|
||||||
|
?: return false
|
||||||
|
val recipientCurrency = recipientAccount.cryptoCurrencies
|
||||||
|
.firstOrNull { it.isSameTokenAs(currency) }
|
||||||
|
?: return false
|
||||||
|
return getAssetRequirementsUseCase(
|
||||||
|
userWalletId = recipientAccount.userWalletId,
|
||||||
|
currency = recipientCurrency,
|
||||||
|
).getOrNull() is AssetRequirementsCondition.RequiredTrustline
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CryptoCurrency.isSameTokenAs(other: CryptoCurrency): Boolean {
|
||||||
|
return id.rawNetworkId == other.id.rawNetworkId && id.contractAddress == other.id.contractAddress
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun MutableList<NotificationUM>.addWarningNotifications(
|
private suspend fun MutableList<NotificationUM>.addWarningNotifications(
|
||||||
destinationAddress: String?,
|
destinationAddress: String?,
|
||||||
memo: String?,
|
memo: String?,
|
||||||
|
|
|
||||||
|
|
@ -257,6 +257,7 @@ internal class AddStakingNotificationsTransformer(
|
||||||
cryptoCurrency = cryptoCurrency,
|
cryptoCurrency = cryptoCurrency,
|
||||||
feeCryptoCurrency = feeCryptoCurrencyStatus?.currency,
|
feeCryptoCurrency = feeCryptoCurrencyStatus?.currency,
|
||||||
isAccountFunded = false,
|
isAccountFunded = false,
|
||||||
|
hasRequiredTrustline = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ sealed interface SwapState {
|
||||||
val currencyCheck: CryptoCurrencyCheck? = null,
|
val currencyCheck: CryptoCurrencyCheck? = null,
|
||||||
val validationResult: Throwable? = null,
|
val validationResult: Throwable? = null,
|
||||||
val minAdaValue: BigDecimal? = null,
|
val minAdaValue: BigDecimal? = null,
|
||||||
|
val hasRequiredTrustline: Boolean = false,
|
||||||
) : SwapState
|
) : SwapState
|
||||||
|
|
||||||
data class EmptyAmountState(
|
data class EmptyAmountState(
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import com.tangem.domain.notifications.IncrementNotificationsShowCountUseCase
|
||||||
import com.tangem.domain.pay.WithdrawalResult
|
import com.tangem.domain.pay.WithdrawalResult
|
||||||
import com.tangem.domain.swap.models.SwapCurrencyStatus
|
import com.tangem.domain.swap.models.SwapCurrencyStatus
|
||||||
import com.tangem.domain.tangempay.TangemPayWithdrawUseCase
|
import com.tangem.domain.tangempay.TangemPayWithdrawUseCase
|
||||||
|
import com.tangem.domain.tokens.GetAssetRequirementsUseCase
|
||||||
import com.tangem.domain.tokens.GetBalanceNotEnoughForFeeWarningUseCase
|
import com.tangem.domain.tokens.GetBalanceNotEnoughForFeeWarningUseCase
|
||||||
import com.tangem.domain.tokens.GetCurrencyCheckUseCase
|
import com.tangem.domain.tokens.GetCurrencyCheckUseCase
|
||||||
import com.tangem.domain.tokens.IsAmountSubtractAvailableUseCase
|
import com.tangem.domain.tokens.IsAmountSubtractAvailableUseCase
|
||||||
|
|
@ -31,6 +32,7 @@ import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
|
||||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
|
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
|
||||||
import com.tangem.domain.transaction.error.GetFeeError
|
import com.tangem.domain.transaction.error.GetFeeError
|
||||||
import com.tangem.domain.transaction.error.SendTransactionError
|
import com.tangem.domain.transaction.error.SendTransactionError
|
||||||
|
import com.tangem.domain.transaction.models.AssetRequirementsCondition
|
||||||
import com.tangem.domain.transaction.models.TransactionFeeExtended
|
import com.tangem.domain.transaction.models.TransactionFeeExtended
|
||||||
import com.tangem.domain.transaction.usecase.CreateTransferTransactionUseCase
|
import com.tangem.domain.transaction.usecase.CreateTransferTransactionUseCase
|
||||||
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||||
|
|
@ -66,8 +68,10 @@ class SwapTransferInteractorImpl @Inject constructor(
|
||||||
private val getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase,
|
private val getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase,
|
||||||
private val getTronFeeNotificationShowCountUseCase: GetTronFeeNotificationShowCountUseCase,
|
private val getTronFeeNotificationShowCountUseCase: GetTronFeeNotificationShowCountUseCase,
|
||||||
private val incrementNotificationsShowCountUseCase: IncrementNotificationsShowCountUseCase,
|
private val incrementNotificationsShowCountUseCase: IncrementNotificationsShowCountUseCase,
|
||||||
|
private val getAssetRequirementsUseCase: GetAssetRequirementsUseCase,
|
||||||
) : SwapTransferInteractor {
|
) : SwapTransferInteractor {
|
||||||
|
|
||||||
|
@Suppress("LongMethod")
|
||||||
override suspend fun updateTransfer(
|
override suspend fun updateTransfer(
|
||||||
fromSwapCurrencyStatus: SwapCurrencyStatus,
|
fromSwapCurrencyStatus: SwapCurrencyStatus,
|
||||||
toSwapCurrencyStatus: SwapCurrencyStatus,
|
toSwapCurrencyStatus: SwapCurrencyStatus,
|
||||||
|
|
@ -109,6 +113,7 @@ class SwapTransferInteractorImpl @Inject constructor(
|
||||||
amount = fromTokenAmountValue,
|
amount = fromTokenAmountValue,
|
||||||
fee = warningsFee,
|
fee = warningsFee,
|
||||||
feeCurrencyBalanceAfterTransaction = null,
|
feeCurrencyBalanceAfterTransaction = null,
|
||||||
|
recipientAddress = toSwapCurrencyStatus.destinationAddress(),
|
||||||
)
|
)
|
||||||
val isAmountSubtractAvailable = isAmountSubtractAvailable(
|
val isAmountSubtractAvailable = isAmountSubtractAvailable(
|
||||||
userWalletId = userWallet.walletId,
|
userWalletId = userWallet.walletId,
|
||||||
|
|
@ -130,6 +135,10 @@ class SwapTransferInteractorImpl @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val tronFeeNotificationShowCount = getTronFeeNotificationShowCountUseCase()
|
val tronFeeNotificationShowCount = getTronFeeNotificationShowCountUseCase()
|
||||||
|
val hasRequiredTrustline = getAssetRequirementsUseCase(
|
||||||
|
userWalletId = toSwapCurrencyStatus.userWalletId,
|
||||||
|
currency = toToken,
|
||||||
|
).getOrNull() is AssetRequirementsCondition.RequiredTrustline
|
||||||
return SwapState.Transfer(
|
return SwapState.Transfer(
|
||||||
userWallet = userWallet,
|
userWallet = userWallet,
|
||||||
fromTokenInfo = fromTokenInfo,
|
fromTokenInfo = fromTokenInfo,
|
||||||
|
|
@ -145,6 +154,7 @@ class SwapTransferInteractorImpl @Inject constructor(
|
||||||
isAmountSubtractAvailable = isAmountSubtractAvailable,
|
isAmountSubtractAvailable = isAmountSubtractAvailable,
|
||||||
isSendingAmountLoading = coverageState.isSendingAmountLoading,
|
isSendingAmountLoading = coverageState.isSendingAmountLoading,
|
||||||
currencyCheck = currencyCheck,
|
currencyCheck = currencyCheck,
|
||||||
|
hasRequiredTrustline = hasRequiredTrustline,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import com.tangem.domain.notifications.IncrementNotificationsShowCountUseCase
|
||||||
import com.tangem.domain.pay.WithdrawalResult
|
import com.tangem.domain.pay.WithdrawalResult
|
||||||
import com.tangem.domain.swap.models.SwapCurrencyStatus
|
import com.tangem.domain.swap.models.SwapCurrencyStatus
|
||||||
import com.tangem.domain.tangempay.TangemPayWithdrawUseCase
|
import com.tangem.domain.tangempay.TangemPayWithdrawUseCase
|
||||||
|
import com.tangem.domain.tokens.GetAssetRequirementsUseCase
|
||||||
import com.tangem.domain.tokens.GetBalanceNotEnoughForFeeWarningUseCase
|
import com.tangem.domain.tokens.GetBalanceNotEnoughForFeeWarningUseCase
|
||||||
import com.tangem.domain.tokens.GetCurrencyCheckUseCase
|
import com.tangem.domain.tokens.GetCurrencyCheckUseCase
|
||||||
import com.tangem.domain.tokens.IsAmountSubtractAvailableUseCase
|
import com.tangem.domain.tokens.IsAmountSubtractAvailableUseCase
|
||||||
|
|
@ -42,6 +43,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.jupiter.api.AfterEach
|
import org.junit.jupiter.api.AfterEach
|
||||||
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
|
|
@ -65,6 +67,7 @@ internal class SwapTransferInteractorImplTest {
|
||||||
private val getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase = mockk(relaxed = true)
|
private val getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase = mockk(relaxed = true)
|
||||||
private val getTronFeeNotificationShowCountUseCase: GetTronFeeNotificationShowCountUseCase = mockk(relaxed = true)
|
private val getTronFeeNotificationShowCountUseCase: GetTronFeeNotificationShowCountUseCase = mockk(relaxed = true)
|
||||||
private val incrementNotificationsShowCountUseCase: IncrementNotificationsShowCountUseCase = mockk(relaxed = true)
|
private val incrementNotificationsShowCountUseCase: IncrementNotificationsShowCountUseCase = mockk(relaxed = true)
|
||||||
|
private val getAssetRequirementsUseCase: GetAssetRequirementsUseCase = mockk()
|
||||||
|
|
||||||
private val sut = SwapTransferInteractorImpl(
|
private val sut = SwapTransferInteractorImpl(
|
||||||
swapFeatureToggles = swapFeatureToggles,
|
swapFeatureToggles = swapFeatureToggles,
|
||||||
|
|
@ -82,8 +85,14 @@ internal class SwapTransferInteractorImplTest {
|
||||||
getBalanceNotEnoughForFeeWarningUseCase = getBalanceNotEnoughForFeeWarningUseCase,
|
getBalanceNotEnoughForFeeWarningUseCase = getBalanceNotEnoughForFeeWarningUseCase,
|
||||||
getTronFeeNotificationShowCountUseCase = getTronFeeNotificationShowCountUseCase,
|
getTronFeeNotificationShowCountUseCase = getTronFeeNotificationShowCountUseCase,
|
||||||
incrementNotificationsShowCountUseCase = incrementNotificationsShowCountUseCase,
|
incrementNotificationsShowCountUseCase = incrementNotificationsShowCountUseCase,
|
||||||
|
getAssetRequirementsUseCase = getAssetRequirementsUseCase,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
fun setup() {
|
||||||
|
coEvery { getAssetRequirementsUseCase(any(), any()) } returns null.right()
|
||||||
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
fun tearDown() {
|
fun tearDown() {
|
||||||
clearAllMocks()
|
clearAllMocks()
|
||||||
|
|
@ -429,6 +438,68 @@ internal class SwapTransferInteractorImplTest {
|
||||||
assertThat(result.isSendingAmountLoading).isTrue()
|
assertThat(result.isSendingAmountLoading).isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN destination address WHEN updateTransfer THEN currency check requested with recipient and isAccountFunded flows through`() =
|
||||||
|
runTest {
|
||||||
|
// Arrange
|
||||||
|
val appCurrency = AppCurrency(code = "USD", name = "US Dollar", symbol = "$")
|
||||||
|
val userWallet: UserWallet = mockk(relaxed = true)
|
||||||
|
val fromCurrencyStatus = buildCurrencyStatus(
|
||||||
|
rawCurrencyId = FROM_RAW_CURRENCY_ID,
|
||||||
|
decimals = FROM_DECIMALS,
|
||||||
|
fiatRate = BigDecimal.TEN,
|
||||||
|
amount = BigDecimal("1.6"),
|
||||||
|
userWallet = userWallet,
|
||||||
|
)
|
||||||
|
val toCurrencyStatus = buildCurrencyStatus(
|
||||||
|
rawCurrencyId = TO_RAW_CURRENCY_ID,
|
||||||
|
decimals = TO_DECIMALS,
|
||||||
|
userWallet = userWallet,
|
||||||
|
destinationAddress = DESTINATION_ADDRESS,
|
||||||
|
)
|
||||||
|
every { getSelectedAppCurrencyUseCase() } returns flowOf(appCurrency.right())
|
||||||
|
every { getBalanceHidingSettingsUseCase.isBalanceHidden() } returns flowOf(false)
|
||||||
|
coEvery { isAccountsModeEnabledUseCase.invokeSync() } returns false
|
||||||
|
// Stub matches only when the destination address is forwarded as recipientAddress; the
|
||||||
|
// returned check has isAccountFunded = true (buildCurrencyCheck default).
|
||||||
|
val fundedCheck = buildCurrencyCheck()
|
||||||
|
coEvery {
|
||||||
|
getCurrencyCheckUseCase(
|
||||||
|
userWalletId = any(),
|
||||||
|
currencyStatus = any(),
|
||||||
|
feeCurrencyStatus = any(),
|
||||||
|
amount = any(),
|
||||||
|
fee = any(),
|
||||||
|
feeCurrencyBalanceAfterTransaction = any(),
|
||||||
|
recipientAddress = DESTINATION_ADDRESS,
|
||||||
|
)
|
||||||
|
} returns fundedCheck
|
||||||
|
coEvery { isAmountSubtractAvailableUseCase(any(), any(), any()) } returns false.right()
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = sut.updateTransfer(
|
||||||
|
fromSwapCurrencyStatus = fromCurrencyStatus,
|
||||||
|
toSwapCurrencyStatus = toCurrencyStatus,
|
||||||
|
fromTokenAmount = "1,5",
|
||||||
|
feePaidCurrencyStatus = null,
|
||||||
|
fee = null,
|
||||||
|
) as SwapState.Transfer
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(result.currencyCheck?.isAccountFunded).isTrue()
|
||||||
|
coVerify {
|
||||||
|
getCurrencyCheckUseCase(
|
||||||
|
userWalletId = any(),
|
||||||
|
currencyStatus = any(),
|
||||||
|
feeCurrencyStatus = any(),
|
||||||
|
amount = any(),
|
||||||
|
fee = any(),
|
||||||
|
feeCurrencyBalanceAfterTransaction = any(),
|
||||||
|
recipientAddress = DESTINATION_ADDRESS,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region loadFee
|
// region loadFee
|
||||||
|
|
|
||||||
|
|
@ -332,6 +332,7 @@ sealed class SwapEvents(
|
||||||
fromCurrency: CryptoCurrency?,
|
fromCurrency: CryptoCurrency?,
|
||||||
toCurrency: CryptoCurrency?,
|
toCurrency: CryptoCurrency?,
|
||||||
feeNetwork: Network,
|
feeNetwork: Network,
|
||||||
|
isTangemPay: Boolean,
|
||||||
) : SwapEvents(
|
) : SwapEvents(
|
||||||
event = "Transfer in Progress Screen Opened",
|
event = "Transfer in Progress Screen Opened",
|
||||||
params = mapOf(
|
params = mapOf(
|
||||||
|
|
@ -340,6 +341,7 @@ sealed class SwapEvents(
|
||||||
RECEIVE_TOKEN to toCurrency?.symbol.orEmpty(),
|
RECEIVE_TOKEN to toCurrency?.symbol.orEmpty(),
|
||||||
"Receive Blockchain" to toCurrency?.network?.name.orEmpty(),
|
"Receive Blockchain" to toCurrency?.network?.name.orEmpty(),
|
||||||
"Network fee" to feeNetwork.name,
|
"Network fee" to feeNetwork.name,
|
||||||
|
"Pay Account" to isTangemPay.toString(),
|
||||||
),
|
),
|
||||||
), AppsFlyerIncludedEvent
|
), AppsFlyerIncludedEvent
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1491,7 +1491,7 @@ internal class SwapModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateTransferModeTangemPayState() {
|
private fun updateTransferModeTangemPayState() {
|
||||||
sendTransferInProgressEvent()
|
sendTransferInProgressEvent(isTangemPay = true)
|
||||||
uiState = swapTransferStateBuilder.createTangemPayWithdrawalSuccessState(
|
uiState = swapTransferStateBuilder.createTangemPayWithdrawalSuccessState(
|
||||||
uiState = uiState,
|
uiState = uiState,
|
||||||
dataState = dataState,
|
dataState = dataState,
|
||||||
|
|
@ -1541,7 +1541,7 @@ internal class SwapModel @Inject constructor(
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
updateWalletBalance()
|
updateWalletBalance()
|
||||||
sendTransferInProgressEvent()
|
sendTransferInProgressEvent(isTangemPay = false)
|
||||||
uiState = swapTransferStateBuilder.createSuccessState(
|
uiState = swapTransferStateBuilder.createSuccessState(
|
||||||
uiState = uiState,
|
uiState = uiState,
|
||||||
dataState = dataState,
|
dataState = dataState,
|
||||||
|
|
@ -1564,7 +1564,7 @@ internal class SwapModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendTransferInProgressEvent() {
|
private fun sendTransferInProgressEvent(isTangemPay: Boolean) {
|
||||||
val fromSwapCurrencyStatus = dataState.fromSwapCurrencyStatus
|
val fromSwapCurrencyStatus = dataState.fromSwapCurrencyStatus
|
||||||
val toSwapCurrencyStatus = dataState.toSwapCurrencyStatus
|
val toSwapCurrencyStatus = dataState.toSwapCurrencyStatus
|
||||||
analyticsEventHandler.send(
|
analyticsEventHandler.send(
|
||||||
|
|
@ -1572,6 +1572,7 @@ internal class SwapModel @Inject constructor(
|
||||||
fromCurrency = fromSwapCurrencyStatus?.currency,
|
fromCurrency = fromSwapCurrencyStatus?.currency,
|
||||||
toCurrency = toSwapCurrencyStatus?.currency,
|
toCurrency = toSwapCurrencyStatus?.currency,
|
||||||
feeNetwork = getFeeToken().network,
|
feeNetwork = getFeeToken().network,
|
||||||
|
isTangemPay = isTangemPay,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,7 @@ internal class SwapNotificationsFactory(
|
||||||
cryptoCurrency = swapCurrencyStatus.currency,
|
cryptoCurrency = swapCurrencyStatus.currency,
|
||||||
feeCryptoCurrency = feeCryptoCurrencyStatus?.currency,
|
feeCryptoCurrency = feeCryptoCurrencyStatus?.currency,
|
||||||
isAccountFunded = true, // consider the account is funded on the provider side
|
isAccountFunded = true, // consider the account is funded on the provider side
|
||||||
|
hasRequiredTrustline = false,
|
||||||
)
|
)
|
||||||
addReduceAmountNotification(
|
addReduceAmountNotification(
|
||||||
cryptoCurrencyStatus = swapCurrencyStatus.status,
|
cryptoCurrencyStatus = swapCurrencyStatus.status,
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,8 @@ internal class SwapTransferNotificationsFactory @Inject constructor() {
|
||||||
sendingAmount = amount.value,
|
sendingAmount = amount.value,
|
||||||
cryptoCurrency = swapCurrencyStatus.currency,
|
cryptoCurrency = swapCurrencyStatus.currency,
|
||||||
feeCryptoCurrency = feeCryptoCurrencyStatus?.currency,
|
feeCryptoCurrency = feeCryptoCurrencyStatus?.currency,
|
||||||
isAccountFunded = true,
|
isAccountFunded = state.currencyCheck?.isAccountFunded == true,
|
||||||
|
hasRequiredTrustline = state.hasRequiredTrustline,
|
||||||
)
|
)
|
||||||
addReduceAmountNotification(
|
addReduceAmountNotification(
|
||||||
cryptoCurrencyStatus = swapCurrencyStatus.status,
|
cryptoCurrencyStatus = swapCurrencyStatus.status,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue