Updated on 2026-08-14
This commit is contained in:
parent
e2d0973392
commit
bb5d6848d9
10 changed files with 339 additions and 43 deletions
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.swap.models.SwapCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
|
||||
import com.tangem.feature.swap.domain.models.ExpressDataError
|
||||
import com.tangem.feature.swap.domain.models.SwapAmount
|
||||
import com.tangem.feature.swap.domain.models.domain.PreparedSwapConfigState
|
||||
|
|
@ -36,6 +37,7 @@ sealed interface SwapState {
|
|||
val userWallet: UserWallet,
|
||||
val fromTokenInfo: TokenSwapInfo,
|
||||
val toTokenInfo: TokenSwapInfo,
|
||||
val cryptoCurrencyWarning: CryptoCurrencyWarning?,
|
||||
val isInsufficientBalance: Boolean,
|
||||
val appCurrency: AppCurrency,
|
||||
val isBalanceHidden: Boolean,
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ interface SwapTransferInteractor {
|
|||
fromSwapCurrencyStatus: SwapCurrencyStatus,
|
||||
toSwapCurrencyStatus: SwapCurrencyStatus,
|
||||
fromTokenAmount: BigDecimal,
|
||||
selectedToken: CryptoCurrencyStatus?,
|
||||
): Either<GetFeeError, TransactionFeeExtended>
|
||||
|
||||
suspend fun sendTransfer(
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.pay.WithdrawalResult
|
||||
import com.tangem.domain.swap.models.SwapCurrencyStatus
|
||||
import com.tangem.domain.tangempay.TangemPayWithdrawUseCase
|
||||
import com.tangem.domain.tokens.GetBalanceNotEnoughForFeeWarningUseCase
|
||||
import com.tangem.domain.tokens.GetCurrencyCheckUseCase
|
||||
import com.tangem.domain.tokens.IsAmountSubtractAvailableUseCase
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.error.SendTransactionError
|
||||
import com.tangem.domain.transaction.models.TransactionFeeExtended
|
||||
|
|
@ -46,7 +48,7 @@ import kotlinx.coroutines.flow.first
|
|||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Suppress("LongParameterList", "LargeClass")
|
||||
class SwapTransferInteractorImpl @Inject constructor(
|
||||
private val swapFeatureToggles: SwapFeatureToggles,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
|
|
@ -60,6 +62,7 @@ class SwapTransferInteractorImpl @Inject constructor(
|
|||
private val getCurrencyCheckUseCase: GetCurrencyCheckUseCase,
|
||||
private val isAmountSubtractAvailableUseCase: IsAmountSubtractAvailableUseCase,
|
||||
private val tangemPayWithdrawUseCase: TangemPayWithdrawUseCase,
|
||||
private val getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase,
|
||||
) : SwapTransferInteractor {
|
||||
|
||||
override suspend fun updateTransfer(
|
||||
|
|
@ -110,10 +113,19 @@ class SwapTransferInteractorImpl @Inject constructor(
|
|||
fee = fee,
|
||||
currencyCheck = currencyCheck,
|
||||
)
|
||||
val cryptoCurrencyWarning = feePaidCurrencyStatus?.let { feeStatus ->
|
||||
getCryptoCurrencyWarning(
|
||||
feeValue = fee?.amount?.value.orZero(),
|
||||
userWallet = userWallet,
|
||||
fromSwapCurrencyStatus = fromSwapCurrencyStatus,
|
||||
feeStatus = feeStatus,
|
||||
)
|
||||
}
|
||||
return SwapState.Transfer(
|
||||
userWallet = userWallet,
|
||||
fromTokenInfo = fromTokenInfo,
|
||||
toTokenInfo = toTokenInfo,
|
||||
cryptoCurrencyWarning = cryptoCurrencyWarning,
|
||||
isInsufficientBalance = fromTokenAmountValue > fromTokenBalance,
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
|
|
@ -124,6 +136,20 @@ class SwapTransferInteractorImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun getCryptoCurrencyWarning(
|
||||
feeValue: BigDecimal,
|
||||
userWallet: UserWallet,
|
||||
fromSwapCurrencyStatus: SwapCurrencyStatus,
|
||||
feeStatus: CryptoCurrencyStatus,
|
||||
): CryptoCurrencyWarning? {
|
||||
return getBalanceNotEnoughForFeeWarningUseCase(
|
||||
fee = feeValue,
|
||||
userWalletId = userWallet.walletId,
|
||||
tokenStatus = fromSwapCurrencyStatus.status,
|
||||
feeStatus = feeStatus,
|
||||
).getOrNull()
|
||||
}
|
||||
|
||||
private suspend fun getCoverageState(
|
||||
fromTokenInfo: TokenSwapInfo,
|
||||
userWallet: UserWallet,
|
||||
|
|
@ -210,12 +236,22 @@ class SwapTransferInteractorImpl @Inject constructor(
|
|||
val destination = toSwapCurrencyStatus.destinationAddress() ?: return feeDataError(
|
||||
message = "Destination address is null",
|
||||
)
|
||||
val userWallet = fromSwapCurrencyStatus.userWallet
|
||||
val currency = fromSwapCurrencyStatus.currency
|
||||
val transactionData = createTransferTransactionUseCase(
|
||||
amount = fromTokenAmount.convertToSdkAmount(
|
||||
cryptoCurrencyStatus = fromSwapCurrencyStatus.status,
|
||||
),
|
||||
memo = null,
|
||||
destination = destination,
|
||||
userWalletId = userWallet.walletId,
|
||||
network = currency.network,
|
||||
).getOrNull() ?: return feeDataError("Failed to build transfer transaction")
|
||||
|
||||
return getFeeUseCase(
|
||||
amount = fromTokenAmount,
|
||||
destination = destination,
|
||||
userWallet = fromSwapCurrencyStatus.userWallet,
|
||||
cryptoCurrency = fromSwapCurrencyStatus.currency,
|
||||
network = fromSwapCurrencyStatus.currency.network,
|
||||
transactionData = transactionData,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -223,6 +259,7 @@ class SwapTransferInteractorImpl @Inject constructor(
|
|||
fromSwapCurrencyStatus: SwapCurrencyStatus,
|
||||
toSwapCurrencyStatus: SwapCurrencyStatus,
|
||||
fromTokenAmount: BigDecimal,
|
||||
selectedToken: CryptoCurrencyStatus?,
|
||||
): Either<GetFeeError, TransactionFeeExtended> {
|
||||
val destination = toSwapCurrencyStatus.destinationAddress() ?: return feeDataError(
|
||||
message = "Destination address is null",
|
||||
|
|
@ -244,7 +281,13 @@ class SwapTransferInteractorImpl @Inject constructor(
|
|||
userWallet = userWallet,
|
||||
network = currency.network,
|
||||
transactionData = transactionData,
|
||||
)
|
||||
).map { transactionFeeExtended ->
|
||||
selectedToken ?: return@map transactionFeeExtended
|
||||
val selectedTokenId = selectedToken.currency.id
|
||||
transactionFeeExtended.copy(
|
||||
feeTokenId = selectedTokenId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun sendTransfer(
|
||||
|
|
@ -310,9 +353,9 @@ class SwapTransferInteractorImpl @Inject constructor(
|
|||
transactionFeeResult: TransactionFeeResult,
|
||||
txData: TransactionData,
|
||||
): Either<SendTransactionError, String> {
|
||||
val isToken = cryptoCurrencyStatus.currency is CryptoCurrency.Token
|
||||
val isGaslessToken = isToken && transactionFeeResult is TransactionFeeResult.LoadedExtended
|
||||
return if (isGaslessToken) {
|
||||
val isFeeInTokenCurrency = transactionFeeResult is TransactionFeeResult.LoadedExtended &&
|
||||
transactionFeeResult.fee.transactionFee.normal is Fee.Ethereum.TokenCurrency
|
||||
return if (isFeeInTokenCurrency) {
|
||||
createAndSendGaslessTransactionUseCase(
|
||||
transactionData = txData,
|
||||
userWallet = userWallet,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.pay.WithdrawalResult
|
||||
import com.tangem.domain.swap.models.SwapCurrencyStatus
|
||||
import com.tangem.domain.tangempay.TangemPayWithdrawUseCase
|
||||
import com.tangem.domain.tokens.GetBalanceNotEnoughForFeeWarningUseCase
|
||||
import com.tangem.domain.tokens.GetCurrencyCheckUseCase
|
||||
import com.tangem.domain.tokens.IsAmountSubtractAvailableUseCase
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
|
||||
|
|
@ -59,6 +60,7 @@ internal class SwapTransferInteractorImplTest {
|
|||
private val getCurrencyCheckUseCase: GetCurrencyCheckUseCase = mockk()
|
||||
private val isAmountSubtractAvailableUseCase: IsAmountSubtractAvailableUseCase = mockk()
|
||||
private val tangemPayWithdrawUseCase: TangemPayWithdrawUseCase = mockk()
|
||||
private val getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase = mockk(relaxed = true)
|
||||
|
||||
private val sut = SwapTransferInteractorImpl(
|
||||
swapFeatureToggles = swapFeatureToggles,
|
||||
|
|
@ -73,6 +75,7 @@ internal class SwapTransferInteractorImplTest {
|
|||
getCurrencyCheckUseCase = getCurrencyCheckUseCase,
|
||||
isAmountSubtractAvailableUseCase = isAmountSubtractAvailableUseCase,
|
||||
tangemPayWithdrawUseCase = tangemPayWithdrawUseCase,
|
||||
getBalanceNotEnoughForFeeWarningUseCase = getBalanceNotEnoughForFeeWarningUseCase,
|
||||
)
|
||||
|
||||
@AfterEach
|
||||
|
|
@ -170,6 +173,7 @@ internal class SwapTransferInteractorImplTest {
|
|||
swapCurrencyStatus = toCurrencyStatus,
|
||||
amountFiat = expectedFiat,
|
||||
),
|
||||
cryptoCurrencyWarning = null,
|
||||
isInsufficientBalance = false,
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = true,
|
||||
|
|
@ -240,6 +244,7 @@ internal class SwapTransferInteractorImplTest {
|
|||
swapCurrencyStatus = toCurrencyStatus,
|
||||
amountFiat = expectedFiat,
|
||||
),
|
||||
cryptoCurrencyWarning = null,
|
||||
isInsufficientBalance = true,
|
||||
appCurrency = appCurrency,
|
||||
isBalanceHidden = true,
|
||||
|
|
@ -313,24 +318,36 @@ internal class SwapTransferInteractorImplTest {
|
|||
|
||||
@Test
|
||||
fun `GIVEN valid amount and destination WHEN loadFee THEN return TransactionFee from use case`() = runTest {
|
||||
val userWallet: UserWallet = mockk()
|
||||
val userWalletId: UserWalletId = mockk()
|
||||
val userWallet: UserWallet = mockk { every { walletId } returns userWalletId }
|
||||
val network: Network = mockk()
|
||||
val fromCurrencyStatus = buildCurrencyStatus(
|
||||
rawCurrencyId = FROM_RAW_CURRENCY_ID,
|
||||
decimals = FROM_DECIMALS,
|
||||
userWallet = userWallet,
|
||||
network = network,
|
||||
)
|
||||
val toCurrencyStatus = buildCurrencyStatus(
|
||||
rawCurrencyId = TO_RAW_CURRENCY_ID,
|
||||
decimals = TO_DECIMALS,
|
||||
destinationAddress = DESTINATION_ADDRESS,
|
||||
)
|
||||
val transactionData: TransactionData.Uncompiled = mockk()
|
||||
val transactionFee: TransactionFee = mockk()
|
||||
coEvery {
|
||||
getFeeUseCase(
|
||||
amount = BigDecimal("1.5"),
|
||||
createTransferTransactionUseCase(
|
||||
amount = any(),
|
||||
memo = null,
|
||||
destination = DESTINATION_ADDRESS,
|
||||
userWalletId = userWalletId,
|
||||
network = network,
|
||||
)
|
||||
} returns transactionData.right()
|
||||
coEvery {
|
||||
getFeeUseCase(
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = fromCurrencyStatus.currency,
|
||||
network = network,
|
||||
transactionData = transactionData,
|
||||
)
|
||||
} returns transactionFee.right()
|
||||
|
||||
|
|
@ -343,10 +360,9 @@ internal class SwapTransferInteractorImplTest {
|
|||
assertThat(result).isEqualTo(transactionFee.right())
|
||||
coVerify {
|
||||
getFeeUseCase(
|
||||
amount = BigDecimal("1.5"),
|
||||
destination = DESTINATION_ADDRESS,
|
||||
userWallet = userWallet,
|
||||
cryptoCurrency = fromCurrencyStatus.currency,
|
||||
network = network,
|
||||
transactionData = transactionData,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -394,6 +410,7 @@ internal class SwapTransferInteractorImplTest {
|
|||
fromSwapCurrencyStatus = fromCurrencyStatus,
|
||||
toSwapCurrencyStatus = toCurrencyStatus,
|
||||
fromTokenAmount = BigDecimal("2.0"),
|
||||
selectedToken = null,
|
||||
)
|
||||
|
||||
assertThat(result).isEqualTo(feeExtended.right())
|
||||
|
|
@ -493,7 +510,7 @@ internal class SwapTransferInteractorImplTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN token and LoadedExtended fee WHEN sendTransfer THEN route via createAndSendGaslessTransactionUseCase`() =
|
||||
fun `GIVEN LoadedExtended fee with TokenCurrency normal fee WHEN sendTransfer THEN route via createAndSendGaslessTransactionUseCase`() =
|
||||
runTest {
|
||||
val userWalletId: UserWalletId = mockk()
|
||||
val userWallet: UserWallet = mockk { every { walletId } returns userWalletId }
|
||||
|
|
@ -511,7 +528,11 @@ internal class SwapTransferInteractorImplTest {
|
|||
)
|
||||
val fee: Fee = mockk()
|
||||
val txData: TransactionData.Uncompiled = mockk()
|
||||
val transactionFeeExtended: TransactionFeeExtended = mockk()
|
||||
val transactionFeeExtended: TransactionFeeExtended = mockk {
|
||||
every { transactionFee } returns mockk {
|
||||
every { normal } returns mockk<Fee.Ethereum.TokenCurrency>()
|
||||
}
|
||||
}
|
||||
val transactionFeeResult = TransactionFeeResult.LoadedExtended(transactionFeeExtended)
|
||||
coEvery {
|
||||
createTransferTransactionUseCase(
|
||||
|
|
@ -602,6 +623,62 @@ internal class SwapTransferInteractorImplTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN LoadedExtended fee with non-TokenCurrency normal fee WHEN sendTransfer THEN fall back to sendTransactionUseCase`() =
|
||||
runTest {
|
||||
val userWalletId: UserWalletId = mockk()
|
||||
val userWallet: UserWallet = mockk { every { walletId } returns userWalletId }
|
||||
val network: Network = mockk()
|
||||
val fromCurrencyStatus = buildTokenCurrencyStatus(
|
||||
rawCurrencyId = FROM_RAW_CURRENCY_ID,
|
||||
decimals = FROM_DECIMALS,
|
||||
userWallet = userWallet,
|
||||
network = network,
|
||||
)
|
||||
val toCurrencyStatus = buildTokenCurrencyStatus(
|
||||
rawCurrencyId = TO_RAW_CURRENCY_ID,
|
||||
decimals = TO_DECIMALS,
|
||||
destinationAddress = DESTINATION_ADDRESS,
|
||||
)
|
||||
val fee: Fee = mockk()
|
||||
val txData: TransactionData.Uncompiled = mockk()
|
||||
val transactionFeeExtended: TransactionFeeExtended = mockk {
|
||||
every { transactionFee } returns mockk {
|
||||
every { normal } returns mockk<Fee.Common>()
|
||||
}
|
||||
}
|
||||
val transactionFeeResult = TransactionFeeResult.LoadedExtended(transactionFeeExtended)
|
||||
coEvery {
|
||||
createTransferTransactionUseCase(
|
||||
amount = any(),
|
||||
fee = fee,
|
||||
memo = null,
|
||||
destination = DESTINATION_ADDRESS,
|
||||
userWalletId = userWalletId,
|
||||
network = network,
|
||||
)
|
||||
} returns txData.right()
|
||||
coEvery {
|
||||
sendTransactionUseCase(txData = txData, userWallet = userWallet, network = network)
|
||||
} returns TX_HASH.right()
|
||||
|
||||
val result = sut.sendTransfer(
|
||||
fromSwapCurrencyStatus = fromCurrencyStatus,
|
||||
toSwapCurrencyStatus = toCurrencyStatus,
|
||||
sendingAmount = BigDecimal("1.0"),
|
||||
fee = fee,
|
||||
transactionFeeResult = transactionFeeResult,
|
||||
)
|
||||
|
||||
assertThat(result).isEqualTo(TX_HASH.right())
|
||||
coVerify {
|
||||
sendTransactionUseCase(txData = txData, userWallet = userWallet, network = network)
|
||||
}
|
||||
coVerify(exactly = 0) {
|
||||
createAndSendGaslessTransactionUseCase(any(), any(), any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN createTransferTransactionUseCase fails WHEN sendTransfer THEN return DataError`() = runTest {
|
||||
val userWalletId: UserWalletId = mockk()
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
package com.tangem.feature.swap.analytics
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.ACCOUNT_DERIVATION_FROM
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.ACCOUNT_DERIVATION_TO
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.ERROR_CODE
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.ERROR_MESSAGE
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.FEE_TOKEN
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.PROVIDER
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.RECEIVE_TOKEN
|
||||
|
|
@ -13,6 +13,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.SEND_TOKEN
|
|||
import com.tangem.core.analytics.models.AppsFlyerIncludedEvent
|
||||
import com.tangem.core.analytics.models.getReferralParams
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.feature.swap.domain.models.domain.SwapProvider
|
||||
import com.tangem.feature.swap.domain.models.ui.FeeBucket
|
||||
|
||||
|
|
@ -247,4 +248,46 @@ sealed class SwapEvents(
|
|||
"Provider" to provider.name,
|
||||
),
|
||||
)
|
||||
|
||||
class TransferModeSwitched(
|
||||
fromCurrency: CryptoCurrency?,
|
||||
toCurrency: CryptoCurrency?,
|
||||
) : SwapEvents(
|
||||
event = "Transfer Mode Switched",
|
||||
params = mapOf(
|
||||
SEND_TOKEN to fromCurrency?.symbol.orEmpty(),
|
||||
"Send Blockchain" to fromCurrency?.network?.name.orEmpty(),
|
||||
RECEIVE_TOKEN to toCurrency?.symbol.orEmpty(),
|
||||
"Receive Blockchain" to toCurrency?.network?.name.orEmpty(),
|
||||
),
|
||||
)
|
||||
|
||||
class ButtonTransferClicked(
|
||||
fromCurrency: CryptoCurrency?,
|
||||
toCurrency: CryptoCurrency?,
|
||||
) : SwapEvents(
|
||||
event = "Button - Transfer",
|
||||
params = mapOf(
|
||||
SEND_TOKEN to fromCurrency?.symbol.orEmpty(),
|
||||
"Send Blockchain" to fromCurrency?.network?.name.orEmpty(),
|
||||
RECEIVE_TOKEN to toCurrency?.symbol.orEmpty(),
|
||||
"Receive Blockchain" to toCurrency?.network?.name.orEmpty(),
|
||||
),
|
||||
)
|
||||
|
||||
@Suppress("NullableToStringCall", "LongParameterList")
|
||||
class TransferInProgressScreen(
|
||||
fromCurrency: CryptoCurrency?,
|
||||
toCurrency: CryptoCurrency?,
|
||||
feeNetwork: Network,
|
||||
) : SwapEvents(
|
||||
event = "Transfer in Progress Screen Opened",
|
||||
params = mapOf(
|
||||
SEND_TOKEN to fromCurrency?.symbol.orEmpty(),
|
||||
"Send Blockchain" to fromCurrency?.network?.name.orEmpty(),
|
||||
RECEIVE_TOKEN to toCurrency?.symbol.orEmpty(),
|
||||
"Receive Blockchain" to toCurrency?.network?.name.orEmpty(),
|
||||
"Network fee" to feeNetwork.name,
|
||||
),
|
||||
), AppsFlyerIncludedEvent
|
||||
}
|
||||
|
|
@ -601,7 +601,15 @@ internal class SwapModel @Inject constructor(
|
|||
toSwapCurrencyStatus = toSwapCurrencyStatus,
|
||||
fromTokenAmount = lastAmount.value,
|
||||
)
|
||||
if (isUpdatedToTransferMode) return
|
||||
if (isUpdatedToTransferMode) {
|
||||
analyticsEventHandler.send(
|
||||
event = SwapEvents.TransferModeSwitched(
|
||||
fromCurrency = fromSwapCurrencyStatus.currency,
|
||||
toCurrency = toSwapCurrencyStatus.currency,
|
||||
),
|
||||
)
|
||||
return
|
||||
}
|
||||
dataState = dataState.copy(currentTransferState = null)
|
||||
modelScope.launch {
|
||||
uiState = stateBuilder.createInitialLoadingState(
|
||||
|
|
@ -770,7 +778,10 @@ internal class SwapModel @Inject constructor(
|
|||
feePaidCurrencyStatus = feePaidCryptoCurrencyStatus,
|
||||
fee = fee,
|
||||
) as? SwapState.Transfer ?: currentTransferState
|
||||
dataState = dataState.copy(currentTransferState = refreshed)
|
||||
dataState = dataState.copy(
|
||||
currentTransferState = refreshed,
|
||||
feePaidCryptoCurrency = feePaidCryptoCurrencyStatus ?: dataState.feePaidCryptoCurrency,
|
||||
)
|
||||
uiState = swapTransferStateBuilder.updateTransferButtonEnableState(
|
||||
dataState = dataState,
|
||||
transferState = refreshed,
|
||||
|
|
@ -1291,6 +1302,12 @@ internal class SwapModel @Inject constructor(
|
|||
private fun onTransferClick() {
|
||||
val fromSwapCurrencyStatus = dataState.fromSwapCurrencyStatus
|
||||
val toSwapCurrencyStatus = dataState.toSwapCurrencyStatus
|
||||
analyticsEventHandler.send(
|
||||
event = SwapEvents.ButtonTransferClicked(
|
||||
fromCurrency = fromSwapCurrencyStatus?.currency,
|
||||
toCurrency = toSwapCurrencyStatus?.currency,
|
||||
),
|
||||
)
|
||||
val fee = (feeSelectorRepository.state.value as? FeeSelectorUM.Content)?.selectedFeeItem?.fee
|
||||
if (fromSwapCurrencyStatus == null || toSwapCurrencyStatus == null) {
|
||||
TangemLogger.e("onTransferClick: missing currency status, aborting")
|
||||
|
|
@ -1332,6 +1349,7 @@ internal class SwapModel @Inject constructor(
|
|||
TangemLogger.e(
|
||||
messageString = "onTransferClick: withdrawTangemPay failed: ${error.getAnalyticsDescription()}",
|
||||
)
|
||||
startLoadingQuotesFromLastState()
|
||||
showAlert()
|
||||
}
|
||||
.onRight { result ->
|
||||
|
|
@ -1343,9 +1361,11 @@ internal class SwapModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun updateTransferModeTangemPayState() {
|
||||
sendTransferInProgressEvent()
|
||||
uiState = swapTransferStateBuilder.createTangemPayWithdrawalSuccessState(
|
||||
uiState = uiState,
|
||||
dataState = dataState,
|
||||
fee = getSelectedSwapFee()?.fee,
|
||||
onExploreClick = {
|
||||
val txUrl = uiState.successState?.txUrl.orEmpty()
|
||||
if (txUrl.isNotEmpty()) {
|
||||
|
|
@ -1373,6 +1393,7 @@ internal class SwapModel @Inject constructor(
|
|||
).fold(
|
||||
ifLeft = { error ->
|
||||
TangemLogger.e("onTransferClick: transfer failed: ${error.getAnalyticsDescription()}")
|
||||
startLoadingQuotesFromLastState()
|
||||
showAlert()
|
||||
},
|
||||
ifRight = { txHash ->
|
||||
|
|
@ -1384,14 +1405,13 @@ internal class SwapModel @Inject constructor(
|
|||
""
|
||||
}
|
||||
updateWalletBalance()
|
||||
sendTransferInProgressEvent()
|
||||
uiState = swapTransferStateBuilder.createSuccessState(
|
||||
uiState = uiState,
|
||||
dataState = dataState,
|
||||
appCurrency = selectedAppCurrencyFlow.value,
|
||||
isAccountsMode = isAccountsMode,
|
||||
txUrl = txUrl,
|
||||
timestamp = System.currentTimeMillis(),
|
||||
fee = null,
|
||||
fee = getSelectedSwapFee()?.fee,
|
||||
onExplorerClick = {
|
||||
if (txUrl.isNotEmpty()) {
|
||||
urlOpener.openUrl(txUrl)
|
||||
|
|
@ -1403,6 +1423,18 @@ internal class SwapModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun sendTransferInProgressEvent() {
|
||||
val fromSwapCurrencyStatus = dataState.fromSwapCurrencyStatus
|
||||
val toSwapCurrencyStatus = dataState.toSwapCurrencyStatus
|
||||
analyticsEventHandler.send(
|
||||
event = SwapEvents.TransferInProgressScreen(
|
||||
fromCurrency = fromSwapCurrencyStatus?.currency,
|
||||
toCurrency = toSwapCurrencyStatus?.currency,
|
||||
feeNetwork = getFeeToken().network,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun processTangemPayWithdrawal(
|
||||
fromSwapCurrencyStatus: SwapCurrencyStatus,
|
||||
swapTransactionState: SwapTransactionState.TangemPayWithdrawalData,
|
||||
|
|
@ -2245,6 +2277,7 @@ internal class SwapModel @Inject constructor(
|
|||
fromSwapCurrencyStatus = fromSwapCurrencyStatus,
|
||||
toSwapCurrencyStatus = toSwapCurrencyStatus,
|
||||
fromTokenAmount = amount,
|
||||
selectedToken = selectedToken,
|
||||
)
|
||||
}
|
||||
val quoteState = dataState.getCurrentLoadedSwapState() ?: return Either.Left(GetFeeError.UnknownError)
|
||||
|
|
@ -2300,10 +2333,6 @@ internal class SwapModel @Inject constructor(
|
|||
modelScope.launch { forceUpdateState.emit(newState.copy(isHidden = true)) }
|
||||
return
|
||||
}
|
||||
refreshTransferUIStateIfNeeded(
|
||||
feePaidCryptoCurrencyStatus = dataState.feePaidCryptoCurrency,
|
||||
fee = (newState as? FeeSelectorUM.Content)?.selectedFeeItem?.fee,
|
||||
)
|
||||
|
||||
val fromSwapCurrencyStatus = dataState.fromSwapCurrencyStatus
|
||||
val toSwapCurrencyStatus = dataState.toSwapCurrencyStatus
|
||||
|
|
@ -2312,7 +2341,13 @@ internal class SwapModel @Inject constructor(
|
|||
fromSwapCurrencyStatus?.currency,
|
||||
toSwapCurrencyStatus?.currency,
|
||||
)
|
||||
if (shouldTransferInsteadOfSwap) return
|
||||
if (shouldTransferInsteadOfSwap) {
|
||||
refreshTransferUIStateIfNeeded(
|
||||
feePaidCryptoCurrencyStatus = getSelectedSwapFee()?.selectedFeeToken,
|
||||
fee = (newState as? FeeSelectorUM.Content)?.selectedFeeItem?.fee,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val quoteState = dataState.getCurrentLoadedSwapState() ?: return
|
||||
val swapFee = getSelectedSwapFee() ?: return
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ package com.tangem.feature.swap.ui.transfer
|
|||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.common.ui.notifications.NotificationsFactory.addDustWarningNotification
|
||||
import com.tangem.common.ui.notifications.NotificationsFactory.addExceedsBalanceNotification
|
||||
import com.tangem.common.ui.notifications.NotificationsFactory.addExistentialWarningNotification
|
||||
import com.tangem.common.ui.notifications.NotificationsFactory.addFeeCoverageNotification
|
||||
import com.tangem.common.ui.notifications.NotificationsFactory.addReserveAmountErrorNotification
|
||||
import com.tangem.common.ui.notifications.NotificationsFactory.addTransactionLimitErrorNotification
|
||||
import com.tangem.common.ui.notifications.NotificationsFactory.addValidateTransactionNotifications
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.feature.swap.domain.models.SwapAmount
|
||||
import com.tangem.feature.swap.domain.models.ui.SwapState
|
||||
|
|
@ -24,12 +26,14 @@ import javax.inject.Inject
|
|||
|
||||
internal class SwapTransferNotificationsFactory @Inject constructor() {
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
fun getNotifications(
|
||||
transferState: SwapState.Transfer,
|
||||
feeCryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||
fee: Fee?,
|
||||
onReduceByAmount: (SwapAmount, BigDecimal) -> Unit,
|
||||
onReduceToAmount: (SwapAmount) -> Unit,
|
||||
onBuyClick: (CryptoCurrency) -> Unit,
|
||||
): ImmutableList<NotificationUM> {
|
||||
return buildList {
|
||||
maybeAddRentExemptionError(transferState)
|
||||
|
|
@ -41,6 +45,7 @@ internal class SwapTransferNotificationsFactory @Inject constructor() {
|
|||
onReduceToAmount = onReduceToAmount,
|
||||
)
|
||||
maybeAddNeedReserveToCreateAccountWarning(transferState)
|
||||
maybeAddExceedsBalanceNotification(transferState, onBuyClick)
|
||||
}.toPersistentList()
|
||||
}
|
||||
|
||||
|
|
@ -172,4 +177,21 @@ internal class SwapTransferNotificationsFactory @Inject constructor() {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<NotificationUM>.maybeAddExceedsBalanceNotification(
|
||||
transferState: SwapState.Transfer,
|
||||
onBuyClick: (CryptoCurrency) -> Unit,
|
||||
) {
|
||||
val cryptoCurrencyStatus = transferState.fromTokenInfo.swapCurrencyStatus.status
|
||||
addExceedsBalanceNotification(
|
||||
cryptoCurrencyWarning = transferState.cryptoCurrencyWarning,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
shouldMergeFeeNetworkName = BlockchainUtils.isArbitrum(
|
||||
networkId = cryptoCurrencyStatus.currency.network.rawId,
|
||||
),
|
||||
onClick = onBuyClick,
|
||||
onAnalyticsEvent = {},
|
||||
onResetAnalyticsEvent = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -59,6 +59,7 @@ internal class SwapTransferStateBuilder @Inject constructor(
|
|||
transferState = transferState,
|
||||
feeCryptoCurrencyStatus = feePaidCryptoCurrencyStatus,
|
||||
fee = fee,
|
||||
onBuyClick = actions.openTokenDetailsScreen,
|
||||
onReduceByAmount = actions.onReduceByAmount,
|
||||
onReduceToAmount = actions.onReduceToAmount,
|
||||
)
|
||||
|
|
@ -227,6 +228,7 @@ internal class SwapTransferStateBuilder @Inject constructor(
|
|||
transferState = transferState,
|
||||
feeCryptoCurrencyStatus = feePaidCryptoCurrencyStatus,
|
||||
fee = fee,
|
||||
onBuyClick = actions.openTokenDetailsScreen,
|
||||
onReduceByAmount = actions.onReduceByAmount,
|
||||
onReduceToAmount = actions.onReduceToAmount,
|
||||
)
|
||||
|
|
@ -325,13 +327,12 @@ internal class SwapTransferStateBuilder @Inject constructor(
|
|||
fun createSuccessState(
|
||||
uiState: SwapStateHolder,
|
||||
dataState: SwapProcessDataState,
|
||||
appCurrency: AppCurrency,
|
||||
isAccountsMode: Boolean,
|
||||
fee: Fee?,
|
||||
txUrl: String,
|
||||
timestamp: Long,
|
||||
fee: TextReference?,
|
||||
onExplorerClick: () -> Unit,
|
||||
): SwapStateHolder {
|
||||
val transferState = requireNotNull(dataState.currentTransferState)
|
||||
val fromSwapCurrencyStatus = requireNotNull(dataState.fromSwapCurrencyStatus)
|
||||
val toSwapCurrencyStatus = requireNotNull(dataState.toSwapCurrencyStatus)
|
||||
val amount = dataState.amount?.parseBigDecimalOrNull() ?: BigDecimal.ZERO
|
||||
|
|
@ -341,11 +342,11 @@ internal class SwapTransferStateBuilder @Inject constructor(
|
|||
val fromAmountText = amount.format { crypto(fromCurrency.symbol, fromCurrency.decimals) }
|
||||
val toAmountText = amount.format { crypto(toCurrency.symbol, toCurrency.decimals) }
|
||||
val fromFiatAmount = getFormattedFiatAmount(
|
||||
appCurrency = appCurrency,
|
||||
appCurrency = transferState.appCurrency,
|
||||
amount = fromSwapCurrencyStatus.status.value.fiatRate?.multiply(amount),
|
||||
)
|
||||
val toFiatAmount = getFormattedFiatAmount(
|
||||
appCurrency = appCurrency,
|
||||
appCurrency = transferState.appCurrency,
|
||||
amount = toSwapCurrencyStatus.status.value.fiatRate?.multiply(amount),
|
||||
)
|
||||
|
||||
|
|
@ -359,15 +360,15 @@ internal class SwapTransferStateBuilder @Inject constructor(
|
|||
isTransferMode = true,
|
||||
providerIcon = "",
|
||||
rate = TextReference.EMPTY,
|
||||
fee = fee,
|
||||
fee = fee?.let { formatFeeForSuccess(transferState = transferState, fee = it) },
|
||||
fromTitle = getCardAccountTitle(
|
||||
account = fromSwapCurrencyStatus.account,
|
||||
isAccountsMode = isAccountsMode,
|
||||
isAccountsMode = transferState.isAccountsMode,
|
||||
isFromCard = true,
|
||||
),
|
||||
toTitle = getCardAccountTitle(
|
||||
account = toSwapCurrencyStatus.account,
|
||||
isAccountsMode = isAccountsMode,
|
||||
isAccountsMode = transferState.isAccountsMode,
|
||||
isFromCard = false,
|
||||
),
|
||||
fromTokenAmount = stringReference(fromAmountText),
|
||||
|
|
@ -385,6 +386,7 @@ internal class SwapTransferStateBuilder @Inject constructor(
|
|||
fun createTangemPayWithdrawalSuccessState(
|
||||
uiState: SwapStateHolder,
|
||||
dataState: SwapProcessDataState,
|
||||
fee: Fee?,
|
||||
onExploreClick: () -> Unit,
|
||||
): SwapStateHolder {
|
||||
val fromSwapCurrencyStatus = requireNotNull(dataState.fromSwapCurrencyStatus)
|
||||
|
|
@ -407,7 +409,7 @@ internal class SwapTransferStateBuilder @Inject constructor(
|
|||
isTransferMode = true,
|
||||
providerIcon = "",
|
||||
rate = TextReference.EMPTY,
|
||||
fee = null,
|
||||
fee = fee?.let { formatFeeForSuccess(transferState = transferState, fee = it) },
|
||||
fromTitle = getCardAccountTitle(
|
||||
account = fromSwapCurrencyStatus.account,
|
||||
isAccountsMode = transferState.isAccountsMode,
|
||||
|
|
@ -429,4 +431,19 @@ internal class SwapTransferStateBuilder @Inject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun formatFeeForSuccess(transferState: SwapState.Transfer, fee: Fee): TextReference {
|
||||
val feeAmount = fee.amount
|
||||
val totalFeeValue = feeAmount.value ?: BigDecimal.ZERO
|
||||
val cryptoFormatted = totalFeeValue.format {
|
||||
crypto(symbol = feeAmount.currencySymbol, decimals = feeAmount.decimals)
|
||||
}
|
||||
val appCurrency = transferState.appCurrency
|
||||
val swapCurrencyStatus = transferState.fromTokenInfo.swapCurrencyStatus
|
||||
val fiatRate = swapCurrencyStatus.status.value.fiatRate
|
||||
val fiatFormatted = fiatRate?.multiply(totalFeeValue).format {
|
||||
fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol)
|
||||
}
|
||||
return stringReference("$cryptoFormatted ($fiatFormatted)")
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@ internal class SwapTransferNotificationsFactoryTest {
|
|||
fee = null,
|
||||
onReduceByAmount = { _, _ -> },
|
||||
onReduceToAmount = {},
|
||||
onBuyClick = {},
|
||||
)
|
||||
|
||||
assertThat(result).isEmpty()
|
||||
|
|
@ -65,6 +66,7 @@ internal class SwapTransferNotificationsFactoryTest {
|
|||
fee = null,
|
||||
onReduceByAmount = { _, _ -> },
|
||||
onReduceToAmount = {},
|
||||
onBuyClick = {},
|
||||
)
|
||||
|
||||
assertThat(result.filterIsInstance<NotificationUM.Solana.RentInfo>()).hasSize(1)
|
||||
|
|
@ -91,6 +93,7 @@ internal class SwapTransferNotificationsFactoryTest {
|
|||
fee = fee,
|
||||
onReduceByAmount = { _, _ -> },
|
||||
onReduceToAmount = {},
|
||||
onBuyClick = {},
|
||||
)
|
||||
|
||||
assertThat(result.filterIsInstance<NotificationUM.Error.ExistentialDeposit>()).hasSize(1)
|
||||
|
|
@ -113,6 +116,7 @@ internal class SwapTransferNotificationsFactoryTest {
|
|||
fee = null,
|
||||
onReduceByAmount = { _, _ -> },
|
||||
onReduceToAmount = {},
|
||||
onBuyClick = {},
|
||||
)
|
||||
|
||||
assertThat(result.filterIsInstance<NotificationUM.Error.MinimumAmountError>()).hasSize(1)
|
||||
|
|
@ -131,6 +135,7 @@ internal class SwapTransferNotificationsFactoryTest {
|
|||
fee = null,
|
||||
onReduceByAmount = { _, _ -> },
|
||||
onReduceToAmount = {},
|
||||
onBuyClick = {},
|
||||
)
|
||||
|
||||
assertThat(result.filterIsInstance<NotificationUM.Cardano.MinAdaValueCharged>()).hasSize(1)
|
||||
|
|
@ -154,6 +159,7 @@ internal class SwapTransferNotificationsFactoryTest {
|
|||
fee = null,
|
||||
onReduceByAmount = { _, _ -> },
|
||||
onReduceToAmount = {},
|
||||
onBuyClick = {},
|
||||
)
|
||||
|
||||
assertThat(result.filterIsInstance<NotificationUM.Warning.FeeCoverageNotification>()).hasSize(1)
|
||||
|
|
@ -176,6 +182,7 @@ internal class SwapTransferNotificationsFactoryTest {
|
|||
fee = null,
|
||||
onReduceByAmount = { _, _ -> },
|
||||
onReduceToAmount = {},
|
||||
onBuyClick = {},
|
||||
)
|
||||
|
||||
val reserve = result.filterIsInstance<SwapNotificationUM.Warning.NeedReserveToCreateAccount>()
|
||||
|
|
@ -199,15 +206,39 @@ internal class SwapTransferNotificationsFactoryTest {
|
|||
fee = null,
|
||||
onReduceByAmount = { _, _ -> },
|
||||
onReduceToAmount = {},
|
||||
onBuyClick = {},
|
||||
)
|
||||
|
||||
assertThat(result.filterIsInstance<SwapNotificationUM.Warning.ReduceAmount>()).hasSize(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN BalanceNotEnoughForFee warning WHEN getNotifications THEN TokenExceedsBalance is added`() = runTest {
|
||||
val warning = CryptoCurrencyWarning.BalanceNotEnoughForFee(
|
||||
tokenCurrency = buildCoin(),
|
||||
coinCurrency = buildCoin(),
|
||||
)
|
||||
val transferState = buildTransferState(
|
||||
cryptoCurrencyWarning = warning,
|
||||
)
|
||||
|
||||
val result = sut.getNotifications(
|
||||
transferState = transferState,
|
||||
feeCryptoCurrencyStatus = null,
|
||||
fee = null,
|
||||
onReduceByAmount = { _, _ -> },
|
||||
onReduceToAmount = {},
|
||||
onBuyClick = {},
|
||||
)
|
||||
|
||||
assertThat(result.filterIsInstance<NotificationUM.Error.TokenExceedsBalance>()).hasSize(1)
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
private fun buildTransferState(
|
||||
fromTokenInfo: TokenSwapInfo = buildTokenInfo(buildCoinStatus()),
|
||||
toTokenInfo: TokenSwapInfo = buildTokenInfo(buildCoinStatus()),
|
||||
cryptoCurrencyWarning: CryptoCurrencyWarning? = null,
|
||||
currencyCheck: CryptoCurrencyCheck? = null,
|
||||
validationResult: Throwable? = null,
|
||||
minAdaValue: BigDecimal? = null,
|
||||
|
|
@ -217,6 +248,7 @@ internal class SwapTransferNotificationsFactoryTest {
|
|||
userWallet = coldWallet,
|
||||
fromTokenInfo = fromTokenInfo,
|
||||
toTokenInfo = toTokenInfo,
|
||||
cryptoCurrencyWarning = cryptoCurrencyWarning,
|
||||
isInsufficientBalance = false,
|
||||
appCurrency = AppCurrency.Default,
|
||||
isBalanceHidden = false,
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ internal class SwapTransferStateBuilderTest {
|
|||
fee = any(),
|
||||
onReduceByAmount = any(),
|
||||
onReduceToAmount = any(),
|
||||
onBuyClick = any(),
|
||||
)
|
||||
} returns persistentListOf()
|
||||
}
|
||||
|
|
@ -129,6 +130,7 @@ internal class SwapTransferStateBuilderTest {
|
|||
fee = null,
|
||||
onReduceByAmount = any(),
|
||||
onReduceToAmount = any(),
|
||||
onBuyClick = any(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -170,6 +172,7 @@ internal class SwapTransferStateBuilderTest {
|
|||
fee = null,
|
||||
onReduceByAmount = any(),
|
||||
onReduceToAmount = any(),
|
||||
onBuyClick = any(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -212,6 +215,7 @@ internal class SwapTransferStateBuilderTest {
|
|||
fee = null,
|
||||
onReduceByAmount = any(),
|
||||
onReduceToAmount = any(),
|
||||
onBuyClick = any(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -260,6 +264,7 @@ internal class SwapTransferStateBuilderTest {
|
|||
fee = null,
|
||||
onReduceByAmount = any(),
|
||||
onReduceToAmount = any(),
|
||||
onBuyClick = any(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -307,6 +312,7 @@ internal class SwapTransferStateBuilderTest {
|
|||
fee = fee,
|
||||
onReduceByAmount = any(),
|
||||
onReduceToAmount = any(),
|
||||
onBuyClick = any(),
|
||||
)
|
||||
} returns persistentListOf()
|
||||
|
||||
|
|
@ -330,6 +336,7 @@ internal class SwapTransferStateBuilderTest {
|
|||
fee = fee,
|
||||
onReduceByAmount = any(),
|
||||
onReduceToAmount = any(),
|
||||
onBuyClick = any(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -468,25 +475,40 @@ internal class SwapTransferStateBuilderTest {
|
|||
|
||||
@Test
|
||||
fun `GIVEN dataState with from-to currencies WHEN createSuccessState THEN success holder is built in transfer mode with given fee and txUrl`() {
|
||||
val appCurrency = AppCurrency(code = "USD", name = "US Dollar", symbol = "$")
|
||||
val amount = BigDecimal("1.5")
|
||||
val transferState = buildTransferState(
|
||||
fromAmount = amount,
|
||||
toAmount = amount,
|
||||
isAccountsMode = true,
|
||||
)
|
||||
val dataState = SwapProcessDataState(
|
||||
fromSwapCurrencyStatus = fromCurrencyStatus,
|
||||
toSwapCurrencyStatus = toCurrencyStatus,
|
||||
amount = amount.toPlainString(),
|
||||
currentTransferState = transferState,
|
||||
)
|
||||
val feeValue = BigDecimal("0.001")
|
||||
val fee = Fee.Common(
|
||||
amount = Amount(currencySymbol = "ETH", value = feeValue, decimals = 18),
|
||||
)
|
||||
val appCurrency = transferState.appCurrency
|
||||
val expectedFee = stringReference(
|
||||
"${feeValue.format { crypto(symbol = "ETH", decimals = 18) }} " +
|
||||
"(${
|
||||
fromCurrencyStatus.status.value.fiatRate!!.multiply(feeValue).format {
|
||||
fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol)
|
||||
}
|
||||
})",
|
||||
)
|
||||
val fee: TextReference = stringReference("0.001 ETH")
|
||||
val txUrl = "https://explorer.example/tx/0xabc"
|
||||
val timestamp = 1_700_000_000_000L
|
||||
|
||||
val result = sut.createSuccessState(
|
||||
uiState = baseStateHolder(),
|
||||
dataState = dataState,
|
||||
appCurrency = appCurrency,
|
||||
isAccountsMode = true,
|
||||
fee = fee,
|
||||
txUrl = txUrl,
|
||||
timestamp = timestamp,
|
||||
fee = fee,
|
||||
onExplorerClick = {},
|
||||
)
|
||||
|
||||
|
|
@ -495,7 +517,7 @@ internal class SwapTransferStateBuilderTest {
|
|||
assertThat(success.shouldShowStatusButton).isFalse()
|
||||
assertThat(success.timestamp).isEqualTo(timestamp)
|
||||
assertThat(success.txUrl).isEqualTo(txUrl)
|
||||
assertThat(success.fee).isEqualTo(fee)
|
||||
assertThat(success.fee).isEqualTo(expectedFee)
|
||||
assertThat(success.providerName).isEqualTo(TextReference.EMPTY)
|
||||
assertThat(success.providerType).isEqualTo(TextReference.EMPTY)
|
||||
assertThat(success.providerIcon).isEmpty()
|
||||
|
|
@ -613,6 +635,7 @@ internal class SwapTransferStateBuilderTest {
|
|||
val result = sut.createTangemPayWithdrawalSuccessState(
|
||||
uiState = baseStateHolder(),
|
||||
dataState = dataState,
|
||||
fee = null,
|
||||
onExploreClick = onExploreClick,
|
||||
)
|
||||
val after = System.currentTimeMillis()
|
||||
|
|
@ -707,6 +730,7 @@ internal class SwapTransferStateBuilderTest {
|
|||
userWallet = coldWallet,
|
||||
fromTokenInfo = fromInfo,
|
||||
toTokenInfo = toInfo,
|
||||
cryptoCurrencyWarning = null,
|
||||
isInsufficientBalance = isInsufficientBalance,
|
||||
appCurrency = AppCurrency.Default,
|
||||
isBalanceHidden = false,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue