Updated on 2026-08-14

This commit is contained in:
Tangem 2023-01-27 15:30:12 +03:00
parent 3ad192c433
commit 93349d80f4
18 changed files with 247 additions and 42 deletions

View file

@ -148,6 +148,10 @@ class TransactionManagerImpl(
}
}
override fun getBlockchainId(networkId: String): String {
return requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }.id
}
private fun handleSendResult(result: SimpleResult): SendTxResult {
when (result) {
is SimpleResult.Success -> return SendTxResult.Success

View file

@ -0,0 +1,27 @@
package com.tangem.core.ui.utils
/**
* Formats input [String] for InputField, to remove wrong symbols, letters etc
* Use [decimals] for cut this number symbols after floating point
*
* Example (with 8 decimals):
* input string - ab123.46377372ab53
* result string 123.46377372
*/
fun getValidatedNumberWithFixedDecimals(text: String, decimals: Int): String {
val filteredChars = text.filterIndexed { index, c ->
c.isDigit()
|| (c == '.' && index != 0 && text.indexOf('.') == index)
|| (c == '.' && index != 0 && text.count { it == '.' } <= 1)
}
// If dot is present, take first 3 digits before decimal and first decimals digits after decimal
return if (filteredChars.count { it == '.' } == 1) {
val beforeDecimal = filteredChars.substringBefore('.')
val afterDecimal = filteredChars.substringAfter('.')
beforeDecimal + "." + afterDecimal.take(decimals)
}
// If there is no dot, just take all digits
else {
filteredChars
}
}

View file

@ -0,0 +1,15 @@
package com.tangem.feature.swap.domain
import com.tangem.feature.swap.domain.models.domain.Currency
interface BlockchainInteractor {
fun getTokenDecimals(token: Currency): Int
/**
* In app blockchain id, actual in blockchain sdk, not the same as networkId
*
* workaround till not use backend only and not integrated server vs sdk
*/
fun getBlockchainId(networkId: String): String
}

View file

@ -0,0 +1,22 @@
package com.tangem.feature.swap.domain
import com.tangem.feature.swap.domain.models.domain.Currency
import com.tangem.lib.crypto.TransactionManager
import javax.inject.Inject
internal class BlockchainInteractorImpl @Inject constructor(
private val transactionManager: TransactionManager,
) : BlockchainInteractor {
override fun getBlockchainId(networkId: String): String {
return transactionManager.getBlockchainId(networkId)
}
override fun getTokenDecimals(token: Currency): Int {
return if (token is Currency.NonNativeToken) {
token.decimalCount
} else {
transactionManager.getNativeTokenDecimals(token.networkId)
}
}
}

View file

@ -91,8 +91,6 @@ interface SwapInteractor {
amountToSwap: String,
): TxState
fun getTokenDecimals(token: Currency): Int
/**
* Returns token in wallet balance
*

View file

@ -215,7 +215,7 @@ internal class SwapInteractorImpl @Inject constructor(
userWalletManager.addToken(cryptoCurrencyConverter.convert(currencyToGet))
TxState.TxSent(
fromAmount = amountFormatter.formatSwapAmountToUI(swapData.fromTokenAmount, currencyToSend.symbol),
toAmount = amountFormatter.formatSwapAmountToUI(swapData.toTokenAmount, currencyToSend.symbol),
toAmount = amountFormatter.formatSwapAmountToUI(swapData.toTokenAmount, currencyToGet.symbol),
)
}
SendTxResult.UserCancelledError -> TxState.UserCancelled
@ -225,7 +225,13 @@ internal class SwapInteractorImpl @Inject constructor(
}
}
override fun getTokenDecimals(token: Currency): Int {
override fun getTokenBalance(token: Currency): SwapAmount {
return userWalletManager.getCurrentWalletTokensBalance(token.networkId)[token.symbol]?.let {
SwapAmount(it.value, it.decimals)
} ?: SwapAmount(BigDecimal.ZERO, getTokenDecimals(token))
}
fun getTokenDecimals(token: Currency): Int {
return if (token is Currency.NonNativeToken) {
token.decimalCount
} else {
@ -233,12 +239,6 @@ internal class SwapInteractorImpl @Inject constructor(
}
}
override fun getTokenBalance(token: Currency): SwapAmount {
return userWalletManager.getCurrentWalletTokensBalance(token.networkId)[token.symbol]?.let {
SwapAmount(it.value, it.decimals)
} ?: SwapAmount(BigDecimal.ZERO, getTokenDecimals(token))
}
private fun selectToToken(
initialToken: Currency,
tokensInWallet: List<Currency>,

View file

@ -1,6 +1,8 @@
package com.tangem.feature.swap.domain.di
import com.tangem.feature.swap.domain.AllowPermissionsHandlerImpl
import com.tangem.feature.swap.domain.BlockchainInteractor
import com.tangem.feature.swap.domain.BlockchainInteractorImpl
import com.tangem.feature.swap.domain.SwapInteractor
import com.tangem.feature.swap.domain.SwapInteractorImpl
import com.tangem.feature.swap.domain.SwapRepository
@ -32,4 +34,14 @@ class SwapDomainModule {
allowPermissionsHandler = AllowPermissionsHandlerImpl(),
)
}
@Provides
@Singleton
fun provideBlockchainInteractor(
transactionManager: TransactionManager,
): BlockchainInteractor {
return BlockchainInteractorImpl(
transactionManager = transactionManager,
)
}
}

View file

@ -29,4 +29,8 @@ sealed class Currency {
val contractAddress: String,
val decimalCount: Int,
) : Currency()
}
fun Currency.isNonNative(): Boolean {
return this is Currency.NonNativeToken
}

View file

@ -49,6 +49,7 @@ android {
dependencies {
/** Core modules */
implementation(project(":core:analytics"))
implementation(project(":core:utils"))
implementation(project(":core:ui"))

View file

@ -0,0 +1,32 @@
package com.tangem.feature.swap.analytics
import com.tangem.core.analytics.AnalyticsEvent
sealed class SwapEvents(
event: String,
params: Map<String, String> = mapOf(),
) : AnalyticsEvent(SWAP_CATEGORY, event, params) {
data class SwapScreenOpened(val token: String) : SwapEvents(
event = "Swap Screen Opened",
params = mapOf("Token" to token),
)
object SendTokenBalanceClicked : SwapEvents(event = "Send Token Balance Clicked")
object ReceiveTokenClicked : SwapEvents(event = "Receive Token Clicked")
object ChooseTokenScreenOpened : SwapEvents(event = "Choose Token Screen Opened")
object SearchTokenClicked : SwapEvents(event = "Search Token Clicked")
data class ButtonSwapClicked(val sendToken: String, val receiveToken: String) : SwapEvents(
event = "Button - Swap",
params = mapOf("Send Token" to sendToken, "Receive Token" to receiveToken),
)
object ButtonGivePermissionClicked : SwapEvents(event = "Button - Give permission") // ?
object ButtonPermissionApproveClicked : SwapEvents(event = "Button - Permission Approve")
object ButtonPermissionCancelClicked : SwapEvents(event = "Button - Permission Cancel")
object ButtonPermitAndSwapClicked : SwapEvents(event = "Button - Permit and Swap") // ?
object ButtonSwipeClicked : SwapEvents(event = "Button - Swipe")
object SwapInProgressScreen : SwapEvents(event = "Swap in Progress Screen Opened")
}
private const val SWAP_CATEGORY = "Swap"

View file

@ -1,12 +1,11 @@
package com.tangem.feature.swap.models
import androidx.annotation.DrawableRes
data class SwapStateHolder(
val sendCardData: SwapCardData,
val receiveCardData: SwapCardData,
val networkCurrency: String,
val networkId: String,
val blockchainId: String, // not the same as networkId, its local id in app
val fee: FeeState = FeeState.Empty,
val warnings: List<SwapWarning> = emptyList(),
val alert: SwapWarning.GenericWarning? = null,
@ -24,6 +23,8 @@ data class SwapStateHolder(
val onSelectTokenClick: (() -> Unit)? = null,
val onSuccess: (() -> Unit)? = null,
val onMaxAmountSelected: (() -> Unit)? = null,
val onShowPermissionBottomSheet: () -> Unit = {},
val onCancelPermissionBottomSheet: () -> Unit = {},
)
data class SwapCardData(
@ -34,7 +35,7 @@ data class SwapCardData(
val tokenIconUrl: String,
val tokenCurrency: String,
val balance: String,
@DrawableRes val networkIconRes: Int? = null,
val isNotNativeToken: Boolean,
val canSelectAnotherToken: Boolean = false,
)

View file

@ -9,4 +9,6 @@ data class UiActions(
val onChangeCardsClicked: () -> Unit,
val onBackClicked: () -> Unit,
val onMaxAmountSelected: () -> Unit,
val openPermissionBottomSheet: () -> Unit,
val hidePermissionBottomSheet: () -> Unit,
)

View file

@ -34,6 +34,7 @@ class SwapFragment : Fragment() {
customTabsManager = CustomTabsManager(WeakReference(activity?.application)),
),
)
viewModel.onScreenOpened()
activity?.onBackPressedDispatcher?.addCallback(
viewLifecycleOwner,

View file

@ -3,6 +3,7 @@ package com.tangem.feature.swap.ui
import com.tangem.feature.swap.converters.TokensDataConverter
import com.tangem.feature.swap.domain.models.DataError
import com.tangem.feature.swap.domain.models.domain.Currency
import com.tangem.feature.swap.domain.models.domain.isNonNative
import com.tangem.feature.swap.domain.models.formatToUIRepresentation
import com.tangem.feature.swap.domain.models.ui.FoundTokensState
import com.tangem.feature.swap.domain.models.ui.PermissionDataState
@ -27,9 +28,10 @@ class StateBuilder(val actions: UiActions) {
private val tokensDataConverter = TokensDataConverter(actions.onSearchEntered, actions.onTokenSelected)
fun createInitialLoadingState(initialCurrency: Currency): SwapStateHolder {
fun createInitialLoadingState(initialCurrency: Currency, blockchainId: String): SwapStateHolder {
return SwapStateHolder(
networkId = initialCurrency.networkId,
blockchainId = blockchainId,
sendCardData = SwapCardData(
type = TransactionCardType.SendCard(actions.onAmountChanged),
amount = null,
@ -38,6 +40,7 @@ class StateBuilder(val actions: UiActions) {
tokenCurrency = initialCurrency.symbol,
coinId = initialCurrency.id,
canSelectAnotherToken = false,
isNotNativeToken = initialCurrency.isNonNative(),
balance = "",
),
receiveCardData = SwapCardData(
@ -48,6 +51,7 @@ class StateBuilder(val actions: UiActions) {
tokenCurrency = "",
canSelectAnotherToken = false,
balance = "",
isNotNativeToken = false,
coinId = null,
),
fee = FeeState.Loading,
@ -58,6 +62,8 @@ class StateBuilder(val actions: UiActions) {
onChangeCardsClicked = actions.onChangeCardsClicked,
onMaxAmountSelected = actions.onMaxAmountSelected,
updateInProgress = true,
onShowPermissionBottomSheet = actions.openPermissionBottomSheet,
onCancelPermissionBottomSheet = actions.hidePermissionBottomSheet,
)
}
@ -75,6 +81,7 @@ class StateBuilder(val actions: UiActions) {
tokenIconUrl = fromToken.logoUrl,
tokenCurrency = fromToken.symbol,
coinId = fromToken.id,
isNotNativeToken = fromToken.isNonNative(),
canSelectAnotherToken = mainTokenId != fromToken.id,
balance = "",
),
@ -85,6 +92,7 @@ class StateBuilder(val actions: UiActions) {
tokenIconUrl = toToken.logoUrl,
tokenCurrency = toToken.symbol,
coinId = toToken.id,
isNotNativeToken = toToken.isNonNative(),
canSelectAnotherToken = mainTokenId != toToken.id,
balance = "",
),
@ -119,6 +127,7 @@ class StateBuilder(val actions: UiActions) {
amountEquivalent = quoteModel.fromTokenInfo.tokenFiatBalance,
tokenIconUrl = uiStateHolder.sendCardData.tokenIconUrl,
coinId = quoteModel.fromTokenInfo.coinId,
isNotNativeToken = uiStateHolder.sendCardData.isNotNativeToken,
tokenCurrency = uiStateHolder.sendCardData.tokenCurrency,
canSelectAnotherToken = uiStateHolder.sendCardData.canSelectAnotherToken,
balance = quoteModel.fromTokenInfo.tokenWalletBalance,
@ -129,6 +138,7 @@ class StateBuilder(val actions: UiActions) {
amountEquivalent = quoteModel.toTokenInfo.tokenFiatBalance,
tokenIconUrl = uiStateHolder.receiveCardData.tokenIconUrl,
coinId = quoteModel.toTokenInfo.coinId,
isNotNativeToken = uiStateHolder.receiveCardData.isNotNativeToken,
tokenCurrency = uiStateHolder.receiveCardData.tokenCurrency,
canSelectAnotherToken = uiStateHolder.receiveCardData.canSelectAnotherToken,
balance = quoteModel.toTokenInfo.tokenWalletBalance,
@ -159,6 +169,7 @@ class StateBuilder(val actions: UiActions) {
amountEquivalent = "",
tokenIconUrl = uiStateHolder.sendCardData.tokenIconUrl,
coinId = uiStateHolder.sendCardData.coinId,
isNotNativeToken = uiStateHolder.sendCardData.isNotNativeToken,
tokenCurrency = uiStateHolder.sendCardData.tokenCurrency,
canSelectAnotherToken = uiStateHolder.sendCardData.canSelectAnotherToken,
balance = emptyAmountState.fromTokenWalletBalance,
@ -169,6 +180,7 @@ class StateBuilder(val actions: UiActions) {
amountEquivalent = "",
tokenIconUrl = uiStateHolder.receiveCardData.tokenIconUrl,
coinId = uiStateHolder.receiveCardData.coinId,
isNotNativeToken = uiStateHolder.receiveCardData.isNotNativeToken,
tokenCurrency = uiStateHolder.receiveCardData.tokenCurrency,
canSelectAnotherToken = uiStateHolder.receiveCardData.canSelectAnotherToken,
balance = emptyAmountState.toTokenWalletBalance,

View file

@ -31,7 +31,12 @@ internal fun SwapScreen(stateHolder: SwapStateHolder) {
if (stateHolder.permissionState is SwapPermissionState.ReadyForRequest) {
SwapPermissionBottomSheetContent(
data = stateHolder.permissionState,
onCancel = { coroutineScope.launch { bottomSheetState.hide() } },
onCancel = {
coroutineScope.launch {
stateHolder.onCancelPermissionBottomSheet.invoke()
bottomSheetState.hide()
}
},
)
} else {
// Required "else" block to prevent compose crash
@ -55,7 +60,12 @@ internal fun SwapScreen(stateHolder: SwapStateHolder) {
val isBottomSheetReady = !bottomSheetState.isVisible &&
stateHolder.permissionState is SwapPermissionState.ReadyForRequest
coroutineScope.launch {
if (isBottomSheetReady) bottomSheetState.show() else bottomSheetState.hide()
if (isBottomSheetReady) {
bottomSheetState.show()
stateHolder.onShowPermissionBottomSheet.invoke()
} else {
bottomSheetState.hide()
}
}
},
)

View file

@ -21,6 +21,7 @@ import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
@ -39,6 +40,7 @@ import com.tangem.core.ui.components.SmallInfoCardWithWarning
import com.tangem.core.ui.components.SpacerH16
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.components.keyboardAsState
import com.tangem.core.ui.extensions.getActiveIconRes
import com.tangem.core.ui.extensions.getActiveIconResByCoinId
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.swap.models.FeeState
@ -161,6 +163,9 @@ private fun MainInfo(state: SwapStateHolder) {
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center,
) {
val networkIconRes = remember {
getActiveIconRes(state.blockchainId)
}
Column {
TransactionCard(
type = state.sendCardData.type,
@ -169,7 +174,7 @@ private fun MainInfo(state: SwapStateHolder) {
amountEquivalent = state.sendCardData.amountEquivalent,
tokenIconUrl = state.sendCardData.tokenIconUrl,
tokenCurrency = state.sendCardData.tokenCurrency,
networkIconRes = state.sendCardData.networkIconRes,
networkIconRes = if (state.sendCardData.isNotNativeToken) networkIconRes else null,
iconPlaceholder = state.sendCardData.coinId?.let {
getActiveIconResByCoinId(it, state.networkId)
},
@ -183,7 +188,7 @@ private fun MainInfo(state: SwapStateHolder) {
amountEquivalent = state.receiveCardData.amountEquivalent,
tokenIconUrl = state.receiveCardData.tokenIconUrl,
tokenCurrency = state.receiveCardData.tokenCurrency,
networkIconRes = state.receiveCardData.networkIconRes,
networkIconRes = if (state.receiveCardData.isNotNativeToken) networkIconRes else null,
iconPlaceholder = state.receiveCardData.coinId?.let {
getActiveIconResByCoinId(it, state.networkId)
},
@ -314,7 +319,7 @@ private val sendCard = SwapCardData(
amountEquivalent = "1 000 000",
tokenIconUrl = "",
tokenCurrency = "DAI",
networkIconRes = R.drawable.img_polygon_22,
isNotNativeToken = true,
canSelectAnotherToken = false,
balance = "123",
coinId = "",
@ -326,7 +331,7 @@ private val receiveCard = SwapCardData(
amountEquivalent = "1 000 000",
tokenIconUrl = "",
tokenCurrency = "DAI",
networkIconRes = R.drawable.img_polygon_22,
isNotNativeToken = true,
canSelectAnotherToken = true,
balance = "33333",
coinId = "",
@ -342,6 +347,7 @@ private val state = SwapStateHolder(
swapButton = SwapButton(enabled = true, loading = false, onClick = {}),
onRefresh = {}, onBackClicked = {}, onChangeCardsClicked = {},
permissionState = SwapPermissionState.InProgress,
blockchainId = "POLYGON",
// alert = SwapWarning.GenericWarning("There was an error. Please try again.") {},
)

View file

@ -7,6 +7,10 @@ import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.ui.utils.getValidatedNumberWithFixedDecimals
import com.tangem.feature.swap.analytics.SwapEvents
import com.tangem.feature.swap.domain.BlockchainInteractor
import com.tangem.feature.swap.domain.SwapInteractor
import com.tangem.feature.swap.domain.models.domain.Currency
import com.tangem.feature.swap.domain.models.domain.SwapDataModel
@ -24,7 +28,6 @@ import com.tangem.feature.swap.ui.StateBuilder
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.Debouncer
import com.tangem.utils.coroutines.runCatching
import com.tangem.utils.toFormattedString
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import kotlinx.serialization.decodeFromString
@ -35,7 +38,9 @@ import kotlin.properties.Delegates
@HiltViewModel
internal class SwapViewModel @Inject constructor(
private val swapInteractor: SwapInteractor,
private val blockchainInteractor: BlockchainInteractor,
private val dispatchers: CoroutineDispatcherProvider,
private val analyticsEventHandler: AnalyticsEventHandler,
savedStateHandle: SavedStateHandle,
) : ViewModel() {
@ -51,7 +56,12 @@ internal class SwapViewModel @Inject constructor(
private val singleTaskScheduler = SingleTaskScheduler<SwapState>()
private var dataState by mutableStateOf(SwapProcessDataState(networkId = currency.networkId))
var uiState: SwapStateHolder by mutableStateOf(stateBuilder.createInitialLoadingState(currency))
var uiState: SwapStateHolder by mutableStateOf(
stateBuilder.createInitialLoadingState(
initialCurrency = currency,
blockchainId = blockchainInteractor.getBlockchainId(currency.networkId),
),
)
private set
// shows currency order (direct - swap initial to selected, reversed = selected to initial)
@ -70,12 +80,21 @@ internal class SwapViewModel @Inject constructor(
super.onCleared()
}
fun onScreenOpened() {
analyticsEventHandler.send(SwapEvents.SwapScreenOpened(currency.symbol))
}
fun setRouter(router: SwapRouter) {
swapRouter = router
uiState = uiState.copy(
onBackClicked = router::back,
onSelectTokenClick = { router.openScreen(SwapScreen.SelectToken) },
onSuccess = { router.openScreen(SwapScreen.Success) },
onSelectTokenClick = {
router.openScreen(SwapScreen.SelectToken)
analyticsEventHandler.send(SwapEvents.ChooseTokenScreenOpened)
},
onSuccess = {
router.openScreen(SwapScreen.Success)
},
)
}
@ -190,16 +209,17 @@ internal class SwapViewModel @Inject constructor(
runCatching(dispatchers.io) {
swapInteractor.onSwap(
networkId = dataState.networkId,
swapData = dataState.swapModel!!,
currencyToSend = dataState.fromCurrency!!,
currencyToGet = dataState.toCurrency!!,
amountToSwap = dataState.amount!!,
swapData = requireNotNull(dataState.swapModel),
currencyToSend = requireNotNull(dataState.fromCurrency),
currencyToGet = requireNotNull(dataState.toCurrency),
amountToSwap = requireNotNull(dataState.amount),
)
}
.onSuccess {
when (it) {
is TxState.TxSent -> {
uiState = stateBuilder.createSuccessState(uiState, it)
analyticsEventHandler.send(SwapEvents.SwapInProgressScreen)
swapRouter.openScreen(SwapScreen.Success)
}
else -> {
@ -209,7 +229,7 @@ internal class SwapViewModel @Inject constructor(
}
}
}
.onFailure { }
.onFailure { makeDefaultAlert() }
}
}
@ -230,16 +250,12 @@ internal class SwapViewModel @Inject constructor(
uiState = stateBuilder.loadingPermissionState(uiState)
}
else -> {
uiState = stateBuilder.addAlert(uiState) {
uiState = stateBuilder.clearAlert(uiState)
}
makeDefaultAlert()
}
}
}
.onFailure {
uiState = stateBuilder.addAlert(uiState) {
uiState = stateBuilder.clearAlert(uiState)
}
makeDefaultAlert()
}
}
}
@ -286,7 +302,8 @@ internal class SwapViewModel @Inject constructor(
toCurrency = newToToken,
)
isOrderReversed = !isOrderReversed
lastAmount.value = cutAmountWithDecimals(swapInteractor.getTokenDecimals(newFromToken), lastAmount.value)
lastAmount.value =
cutAmountWithDecimals(blockchainInteractor.getTokenDecimals(newFromToken), lastAmount.value)
uiState = stateBuilder.updateSwapAmount(uiState, lastAmount.value)
startLoadingQuotes(newFromToken, newToToken, lastAmount.value)
}
@ -296,7 +313,7 @@ internal class SwapViewModel @Inject constructor(
val fromToken = dataState.fromCurrency
val toToken = dataState.toCurrency
if (fromToken != null && toToken != null) {
val cutValue = cutAmountWithDecimals(swapInteractor.getTokenDecimals(fromToken), value)
val cutValue = cutAmountWithDecimals(blockchainInteractor.getTokenDecimals(fromToken), value)
uiState = stateBuilder.updateSwapAmount(uiState, cutValue)
lastAmount.value = cutValue
amountDebouncer.debounce(DEBOUNCE_AMOUNT_DELAY, viewModelScope) {
@ -313,19 +330,52 @@ internal class SwapViewModel @Inject constructor(
}
private fun cutAmountWithDecimals(maxDecimals: Int, amount: String): String {
return amount.toBigDecimalOrNull()?.toFormattedString(maxDecimals) ?: INITIAL_AMOUNT
return getValidatedNumberWithFixedDecimals(amount, maxDecimals)
}
private fun makeDefaultAlert() {
uiState = stateBuilder.addAlert(uiState) {
uiState = stateBuilder.clearAlert(uiState)
}
}
private fun createUiActions(): UiActions {
return UiActions(
onSearchEntered = { onSearchEntered(it) },
onTokenSelected = { onTokenSelect(it) },
onTokenSelected = {
onTokenSelect(it)
analyticsEventHandler.send(SwapEvents.SearchTokenClicked)
},
onAmountChanged = { onAmountChanged(it) },
onSwapClick = { onSwapClick() },
onGivePermissionClick = { givePermissionsToSwap() },
onChangeCardsClicked = { onChangeCardsClicked() },
onSwapClick = {
onSwapClick()
val sendTokenSymbol = dataState.fromCurrency?.symbol
val receiveTokenSymbol = dataState.toCurrency?.symbol
if (sendTokenSymbol != null && receiveTokenSymbol != null) {
analyticsEventHandler.send(
SwapEvents.ButtonSwapClicked(
sendToken = sendTokenSymbol,
receiveToken = receiveTokenSymbol,
),
)
}
},
onGivePermissionClick = {
givePermissionsToSwap()
analyticsEventHandler.send(SwapEvents.ButtonPermissionApproveClicked)
},
onChangeCardsClicked = {
onChangeCardsClicked()
analyticsEventHandler.send(SwapEvents.ButtonSwipeClicked)
},
onBackClicked = { onSearchEntered("") },
onMaxAmountSelected = { onMaxAmountClicked() },
openPermissionBottomSheet = {
analyticsEventHandler.send(SwapEvents.ButtonGivePermissionClicked)
},
hidePermissionBottomSheet = {
analyticsEventHandler.send(SwapEvents.ButtonPermissionCancelClicked)
},
)
}

View file

@ -44,4 +44,12 @@ interface TransactionManager {
suspend fun updateWalletManager(networkId: String)
fun calculateFee(networkId: String, gasPrice: String, estimatedGas: Int): BigDecimal
/**
* In app blockchain id, actual in blockchain sdk, not the same as networkId
*
* workaround till not use backend only and not integrated server vs sdk
*/
@Throws(IllegalStateException::class)
fun getBlockchainId(networkId: String): String
}