Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-29 19:47:19 +01:00
parent e2d0973392
commit bb5d6848d9
10 changed files with 339 additions and 43 deletions

View file

@ -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
}

View file

@ -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

View file

@ -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 = {},
)
}
}

View file

@ -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)")
}
}

View file

@ -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,

View file

@ -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,