From bf31324d3eedb33603a2d46c17a9ef4fb23d18ae Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 5 Oct 2023 16:35:37 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../com/tangem/tap/domain/TapWalletManager.kt | 8 ++- .../walletconnect/WalletConnectMiddleware.kt | 42 ++++++++++++ .../walletconnect/WalletConnectActions.kt | 12 ++++ .../walletmanager/WalletManagersFacade.kt | 1 + .../wallet/viewmodels/WalletViewModel.kt | 67 ++++++++++++++++++- 5 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 domain/legacy/src/main/java/com/tangem/domain/walletconnect/WalletConnectActions.kt diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index 67f1253c9e..729e96fe27 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -91,8 +91,12 @@ class TapWalletManager( store.dispatch(GlobalAction.SetIfCardVerifiedOnline(!attestationFailed)) store.dispatchWalletAction(action = WalletAction.Warnings.CheckIfNeeded) } - setupWalletConnectV2(userWallet) - loadData(userWallet = userWallet, refresh = refresh) + + val walletFeatureToggles = store.state.daggerGraphState.get(DaggerGraphState::walletFeatureToggles) + if (!walletFeatureToggles.isRedesignedScreenEnabled) { + setupWalletConnectV2(userWallet) + loadData(userWallet = userWallet, refresh = refresh) + } } private fun Store.dispatchWalletAction(action: WalletAction) { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index a9f177a893..4ed140a246 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -14,6 +14,8 @@ import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.util.derivationStyleProvider import com.tangem.domain.models.scan.ScanResponse +import com.tangem.domain.walletconnect.WalletConnectActions +import com.tangem.domain.wallets.models.UserWallet import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction @@ -60,6 +62,28 @@ class WalletConnectMiddleware { if (DemoHelper.tryHandle(state, action)) return when (action) { + is WalletConnectActions.New.Initialize -> { + val userWallet = action.userWallet + val cardId = if (userWallet.scanResponse.card.backupStatus?.isActive != true) { + userWallet.cardId + } else { // if wallet has backup, any card from wallet can be used to sign + null + } + scope.launch { + val wcInteractor = store.state.daggerGraphState.walletConnectInteractor ?: return@launch + wcInteractor.startListening( + userWalletId = userWallet.walletId.stringValue, + cardId = cardId, + ) + } + } + is WalletConnectActions.New.SetupUserChains -> { + scope.launch { + val userWallet = action.userWallet + val wcInteractor = store.state.daggerGraphState.walletConnectInteractor ?: return@launch + wcInteractor.setUserChains(getAccountsForWc(wcInteractor, userWallet)) + } + } is WalletConnectAction.ResetState -> walletConnectManager = WalletConnectManager() is WalletConnectAction.RestoreSessions -> { walletConnectManager.restoreSessions(action.scanResponse) @@ -485,4 +509,22 @@ class WalletConnectMiddleware { private fun isWalletConnectUri(uri: String): Boolean { return WalletConnectManager.isCorrectWcUri(uri) || walletConnectInteractor.isWalletConnectUri(uri) } + + private suspend fun getAccountsForWc(wcInteractor: WalletConnectInteractor, userWallet: UserWallet): List { + val walletManagerFacade = store.state.daggerGraphState + .get(DaggerGraphState::walletManagersFacade) + return walletManagerFacade.getStoredWalletManagers(userWallet.walletId).mapNotNull { + val wallet = it.wallet + val chainId = wcInteractor.blockchainHelper.networkIdToChainIdOrNull( + wallet.blockchain.toNetworkId(), + ) + chainId?.let { + Account( + chainId, + wallet.address, + wallet.publicKey.derivationPath?.rawPath, + ) + } + } + } } \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletconnect/WalletConnectActions.kt b/domain/legacy/src/main/java/com/tangem/domain/walletconnect/WalletConnectActions.kt new file mode 100644 index 0000000000..afb7d26d9f --- /dev/null +++ b/domain/legacy/src/main/java/com/tangem/domain/walletconnect/WalletConnectActions.kt @@ -0,0 +1,12 @@ +package com.tangem.domain.walletconnect + +import com.tangem.domain.wallets.models.UserWallet +import org.rekotlin.Action + +sealed class WalletConnectActions : Action { + sealed class New { + data class Initialize(val userWallet: UserWallet) : WalletConnectActions() + + data class SetupUserChains(val userWallet: UserWallet) : WalletConnectActions() + } +} \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagersFacade.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagersFacade.kt index 2a30480141..6df4bf3f84 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagersFacade.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagersFacade.kt @@ -77,6 +77,7 @@ interface WalletManagersFacade { derivationPath: String?, ): WalletManager? + @Deprecated("Will be removed in future") suspend fun getStoredWalletManagers(userWalletId: UserWalletId): List /** diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt index e860f3d518..9cb22da162 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletViewModel.kt @@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.viewmodels import androidx.lifecycle.* import androidx.paging.cachedIn +import arrow.core.Either import arrow.core.getOrElse import com.tangem.blockchain.blockchains.cardano.CardanoUtils import com.tangem.blockchain.common.Blockchain @@ -39,6 +40,7 @@ import com.tangem.domain.redux.LegacyAction import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.settings.* import com.tangem.domain.tokens.* +import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.legacy.TradeCryptoAction import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus @@ -48,6 +50,7 @@ import com.tangem.domain.tokens.models.analytics.TokenReceiveAnalyticsEvent import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase import com.tangem.domain.userwallets.UserWalletBuilder +import com.tangem.domain.walletconnect.WalletConnectActions import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId @@ -158,6 +161,7 @@ internal class WalletViewModel @Inject constructor( private var singleWalletCryptoCurrencyStatus: CryptoCurrencyStatus? = null private val tokensJobHolder = JobHolder() + private val updateWcJobHolder = JobHolder() private val marketPriceJobHolder = JobHolder() private val buttonsJobHolder = JobHolder() private val notificationsJobHolder = JobHolder() @@ -455,6 +459,7 @@ internal class WalletViewModel @Inject constructor( * If jobs aren't stopped and wallet is changed then it will update state for the prev wallet. */ tokensJobHolder.update(job = null) + updateWcJobHolder.update(job = null) marketPriceJobHolder.update(job = null) buttonsJobHolder.update(job = null) notificationsJobHolder.update(job = null) @@ -851,6 +856,7 @@ internal class WalletViewModel @Inject constructor( * If jobs aren't stopped and wallet is changed then it will update state for the prev wallet. */ tokensJobHolder.update(job = null) + updateWcJobHolder.update(job = null) marketPriceJobHolder.update(job = null) buttonsJobHolder.update(job = null) notificationsJobHolder.update(job = null) @@ -862,17 +868,22 @@ internal class WalletViewModel @Inject constructor( wallet.isLocked -> { uiState = stateFactory.getLockedState() } - wallet.isMultiCurrency -> getMultiCurrencyContent(index) + wallet.isMultiCurrency -> getMultiCurrencyContent(wallet, index) !wallet.isMultiCurrency -> getSingleCurrencyContent(index) } } - private fun getMultiCurrencyContent(walletIndex: Int) { + private fun getMultiCurrencyContent(wallet: UserWallet, walletIndex: Int) { val state = requireNotNull(uiState as? WalletMultiCurrencyState) { "Impossible to get a token list updates if state isn't WalletMultiCurrencyState" } - getTokenListUseCase(userWalletId = state.walletsListConfig.wallets[walletIndex].id) + val tokenListFlow = getTokenListUseCase(userWalletId = state.walletsListConfig.wallets[walletIndex].id) + .shareIn(viewModelScope, SharingStarted.WhileSubscribed()) + + initAndSetupWc(tokenListFlow, wallet) + + tokenListFlow .distinctUntilChanged() .onEach { maybeTokenList -> uiState = stateFactory.getStateByTokensList(maybeTokenList) @@ -905,6 +916,44 @@ internal class WalletViewModel @Inject constructor( } } + private fun initAndSetupWc(tokenListFlow: SharedFlow>, wallet: UserWallet) { + initWalletConnectForWallet(wallet) + tokenListFlow + .filter(::filterLoadedTokenList) + .take(1) + .onEach { + it.onRight { + setupWalletConnectOnWallet(wallet) + } + } + .flowOn(dispatchers.io) + .launchIn(viewModelScope) + .saveIn(updateWcJobHolder) + } + + private fun List.isAllCurrenciesLoaded(): Boolean { + return !this.any { it.value is CryptoCurrencyStatus.Loading } + } + + private fun filterLoadedTokenList(either: Either): Boolean { + return either.fold( + ifRight = { list -> + when (list) { + is TokenList.Ungrouped -> { + list.currencies.isAllCurrenciesLoaded() + } + is TokenList.GroupedByNetwork -> { + list.groups.flatMap { group -> group.currencies }.isAllCurrenciesLoaded() + } + else -> { + false + } + } + }, + ifLeft = { false }, + ) + } + private fun List.hasNonZeroWallets(): Boolean { return any { val amount = it.value.amount ?: return@any false @@ -1023,6 +1072,18 @@ internal class WalletViewModel @Inject constructor( ) } + private fun initWalletConnectForWallet(userWallet: UserWallet) { + reduxStateHolder.dispatch( + WalletConnectActions.New.Initialize(userWallet = userWallet), + ) + } + + private fun setupWalletConnectOnWallet(userWallet: UserWallet) { + reduxStateHolder.dispatch( + WalletConnectActions.New.SetupUserChains(userWallet = userWallet), + ) + } + private fun getWallet(index: Int): UserWallet { return requireNotNull( value = wallets.getOrNull(index),