Updated on 2026-08-14

This commit is contained in:
Tangem 2025-06-03 19:35:11 +04:00
parent 808210b23b
commit ab31d57fa5
29 changed files with 689 additions and 410 deletions

View file

@ -4,10 +4,17 @@ import com.tangem.core.ui.R
import com.tangem.core.ui.components.bottomsheets.message.*
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
internal object WcAlertsFactory {
fun createUnknownDomainAlert(onClick: () -> Unit): MessageBottomSheetUMV2 {
internal fun createCommonTransactionAppInfoAlertUM(alertType: WcTransactionRoutes.Alert.Type) = when (alertType) {
is WcTransactionRoutes.Alert.Type.Verified -> createVerifiedDomainAlert(alertType.appName)
is WcTransactionRoutes.Alert.Type.UnknownDomain -> createUnknownDomainAlert()
is WcTransactionRoutes.Alert.Type.UnsafeDomain -> createUnsafeDomainAlert()
}
fun createUnknownDomainAlert(activeButtonOnClick: (() -> Unit)? = null): MessageBottomSheetUMV2 {
return messageBottomSheetUM {
infoBlock {
icon(R.drawable.img_knight_shield_32) {
@ -24,14 +31,16 @@ internal object WcAlertsFactory {
text = resourceReference(R.string.common_cancel)
onClick { closeBs() }
}
secondaryButton {
text = resourceReference(R.string.wc_alert_connect_anyway)
onClick { onClick() }
if (activeButtonOnClick != null) {
secondaryButton {
text = resourceReference(R.string.wc_alert_connect_anyway)
onClick { activeButtonOnClick() }
}
}
}
}
fun createUnsafeDomainAlert(onClick: () -> Unit): MessageBottomSheetUMV2 {
fun createUnsafeDomainAlert(activeButtonOnClick: (() -> Unit)? = null): MessageBottomSheetUMV2 {
return messageBottomSheetUM {
infoBlock {
icon(R.drawable.img_knight_shield_32) {
@ -48,9 +57,11 @@ internal object WcAlertsFactory {
text = resourceReference(R.string.common_cancel)
onClick { closeBs() }
}
secondaryButton {
text = resourceReference(R.string.wc_alert_connect_anyway)
onClick { onClick() }
if (activeButtonOnClick != null) {
secondaryButton {
text = resourceReference(R.string.wc_alert_connect_anyway)
onClick { activeButtonOnClick() }
}
}
}
}

View file

@ -11,12 +11,10 @@ import com.tangem.features.walletconnect.transaction.ui.chain.WcAddEthereumChain
internal class WcAddNetworkComponent(
private val appComponentContext: AppComponentContext,
private val model: WcAddNetworkModel,
private val transactionInfoOnClick: () -> Unit,
private val onDismiss: () -> Unit,
) : AppComponentContext by appComponentContext, ComposableBottomSheetComponent {
override fun dismiss() {
onDismiss()
model.dismiss()
}
@Composable
@ -26,7 +24,7 @@ internal class WcAddNetworkComponent(
if (content != null) {
WcAddEthereumChainModalBottomSheetContent(
state = content!!.transaction,
onClickTransactionRequest = transactionInfoOnClick,
onClickTransactionRequest = model::showTransactionRequest,
onBack = router::pop,
onDismiss = ::dismiss,
)

View file

@ -1,66 +1,25 @@
package com.tangem.features.walletconnect.transaction.components.chain
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack
import com.arkivanov.decompose.router.stack.pop
import com.arkivanov.decompose.router.stack.pushNew
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.walletconnect.transaction.components.common.WcCommonTransactionComponentDelegate
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionRequestInfoComponent
import com.tangem.features.walletconnect.transaction.components.common.getWcCommonScreen
import com.tangem.features.walletconnect.transaction.model.WcAddNetworkModel
import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
internal class WcAddNetworkContainerComponent(
private val appComponentContext: AppComponentContext,
appComponentContext: AppComponentContext,
params: WcTransactionModelParams,
) : AppComponentContext by appComponentContext, ComposableContentComponent {
) : WcCommonTransactionComponentDelegate(appComponentContext) {
private val contentNavigation = StackNavigation<WcTransactionRoutes>()
private val innerRouter = InnerRouter<WcTransactionRoutes>(
stackNavigation = contentNavigation,
popCallback = { onChildBack() },
)
private val model: WcAddNetworkModel = getOrCreateModel(params = params)
private val contentStack = childStack(
key = "WcAddNetworkStack",
source = contentNavigation,
serializer = WcTransactionRoutes.serializer(),
initialConfiguration = WcTransactionRoutes.Transaction,
handleBackButton = true,
childFactory = ::screenChild,
)
@Composable
override fun Content(modifier: Modifier) {
val content by contentStack.subscribeAsState()
BackHandler(onBack = ::onChildBack)
content.active.instance.BottomSheet()
}
private fun dismiss() {
model.dismiss()
}
private fun onChildBack() {
when (contentStack.value.active.configuration) {
WcTransactionRoutes.Transaction -> contentNavigation.pop()
WcTransactionRoutes.TransactionRequestInfo -> contentNavigation.pushNew(WcTransactionRoutes.Transaction)
}
}
private fun toTransactionRequestInfo() {
contentNavigation.pushNew(WcTransactionRoutes.TransactionRequestInfo)
init {
super.init(navigation = model.stackNavigation, screenChild = ::screenChild, screenKey = "WcAddNetworkStack")
}
private fun screenChild(
@ -68,18 +27,15 @@ internal class WcAddNetworkContainerComponent(
componentContext: ComponentContext,
): ComposableBottomSheetComponent {
val appComponentContext = childByContext(componentContext = componentContext, router = innerRouter)
return when (config) {
is WcTransactionRoutes.Transaction -> WcAddNetworkComponent(
appComponentContext = childByContext(componentContext),
transactionInfoOnClick = ::toTransactionRequestInfo,
onDismiss = ::dismiss,
model = model,
)
is WcTransactionRoutes.TransactionRequestInfo -> WcTransactionRequestInfoComponent(
appComponentContext = appComponentContext,
onDismiss = ::dismiss,
model = model.uiState.value?.transactionRequestInfo,
)
}
return getWcCommonScreen(
config = config,
appComponentContext = appComponentContext,
transactionScreenConverter = { createTransactionComponent(appComponentContext) },
model = model,
)
}
private fun createTransactionComponent(appComponentContext: AppComponentContext): WcAddNetworkComponent {
return WcAddNetworkComponent(appComponentContext = appComponentContext, model = model)
}
}

View file

@ -0,0 +1,67 @@
package com.tangem.features.walletconnect.transaction.components.common
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.stack.ChildStack
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack
import com.arkivanov.decompose.router.stack.pop
import com.arkivanov.decompose.value.Value
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
internal abstract class WcCommonTransactionComponentDelegate(
private val appComponentContext: AppComponentContext,
) : AppComponentContext by appComponentContext, ComposableContentComponent {
private var stackNavigation: StackNavigation<WcTransactionRoutes>? = null
private var contentStack: Value<ChildStack<WcTransactionRoutes, ComposableBottomSheetComponent>>? = null
protected val innerRouter by lazy {
stackNavigation?.let {
InnerRouter<WcTransactionRoutes>(stackNavigation = it, popCallback = { onChildBack() })
}
}
protected fun init(
navigation: StackNavigation<WcTransactionRoutes>,
screenChild: (WcTransactionRoutes, ComponentContext) -> ComposableBottomSheetComponent,
screenKey: String,
) {
stackNavigation = navigation
contentStack = childStack(
key = screenKey,
source = navigation,
serializer = WcTransactionRoutes.serializer(),
initialConfiguration = WcTransactionRoutes.Transaction,
handleBackButton = true,
childFactory = screenChild,
)
}
@Composable
override fun Content(modifier: Modifier) {
if (contentStack != null) {
val content by contentStack!!.subscribeAsState()
BackHandler(onBack = ::onChildBack)
content.active.instance.BottomSheet()
}
}
private fun onChildBack() {
when (contentStack?.value?.active?.configuration) {
is WcTransactionRoutes.Transaction,
is WcTransactionRoutes.TransactionRequestInfo,
is WcTransactionRoutes.Alert,
-> stackNavigation?.pop()
else -> Unit
}
}
}

View file

@ -0,0 +1,27 @@
package com.tangem.features.walletconnect.transaction.components.common
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.features.walletconnect.connections.components.AlertsComponentV2
import com.tangem.features.walletconnect.connections.utils.WcAlertsFactory.createCommonTransactionAppInfoAlertUM
import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionModel
import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
internal fun getWcCommonScreen(
config: WcTransactionRoutes,
appComponentContext: AppComponentContext,
transactionScreenConverter: () -> ComposableBottomSheetComponent,
model: WcCommonTransactionModel,
): ComposableBottomSheetComponent {
return when (config) {
is WcTransactionRoutes.Transaction -> transactionScreenConverter()
is WcTransactionRoutes.Alert -> AlertsComponentV2(
appComponentContext = appComponentContext,
messageUM = createCommonTransactionAppInfoAlertUM(config.type),
)
is WcTransactionRoutes.TransactionRequestInfo -> WcTransactionRequestInfoComponent(
appComponentContext = appComponentContext,
model = model,
)
}
}

View file

@ -1,25 +1,31 @@
package com.tangem.features.walletconnect.transaction.components.common
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionModel
import com.tangem.features.walletconnect.transaction.ui.common.TransactionRequestInfoContent
internal class WcTransactionRequestInfoComponent(
private val appComponentContext: AppComponentContext,
private val model: WcTransactionRequestInfoUM?,
private val onDismiss: () -> Unit,
private val model: WcCommonTransactionModel,
) : AppComponentContext by appComponentContext, ComposableBottomSheetComponent {
override fun dismiss() {
onDismiss()
model.dismiss()
}
@Composable
override fun BottomSheet() {
if (model != null) {
TransactionRequestInfoContent(model, onBack = router::pop, onDismiss = ::dismiss)
val content by model.uiState.collectAsStateWithLifecycle()
if (content?.transactionRequestInfo != null) {
TransactionRequestInfoContent(
state = content!!.transactionRequestInfo,
onBack = router::pop,
onDismiss = ::dismiss,
)
}
}
}

View file

@ -11,12 +11,10 @@ import com.tangem.features.walletconnect.transaction.ui.send.WcSendTransactionMo
internal class WcSendTransactionComponent(
private val appComponentContext: AppComponentContext,
private val model: WcSendTransactionModel,
private val transactionInfoOnClick: () -> Unit,
private val onDismiss: () -> Unit,
) : AppComponentContext by appComponentContext, ComposableBottomSheetComponent {
override fun dismiss() {
onDismiss()
model.dismiss()
}
@Composable
@ -26,7 +24,7 @@ internal class WcSendTransactionComponent(
if (content != null) {
WcSendTransactionModalBottomSheet(
state = content!!.transaction,
onClickTransactionRequest = transactionInfoOnClick,
onClickTransactionRequest = model::showTransactionRequest,
onBack = router::pop,
onDismiss = ::dismiss,
)

View file

@ -1,66 +1,29 @@
package com.tangem.features.walletconnect.transaction.components.send
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack
import com.arkivanov.decompose.router.stack.pop
import com.arkivanov.decompose.router.stack.pushNew
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.walletconnect.transaction.components.common.WcCommonTransactionComponentDelegate
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionRequestInfoComponent
import com.tangem.features.walletconnect.transaction.components.common.getWcCommonScreen
import com.tangem.features.walletconnect.transaction.model.WcSendTransactionModel
import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
internal class WcSendTransactionContainerComponent(
private val appComponentContext: AppComponentContext,
appComponentContext: AppComponentContext,
params: WcTransactionModelParams,
) : AppComponentContext by appComponentContext, ComposableContentComponent {
) : WcCommonTransactionComponentDelegate(appComponentContext) {
private val contentNavigation = StackNavigation<WcTransactionRoutes>()
private val innerRouter = InnerRouter<WcTransactionRoutes>(
stackNavigation = contentNavigation,
popCallback = { onChildBack() },
)
private val model: WcSendTransactionModel = getOrCreateModel(params = params)
private val contentStack = childStack(
key = "WcSendTransactionStack",
source = contentNavigation,
serializer = WcTransactionRoutes.serializer(),
initialConfiguration = WcTransactionRoutes.Transaction,
handleBackButton = true,
childFactory = ::screenChild,
)
@Composable
override fun Content(modifier: Modifier) {
val content by contentStack.subscribeAsState()
BackHandler(onBack = ::onChildBack)
content.active.instance.BottomSheet()
}
private fun dismiss() {
router.pop()
}
private fun onChildBack() {
when (contentStack.value.active.configuration) {
WcTransactionRoutes.Transaction -> contentNavigation.pop()
WcTransactionRoutes.TransactionRequestInfo -> contentNavigation.pushNew(WcTransactionRoutes.Transaction)
}
}
private fun toTransactionRequestInfo() {
contentNavigation.pushNew(WcTransactionRoutes.TransactionRequestInfo)
init {
super.init(
navigation = model.stackNavigation,
screenChild = ::screenChild,
screenKey = "WcSendTransactionStack",
)
}
private fun screenChild(
@ -68,18 +31,15 @@ internal class WcSendTransactionContainerComponent(
componentContext: ComponentContext,
): ComposableBottomSheetComponent {
val appComponentContext = childByContext(componentContext = componentContext, router = innerRouter)
return when (config) {
is WcTransactionRoutes.Transaction -> WcSendTransactionComponent(
appComponentContext = childByContext(componentContext),
transactionInfoOnClick = ::toTransactionRequestInfo,
onDismiss = ::dismiss,
model = model,
)
is WcTransactionRoutes.TransactionRequestInfo -> WcTransactionRequestInfoComponent(
appComponentContext = appComponentContext,
onDismiss = ::dismiss,
model = model.uiState.value?.transactionRequestInfo,
)
}
return getWcCommonScreen(
config = config,
appComponentContext = appComponentContext,
transactionScreenConverter = { createTransactionComponent(appComponentContext) },
model = model,
)
}
private fun createTransactionComponent(appComponentContext: AppComponentContext): WcSendTransactionComponent {
return WcSendTransactionComponent(appComponentContext = appComponentContext, model = model)
}
}

View file

@ -11,12 +11,10 @@ import com.tangem.features.walletconnect.transaction.ui.sign.WcSignTransactionMo
internal class WcSignTransactionComponent(
private val appComponentContext: AppComponentContext,
private val model: WcSignTransactionModel,
private val transactionInfoOnClick: () -> Unit,
private val onDismiss: () -> Unit,
) : AppComponentContext by appComponentContext, ComposableBottomSheetComponent {
override fun dismiss() {
onDismiss()
model.dismiss()
}
@Composable
@ -26,7 +24,7 @@ internal class WcSignTransactionComponent(
if (content != null) {
WcSignTransactionModalBottomSheetContent(
state = content!!.transaction,
onClickTransactionRequest = transactionInfoOnClick,
onClickTransactionRequest = model::showTransactionRequest,
onBack = router::pop,
onDismiss = ::dismiss,
)

View file

@ -1,56 +1,29 @@
package com.tangem.features.walletconnect.transaction.components.sign
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.subscribeAsState
import com.arkivanov.decompose.router.stack.*
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.walletconnect.transaction.components.common.WcCommonTransactionComponentDelegate
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionRequestInfoComponent
import com.tangem.features.walletconnect.transaction.components.common.getWcCommonScreen
import com.tangem.features.walletconnect.transaction.model.WcSignTransactionModel
import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
internal class WcSignTransactionContainerComponent(
private val appComponentContext: AppComponentContext,
appComponentContext: AppComponentContext,
params: WcTransactionModelParams,
) : AppComponentContext by appComponentContext, ComposableContentComponent {
) : WcCommonTransactionComponentDelegate(appComponentContext) {
private val contentNavigation = StackNavigation<WcTransactionRoutes>()
private val innerRouter = InnerRouter<WcTransactionRoutes>(
stackNavigation = contentNavigation,
popCallback = { onChildBack() },
)
private val model: WcSignTransactionModel = getOrCreateModel(params = params)
private val contentStack = childStack(
key = "WcSignTransactionStack",
source = contentNavigation,
serializer = WcTransactionRoutes.serializer(),
initialConfiguration = WcTransactionRoutes.Transaction,
handleBackButton = true,
childFactory = ::screenChild,
)
@Composable
override fun Content(modifier: Modifier) {
val content by contentStack.subscribeAsState()
BackHandler(onBack = ::onChildBack)
content.active.instance.BottomSheet()
}
private fun onChildBack() {
when (contentStack.value.active.configuration) {
WcTransactionRoutes.Transaction,
WcTransactionRoutes.TransactionRequestInfo,
-> contentNavigation.pop()
}
init {
super.init(
navigation = model.stackNavigation,
screenChild = ::screenChild,
screenKey = "WcSignTransactionStack",
)
}
private fun screenChild(
@ -58,18 +31,15 @@ internal class WcSignTransactionContainerComponent(
componentContext: ComponentContext,
): ComposableBottomSheetComponent {
val appComponentContext = childByContext(componentContext = componentContext, router = innerRouter)
return when (config) {
is WcTransactionRoutes.Transaction -> WcSignTransactionComponent(
appComponentContext = appComponentContext,
onDismiss = model::dismiss,
model = model,
transactionInfoOnClick = { contentNavigation.pushNew(WcTransactionRoutes.TransactionRequestInfo) },
)
is WcTransactionRoutes.TransactionRequestInfo -> WcTransactionRequestInfoComponent(
appComponentContext = appComponentContext,
onDismiss = model::dismiss,
model = model.uiState.value?.transactionRequestInfo,
)
}
return getWcCommonScreen(
config = config,
appComponentContext = appComponentContext,
transactionScreenConverter = { createTransactionComponent(appComponentContext) },
model = model,
)
}
private fun createTransactionComponent(appComponentContext: AppComponentContext): WcSignTransactionComponent {
return WcSignTransactionComponent(appComponentContext = appComponentContext, model = model)
}
}

View file

@ -0,0 +1,30 @@
package com.tangem.features.walletconnect.transaction.converter
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.walletconnect.usecase.method.WcMethodContext
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestBlockUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoItemUM
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import javax.inject.Inject
internal class BasicTransactionRequestInfoBlocksConverter @Inject constructor() :
Converter<WcMethodContext, ImmutableList<WcTransactionRequestBlockUM>> {
override fun convert(value: WcMethodContext) = persistentListOf(
WcTransactionRequestBlockUM(
persistentListOf(
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_signature_type),
description = value.rawSdkRequest.request.method,
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_contents),
description = value.rawSdkRequest.request.params,
),
),
),
)
}

View file

@ -0,0 +1,41 @@
package com.tangem.features.walletconnect.transaction.converter
import com.tangem.domain.walletconnect.usecase.method.WcAddNetworkUseCase
import com.tangem.features.walletconnect.transaction.entity.chain.WcAddEthereumChainItemUM
import com.tangem.features.walletconnect.transaction.entity.chain.WcAddEthereumChainUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
import com.tangem.utils.converter.Converter
import javax.inject.Inject
internal class WcAddEthereumChainUMConverter @Inject constructor(
private val basicBlocksConverter: BasicTransactionRequestInfoBlocksConverter,
private val appInfoContentUMConverter: WcTransactionAppInfoContentUMConverter,
) : Converter<WcAddEthereumChainUMConverter.Input, WcAddEthereumChainUM> {
override fun convert(value: Input): WcAddEthereumChainUM {
return WcAddEthereumChainUM(
transaction = WcAddEthereumChainItemUM(
onDismiss = value.actions.onDismiss,
onSign = value.actions.onSign,
appInfo = appInfoContentUMConverter.convert(
WcTransactionAppInfoContentUMConverter.Input(
session = value.useCase.session,
onShowVerifiedAlert = value.actions.onShowVerifiedAlert,
),
),
walletName = value.useCase.session.wallet.name,
isLoading = false,
),
transactionRequestInfo = WcTransactionRequestInfoUM(
blocks = basicBlocksConverter.convert(value.useCase),
onCopy = value.actions.onCopy,
),
)
}
data class Input(
val useCase: WcAddNetworkUseCase,
val actions: WcTransactionActionsUM,
)
}

View file

@ -0,0 +1,50 @@
package com.tangem.features.walletconnect.transaction.converter
import com.tangem.domain.walletconnect.model.WcEthMethod
import com.tangem.domain.walletconnect.model.WcSolanaMethod
import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase
import com.tangem.domain.walletconnect.usecase.method.WcSignState
import com.tangem.domain.walletconnect.usecase.method.WcSignUseCase
import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.utils.converter.Converter
import javax.inject.Inject
internal class WcCommonTransactionUMConverter @Inject constructor(
private val signTypedDataUMConverter: WcSignTypedDataUMConverter,
private val signTransactionUMConverter: WcSignTransactionUMConverter,
) : Converter<WcCommonTransactionUMConverter.Input, WcCommonTransactionUM?> {
override fun convert(value: Input): WcCommonTransactionUM? {
return when (value.useCase) {
is WcMessageSignUseCase -> {
when (value.useCase.method) {
is WcEthMethod.SignTypedData -> signTypedDataUMConverter.convert(
WcSignTypedDataUMConverter.Input(
useCase = value.useCase,
signState = value.signState,
signModel = value.signState.signModel as WcMessageSignUseCase.SignModel,
actions = value.actions,
),
)
is WcEthMethod.MessageSign, is WcSolanaMethod.SignMessage -> signTransactionUMConverter.convert(
WcSignTransactionUMConverter.Input(
useCase = value.useCase,
signState = value.signState,
signModel = value.signState.signModel as WcMessageSignUseCase.SignModel,
actions = value.actions,
),
)
else -> null
}
}
else -> TODO("[REDACTED_JIRA]")
}
}
data class Input(
val useCase: WcSignUseCase<*>,
val signState: WcSignState<*>,
val actions: WcTransactionActionsUM,
)
}

View file

@ -0,0 +1,15 @@
package com.tangem.features.walletconnect.transaction.converter
import com.tangem.core.ui.extensions.getActiveIconRes
import com.tangem.domain.models.network.Network
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
import com.tangem.utils.converter.Converter
import javax.inject.Inject
internal class WcNetworkInfoUMConverter @Inject constructor() : Converter<Network, WcNetworkInfoUM> {
override fun convert(value: Network) = WcNetworkInfoUM(
name = value.name,
iconRes = getActiveIconRes(value.rawId),
)
}

View file

@ -0,0 +1,50 @@
package com.tangem.features.walletconnect.transaction.converter
import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase
import com.tangem.domain.walletconnect.usecase.method.WcSignState
import com.tangem.domain.walletconnect.usecase.method.WcSignStep
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionItemUM
import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionUM
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.persistentListOf
import javax.inject.Inject
internal class WcSignTransactionUMConverter @Inject constructor(
private val appInfoContentUMConverter: WcTransactionAppInfoContentUMConverter,
private val networkInfoUMConverter: WcNetworkInfoUMConverter,
private val requestBlockUMConverter: WcTransactionRequestBlockUMConverter,
) : Converter<WcSignTransactionUMConverter.Input, WcSignTransactionUM> {
override fun convert(value: Input) = WcSignTransactionUM(
transaction = WcSignTransactionItemUM(
onDismiss = value.actions.onDismiss,
onSign = value.actions.onSign,
appInfo = appInfoContentUMConverter.convert(
WcTransactionAppInfoContentUMConverter.Input(
session = value.useCase.session,
onShowVerifiedAlert = value.actions.onShowVerifiedAlert,
),
),
walletName = value.useCase.session.wallet.name,
networkInfo = networkInfoUMConverter.convert(value.useCase.network),
isLoading = value.signState.domainStep == WcSignStep.Signing,
),
transactionRequestInfo = WcTransactionRequestInfoUM(
persistentListOf(
requestBlockUMConverter.convert(
WcTransactionRequestBlockUMConverter.Input(value.useCase.rawSdkRequest, value.signModel),
),
),
onCopy = value.actions.onCopy,
),
)
data class Input(
val useCase: WcMessageSignUseCase,
val signState: WcSignState<*>,
val signModel: WcMessageSignUseCase.SignModel,
val actions: WcTransactionActionsUM,
)
}

View file

@ -0,0 +1,84 @@
package com.tangem.features.walletconnect.transaction.converter
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.walletconnect.model.WcEthMethod
import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase
import com.tangem.domain.walletconnect.usecase.method.WcSignState
import com.tangem.domain.walletconnect.usecase.method.WcSignStep
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestBlockUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoItemUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionItemUM
import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionUM
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import javax.inject.Inject
private const val ADDRESS_FIRST_PART_LENGTH = 7
private const val ADDRESS_SECOND_PART_LENGTH = 4
internal class WcSignTypedDataUMConverter @Inject constructor(
private val appInfoContentUMConverter: WcTransactionAppInfoContentUMConverter,
private val networkInfoUMConverter: WcNetworkInfoUMConverter,
private val requestBlockUMConverter: WcTransactionRequestBlockUMConverter,
) : Converter<WcSignTypedDataUMConverter.Input, WcSignTransactionUM> {
override fun convert(value: Input): WcSignTransactionUM = WcSignTransactionUM(
transaction = WcSignTransactionItemUM(
onDismiss = value.actions.onDismiss,
onSign = value.actions.onSign,
appInfo = appInfoContentUMConverter.convert(
WcTransactionAppInfoContentUMConverter.Input(
session = value.useCase.session,
onShowVerifiedAlert = value.actions.onShowVerifiedAlert,
),
),
walletName = value.useCase.session.wallet.name,
networkInfo = networkInfoUMConverter.convert(value.useCase.network),
addressText = value.useCase.walletAddress.toShortAddressText(),
isLoading = value.signState.domainStep == WcSignStep.Signing,
),
transactionRequestInfo = WcTransactionRequestInfoUM(
blocks = buildList {
add(
requestBlockUMConverter.convert(
WcTransactionRequestBlockUMConverter.Input(value.useCase.rawSdkRequest, value.signModel),
),
)
(value.useCase.method as? WcEthMethod.SignTypedData)?.params?.message?.to?.let { to ->
add(
WcTransactionRequestBlockUM(
persistentListOf(
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_transaction_info_to_title),
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.settings_wallet_name_title),
description = to.name,
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_common_wallet),
description = to.wallet,
),
),
),
)
}
}.toImmutableList(),
onCopy = value.actions.onCopy,
),
)
private fun String.toShortAddressText() =
"${take(ADDRESS_FIRST_PART_LENGTH)}...${takeLast(ADDRESS_SECOND_PART_LENGTH)}"
data class Input(
val useCase: WcMessageSignUseCase,
val signState: WcSignState<*>,
val signModel: WcMessageSignUseCase.SignModel,
val actions: WcTransactionActionsUM,
)
}

View file

@ -0,0 +1,25 @@
package com.tangem.features.walletconnect.transaction.converter
import com.tangem.domain.walletconnect.model.WcSession
import com.tangem.features.walletconnect.connections.model.transformers.WcDAppVerifiedStateConverter
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM
import com.tangem.utils.converter.Converter
import javax.inject.Inject
internal class WcTransactionAppInfoContentUMConverter @Inject constructor() :
Converter<WcTransactionAppInfoContentUMConverter.Input, WcTransactionAppInfoContentUM> {
override fun convert(value: Input) = WcTransactionAppInfoContentUM(
appName = value.session.sdkModel.appMetaData.name,
appIcon = value.session.sdkModel.appMetaData.icons.firstOrNull().orEmpty(),
verifiedState = WcDAppVerifiedStateConverter(onVerifiedClick = value.onShowVerifiedAlert).convert(
value.session.securityStatus to value.session.sdkModel.appMetaData.name,
),
appSubtitle = value.session.sdkModel.appMetaData.description,
)
data class Input(
val session: WcSession,
val onShowVerifiedAlert: (String) -> Unit,
)
}

View file

@ -0,0 +1,33 @@
package com.tangem.features.walletconnect.transaction.converter
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest
import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestBlockUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoItemUM
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.persistentListOf
import javax.inject.Inject
internal class WcTransactionRequestBlockUMConverter @Inject constructor() :
Converter<WcTransactionRequestBlockUMConverter.Input, WcTransactionRequestBlockUM> {
override fun convert(value: Input) = WcTransactionRequestBlockUM(
persistentListOf(
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_signature_type),
description = value.rawSdkRequest.request.method,
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_contents),
description = value.signModel?.humanMsg ?: value.rawSdkRequest.request.params,
),
),
)
data class Input(
val rawSdkRequest: WcSdkSessionRequest,
val signModel: WcMessageSignUseCase.SignModel? = null,
)
}

View file

@ -1,13 +1,14 @@
package com.tangem.features.walletconnect.transaction.entity.chain
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
internal data class WcAddEthereumChainUM(
val transaction: WcAddEthereumChainItemUM,
val transactionRequestInfo: WcTransactionRequestInfoUM,
)
override val transactionRequestInfo: WcTransactionRequestInfoUM,
) : WcCommonTransactionUM
internal data class WcAddEthereumChainItemUM(
val onDismiss: () -> Unit,

View file

@ -0,0 +1,10 @@
package com.tangem.features.walletconnect.transaction.entity.common
import kotlinx.coroutines.flow.StateFlow
internal interface WcCommonTransactionModel {
val uiState: StateFlow<WcCommonTransactionUM?>
fun dismiss()
}

View file

@ -0,0 +1,6 @@
package com.tangem.features.walletconnect.transaction.entity.common
internal interface WcCommonTransactionUM {
val transactionRequestInfo: WcTransactionRequestInfoUM
}

View file

@ -2,14 +2,15 @@ package com.tangem.features.walletconnect.transaction.entity.send
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.features.walletconnect.transaction.entity.blockaid.WcEstimatedWalletChangesUM
import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionUM
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
internal data class WcSendTransactionUM(
val transaction: WcSendTransactionItemUM,
val transactionRequestInfo: WcTransactionRequestInfoUM,
)
override val transactionRequestInfo: WcTransactionRequestInfoUM,
) : WcCommonTransactionUM
internal data class WcSendTransactionItemUM(
val onDismiss: () -> Unit,

View file

@ -1,14 +1,15 @@
package com.tangem.features.walletconnect.transaction.entity.sign
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionUM
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
internal data class WcSignTransactionUM(
val transaction: WcSignTransactionItemUM,
val transactionRequestInfo: WcTransactionRequestInfoUM,
)
override val transactionRequestInfo: WcTransactionRequestInfoUM,
) : WcCommonTransactionUM
internal data class WcSignTransactionItemUM(
val onDismiss: () -> Unit,

View file

@ -1,6 +1,8 @@
package com.tangem.features.walletconnect.transaction.model
import androidx.compose.runtime.Stable
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.pushNew
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -11,8 +13,10 @@ import com.tangem.domain.walletconnect.usecase.method.WcAddNetworkUseCase
import com.tangem.domain.walletconnect.usecase.method.WcMethodUseCase
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams
import com.tangem.features.walletconnect.transaction.entity.chain.WcAddEthereumChainUM
import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionModel
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.utils.toUM
import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
import com.tangem.features.walletconnect.transaction.converter.WcAddEthereumChainUMConverter
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -28,36 +32,46 @@ internal class WcAddNetworkModel @Inject constructor(
private val router: Router,
private val clipboardManager: ClipboardManager,
private val useCaseFactory: WcRequestUseCaseFactory,
) : Model() {
private val wcAddEthereumChainUMConverter: WcAddEthereumChainUMConverter,
) : Model(), WcCommonTransactionModel {
private val _uiState = MutableStateFlow<WcAddEthereumChainUM?>(null)
val uiState: StateFlow<WcAddEthereumChainUM?> = _uiState
override val uiState: StateFlow<WcAddEthereumChainUM?> = _uiState
val stackNavigation = StackNavigation<WcTransactionRoutes>()
private val params = paramsContainer.require<WcTransactionModelParams>()
init {
modelScope.launch {
val useCase: WcMethodUseCase = useCaseFactory.createUseCase(params.rawRequest)
val transactionUM = (useCase as? WcAddNetworkUseCase)?.toUM(
actions = WcTransactionActionsUM(
onShowVerifiedAlert = ::showVerifiedAlert,
onDismiss = { cancel(useCase) },
onSign = { sign(useCase) },
onCopy = { copyData(useCase.rawSdkRequest.request.params) },
),
)
val transactionUM = (useCase as? WcAddNetworkUseCase)?.let {
wcAddEthereumChainUMConverter.convert(
WcAddEthereumChainUMConverter.Input(
useCase = useCase,
actions = WcTransactionActionsUM(
onShowVerifiedAlert = ::showVerifiedAlert,
onDismiss = { cancel(useCase) },
onSign = { sign(useCase) },
onCopy = { copyData(useCase.rawSdkRequest.request.params) },
),
),
)
}
_uiState.emit(transactionUM)
}
}
fun dismiss() {
override fun dismiss() {
_uiState.value?.transaction?.onDismiss?.invoke() ?: router.pop()
}
@Suppress("UnusedPrivateMember")
fun showTransactionRequest() {
stackNavigation.pushNew(WcTransactionRoutes.TransactionRequestInfo)
}
private fun showVerifiedAlert(appName: String) {
// TODO(wc): Nastya [REDACTED_JIRA] // see WcPairComponent and WcPairModel
// router.push(WcAppInfoRoutes.Alert(elements = message.elements))
stackNavigation.pushNew(WcTransactionRoutes.Alert(WcTransactionRoutes.Alert.Type.Verified(appName)))
}
private fun sign(useCase: WcAddNetworkUseCase) {

View file

@ -1,24 +1,102 @@
package com.tangem.features.walletconnect.transaction.model
import androidx.compose.runtime.Stable
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.pushNew
import com.domain.blockaid.models.transaction.TransactionData
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.domain.walletconnect.WcRequestUseCaseFactory
import com.tangem.domain.walletconnect.usecase.method.*
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams
import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionModel
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransactionUM
import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
import com.tangem.features.walletconnect.transaction.converter.WcCommonTransactionUMConverter
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject
@Stable
@ModelScoped
internal class WcSendTransactionModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
) : Model() {
private val router: Router,
private val clipboardManager: ClipboardManager,
private val useCaseFactory: WcRequestUseCaseFactory,
private val converter: WcCommonTransactionUMConverter,
) : Model(), WcCommonTransactionModel {
private val params = paramsContainer.require<WcTransactionModelParams>()
private val _uiState = MutableStateFlow<WcSendTransactionUM?>(null)
val uiState: StateFlow<WcSendTransactionUM?> = _uiState
override val uiState: StateFlow<WcSendTransactionUM?> = _uiState
val stackNavigation = StackNavigation<WcTransactionRoutes>()
init {
TODO("Finish model in this task [REDACTED_JIRA]")
modelScope.launch {
when (val useCase: WcSignUseCase<TransactionData> = useCaseFactory.createUseCase(params.rawRequest)) {
is WcTransactionUseCase,
is WcListTransactionUseCase,
-> {
useCase.invoke().onEach { signState ->
if (signingIsDone(signState)) return@onEach
val transactionUM = converter.convert(
WcCommonTransactionUMConverter.Input(
useCase = useCase,
signState = signState,
actions = WcTransactionActionsUM(
onShowVerifiedAlert = ::showVerifiedAlert,
onDismiss = { cancel(useCase) },
onSign = useCase::sign,
onCopy = { copyData(useCase.rawSdkRequest.request.params) },
),
),
) as? WcSendTransactionUM
_uiState.emit(transactionUM)
}
.launchIn(this)
}
}
}
}
override fun dismiss() {
_uiState.value?.transaction?.onDismiss?.invoke() ?: router.pop()
}
fun showTransactionRequest() {
stackNavigation.pushNew(WcTransactionRoutes.TransactionRequestInfo)
}
private fun showVerifiedAlert(appName: String) {
stackNavigation.pushNew(WcTransactionRoutes.Alert(WcTransactionRoutes.Alert.Type.Verified(appName)))
}
private fun signingIsDone(signState: WcSignState<*>): Boolean {
(signState.domainStep as? WcSignStep.Result)?.result?.let {
router.pop()
return true
}
return false
}
private fun cancel(useCase: WcSignUseCase<*>) {
useCase.cancel()
router.pop()
}
private fun copyData(text: String) {
clipboardManager.setText(text = text, isSensitive = true)
}
}

View file

@ -1,6 +1,8 @@
package com.tangem.features.walletconnect.transaction.model
import androidx.compose.runtime.Stable
import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.pushNew
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -11,9 +13,11 @@ import com.tangem.domain.walletconnect.usecase.method.WcSignState
import com.tangem.domain.walletconnect.usecase.method.WcSignStep
import com.tangem.domain.walletconnect.usecase.method.WcSignUseCase
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams
import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionModel
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionUM
import com.tangem.features.walletconnect.transaction.utils.toUM
import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
import com.tangem.features.walletconnect.transaction.converter.WcCommonTransactionUMConverter
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -30,42 +34,50 @@ internal class WcSignTransactionModel @Inject constructor(
private val router: Router,
private val clipboardManager: ClipboardManager,
private val useCaseFactory: WcRequestUseCaseFactory,
) : Model() {
private val _uiState = MutableStateFlow<WcSignTransactionUM?>(null)
val uiState: StateFlow<WcSignTransactionUM?> = _uiState
private val converter: WcCommonTransactionUMConverter,
) : Model(), WcCommonTransactionModel {
private val params = paramsContainer.require<WcTransactionModelParams>()
private val _uiState = MutableStateFlow<WcSignTransactionUM?>(null)
override val uiState: StateFlow<WcSignTransactionUM?> = _uiState
val stackNavigation = StackNavigation<WcTransactionRoutes>()
init {
modelScope.launch {
val useCase: WcSignUseCase<*> = useCaseFactory.createUseCase(params.rawRequest)
useCase.invoke()
.onEach { signState ->
if (signingIsDone(signState)) return@onEach
val signTransactionUM = useCase.toUM(
signState = signState,
actions = WcTransactionActionsUM(
onShowVerifiedAlert = ::showVerifiedAlert,
onDismiss = { cancel(useCase) },
onSign = useCase::sign,
onCopy = { copyData(useCase.rawSdkRequest.request.params) },
val signTransactionUM = converter.convert(
WcCommonTransactionUMConverter.Input(
useCase = useCase,
signState = signState,
actions = WcTransactionActionsUM(
onShowVerifiedAlert = ::showVerifiedAlert,
onDismiss = { cancel(useCase) },
onSign = useCase::sign,
onCopy = { copyData(useCase.rawSdkRequest.request.params) },
),
),
)
) as? WcSignTransactionUM
_uiState.emit(signTransactionUM)
}
.launchIn(this)
}
}
fun dismiss() {
override fun dismiss() {
_uiState.value?.transaction?.onDismiss?.invoke() ?: router.pop()
}
@Suppress("UnusedPrivateMember")
fun showTransactionRequest() {
stackNavigation.pushNew(WcTransactionRoutes.TransactionRequestInfo)
}
private fun showVerifiedAlert(appName: String) {
// TODO(wc): Nastya [REDACTED_JIRA] // see WcPairComponent and WcPairModel
// router.push(WcAppInfoRoutes.Alert(elements = message.elements))
stackNavigation.pushNew(WcTransactionRoutes.Alert(WcTransactionRoutes.Alert.Type.Verified(appName)))
}
private fun signingIsDone(signState: WcSignState<*>): Boolean {

View file

@ -13,4 +13,14 @@ internal sealed class WcTransactionRoutes : TangemBottomSheetConfigContent, Rout
@Serializable
data object TransactionRequestInfo : WcTransactionRoutes()
@Serializable
data class Alert(val type: Type) : WcTransactionRoutes() {
@Serializable
sealed class Type {
data class Verified(val appName: String) : Type()
data object UnknownDomain : Type()
data object UnsafeDomain : Type()
}
}
}

View file

@ -1,7 +0,0 @@
package com.tangem.features.walletconnect.transaction.utils
const val ADDRESS_FIRST_PART_LENGTH = 7
const val ADDRESS_SECOND_PART_LENGTH = 4
internal fun String.toShortAddressText() =
"${take(ADDRESS_FIRST_PART_LENGTH)}...${takeLast(ADDRESS_SECOND_PART_LENGTH)}"

View file

@ -1,166 +0,0 @@
package com.tangem.features.walletconnect.transaction.utils
import com.tangem.core.ui.extensions.getActiveIconRes
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.walletconnect.model.WcEthMethod
import com.tangem.domain.walletconnect.model.WcSolanaMethod
import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest
import com.tangem.domain.walletconnect.usecase.method.WcAddNetworkUseCase
import com.tangem.domain.walletconnect.usecase.method.WcMessageSignUseCase
import com.tangem.domain.walletconnect.usecase.method.WcMethodContext
import com.tangem.domain.walletconnect.usecase.method.WcSignState
import com.tangem.domain.walletconnect.usecase.method.WcSignStep
import com.tangem.domain.walletconnect.usecase.method.WcSignUseCase
import com.tangem.features.walletconnect.connections.model.transformers.WcDAppVerifiedStateConverter
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.chain.WcAddEthereumChainItemUM
import com.tangem.features.walletconnect.transaction.entity.chain.WcAddEthereumChainUM
import com.tangem.features.walletconnect.transaction.entity.common.*
import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionItemUM
import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionUM
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
internal fun WcAddNetworkUseCase.toUM(actions: WcTransactionActionsUM): WcAddEthereumChainUM {
return WcAddEthereumChainUM(
transaction = WcAddEthereumChainItemUM(
onDismiss = actions.onDismiss,
onSign = actions.onSign,
appInfo = appInfo(onShowVerifiedAlert = actions.onShowVerifiedAlert),
walletName = session.wallet.name,
isLoading = false,
),
transactionRequestInfo = WcTransactionRequestInfoUM(
blocks = basicTransactionRequestInfoBlocks(),
onCopy = actions.onCopy,
),
)
}
internal fun WcSignUseCase<*>.toUM(signState: WcSignState<*>, actions: WcTransactionActionsUM): WcSignTransactionUM? {
return when (this) {
is WcMessageSignUseCase -> {
when (method) {
is WcEthMethod.SignTypedData -> signTypedDataToUM(
signState = signState,
signModel = signState.signModel as WcMessageSignUseCase.SignModel,
actions = actions,
)
is WcEthMethod.MessageSign, is WcSolanaMethod.SignMessage -> messageSignToUM(
signState = signState,
signModel = signState.signModel as WcMessageSignUseCase.SignModel,
actions = actions,
)
else -> null
}
}
else -> null
}
}
private fun WcMessageSignUseCase.signTypedDataToUM(
signState: WcSignState<*>,
signModel: WcMessageSignUseCase.SignModel,
actions: WcTransactionActionsUM,
) = WcSignTransactionUM(
transaction = WcSignTransactionItemUM(
onDismiss = actions.onDismiss,
onSign = actions.onSign,
appInfo = appInfo(onShowVerifiedAlert = actions.onShowVerifiedAlert),
walletName = session.wallet.name,
networkInfo = networkInfo(),
addressText = walletAddress.toShortAddressText(),
isLoading = signState.domainStep == WcSignStep.Signing,
),
transactionRequestInfo = WcTransactionRequestInfoUM(
blocks = buildList {
add(createInfoBlockUM(rawSdkRequest, signModel))
(method as? WcEthMethod.SignTypedData)?.params?.message?.to?.let { to ->
add(
WcTransactionRequestBlockUM(
persistentListOf(
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_transaction_info_to_title),
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.settings_wallet_name_title),
description = to.name,
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_common_wallet),
description = to.wallet,
),
),
),
)
}
}.toImmutableList(),
onCopy = actions.onCopy,
),
)
private fun WcMessageSignUseCase.messageSignToUM(
signState: WcSignState<*>,
signModel: WcMessageSignUseCase.SignModel,
actions: WcTransactionActionsUM,
) = WcSignTransactionUM(
transaction = WcSignTransactionItemUM(
onDismiss = actions.onDismiss,
onSign = actions.onSign,
appInfo = appInfo(onShowVerifiedAlert = actions.onShowVerifiedAlert),
walletName = session.wallet.name,
networkInfo = networkInfo(),
isLoading = signState.domainStep == WcSignStep.Signing,
),
transactionRequestInfo = WcTransactionRequestInfoUM(
persistentListOf(createInfoBlockUM(rawSdkRequest, signModel)),
onCopy = actions.onCopy,
),
)
private fun createInfoBlockUM(
rawSdkRequest: WcSdkSessionRequest,
signModel: WcMessageSignUseCase.SignModel,
): WcTransactionRequestBlockUM {
return WcTransactionRequestBlockUM(
persistentListOf(
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_signature_type),
description = rawSdkRequest.request.method,
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_contents),
description = signModel.humanMsg,
),
),
)
}
private fun WcMethodContext.basicTransactionRequestInfoBlocks() = persistentListOf(
WcTransactionRequestBlockUM(
persistentListOf(
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_signature_type),
description = rawSdkRequest.request.method,
),
WcTransactionRequestInfoItemUM(
title = resourceReference(R.string.wc_contents),
description = rawSdkRequest.request.params,
),
),
),
)
private fun WcMethodContext.appInfo(onShowVerifiedAlert: (String) -> Unit) = WcTransactionAppInfoContentUM(
appName = session.sdkModel.appMetaData.name,
appIcon = session.sdkModel.appMetaData.url,
verifiedState = WcDAppVerifiedStateConverter(onVerifiedClick = onShowVerifiedAlert).convert(
session.securityStatus to session.sdkModel.appMetaData.name,
),
appSubtitle = session.sdkModel.appMetaData.description,
)
private fun WcMethodContext.networkInfo() = WcNetworkInfoUM(
name = network.name,
iconRes = getActiveIconRes(network.rawId),
)