Updated on 2026-08-14
This commit is contained in:
parent
c68ca68b13
commit
1c7148015f
20 changed files with 383 additions and 22 deletions
|
|
@ -19,12 +19,14 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.core.os.bundleOf
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.flowWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import arrow.core.getOrElse
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.deeplink.DeepLinksRegistry
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
|
|
@ -35,10 +37,13 @@ import com.tangem.data.card.sdk.CardSdkLifecycleObserver
|
|||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
|
||||
import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManagerFeatureToggles
|
||||
import com.tangem.domain.wallets.legacy.asLockable
|
||||
import com.tangem.feature.qrscanning.QrScanningRouter
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
|
||||
import com.tangem.features.managetokens.navigation.ManageTokensUi
|
||||
import com.tangem.features.send.api.navigation.SendRouter
|
||||
import com.tangem.features.tester.api.TesterRouter
|
||||
|
|
@ -99,6 +104,7 @@ val userWalletsListManagerSafe: UserWalletsListManager?
|
|||
val userWalletsListManager: UserWalletsListManager
|
||||
get() = userWalletsListManagerSafe!!
|
||||
|
||||
@Suppress("LargeClass")
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbackHolder {
|
||||
|
||||
|
|
@ -148,6 +154,15 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
@Inject
|
||||
lateinit var generalUserWalletsListManager: UserWalletsListManager
|
||||
|
||||
@Inject
|
||||
lateinit var getPolkadotCheckHasResetUseCase: GetPolkadotCheckHasResetUseCase
|
||||
|
||||
@Inject
|
||||
lateinit var getPolkadotCheckHasImmortalUseCase: GetPolkadotCheckHasImmortalUseCase
|
||||
|
||||
@Inject
|
||||
lateinit var analyticsEventsHandler: AnalyticsEventHandler
|
||||
|
||||
internal val viewModel: MainViewModel by viewModels()
|
||||
|
||||
private lateinit var appThemeModeFlow: SharedFlow<AppThemeMode?>
|
||||
|
|
@ -177,6 +192,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
|
||||
checkForNotificationPermission()
|
||||
observeStateUpdates()
|
||||
observePolkadotAccountHealthCheck()
|
||||
|
||||
if (intent != null) {
|
||||
deepLinksRegistry.launch(intent)
|
||||
|
|
@ -482,4 +498,19 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observePolkadotAccountHealthCheck() {
|
||||
lifecycleScope.launch {
|
||||
getPolkadotCheckHasResetUseCase()
|
||||
.flowWithLifecycle(lifecycle, minActiveState = Lifecycle.State.CREATED)
|
||||
.collect {
|
||||
analyticsEventsHandler.send(WalletScreenAnalyticsEvent.Token.PolkadotAccountReset(it))
|
||||
}
|
||||
getPolkadotCheckHasImmortalUseCase()
|
||||
.flowWithLifecycle(lifecycle, minActiveState = Lifecycle.State.CREATED)
|
||||
.collect {
|
||||
analyticsEventsHandler.send(WalletScreenAnalyticsEvent.Token.PolkadotImmortalTransactions(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,9 @@ import android.content.Context
|
|||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.exchange.RampStateManager
|
||||
import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
|
||||
import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
|
||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
||||
import com.tangem.tap.domain.TangemSdkManager
|
||||
import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository
|
||||
import com.tangem.tap.network.exchangeServices.DefaultRampManager
|
||||
|
|
@ -57,4 +60,20 @@ internal object ActivityModule {
|
|||
fun provideActivityDelayedWorkCoroutineScope(): CoroutineScope {
|
||||
return CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetPolkadotCheckHasResetUseCase(
|
||||
polkadotAccountHealthCheckRepository: PolkadotAccountHealthCheckRepository,
|
||||
): GetPolkadotCheckHasResetUseCase {
|
||||
return GetPolkadotCheckHasResetUseCase(polkadotAccountHealthCheckRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetPolkadotCheckHasImmortalUseCase(
|
||||
polkadotAccountHealthCheckRepository: PolkadotAccountHealthCheckRepository,
|
||||
): GetPolkadotCheckHasImmortalUseCase {
|
||||
return GetPolkadotCheckHasImmortalUseCase(polkadotAccountHealthCheckRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -332,4 +332,13 @@ internal object TokensDomainModule {
|
|||
): IsAmountSubtractAvailableUseCase {
|
||||
return IsAmountSubtractAvailableUseCase(currenciesRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideRunPolkadotAccountHealthCheckUseCase(
|
||||
repository: PolkadotAccountHealthCheckRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): RunPolkadotAccountHealthCheckUseCase {
|
||||
return RunPolkadotAccountHealthCheckUseCase(repository, dispatchers)
|
||||
}
|
||||
}
|
||||
|
|
@ -63,6 +63,16 @@ object PreferencesKeys {
|
|||
|
||||
val APP_LOGS_KEY by lazy { stringPreferencesKey(name = "app_logs") }
|
||||
|
||||
val POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX by lazy {
|
||||
stringPreferencesKey(name = "POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX")
|
||||
}
|
||||
val POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS by lazy {
|
||||
stringPreferencesKey(name = "POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS")
|
||||
}
|
||||
val POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS by lazy {
|
||||
stringPreferencesKey(name = "POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS")
|
||||
}
|
||||
|
||||
fun getStart2CoinTOSAcceptedKey(region: String?) = booleanPreferencesKey(name = "start2Coin_tos_accepted_$region")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -119,4 +119,16 @@ internal object TokensDataModule {
|
|||
fun provideCurrencyChecksRepository(walletManagersFacade: WalletManagersFacade): CurrencyChecksRepository {
|
||||
return DefaultCurrencyChecksRepository(walletManagersFacade = walletManagersFacade)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providePolkadotAccountHealthCheckRepository(
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
appPreferencesStore: AppPreferencesStore,
|
||||
): PolkadotAccountHealthCheckRepository {
|
||||
return DefaultPolkadotAccountHealthCheckRepository(
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
appPreferencesStore = appPreferencesStore,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ import kotlinx.coroutines.flow.channelFlow
|
|||
import kotlinx.coroutines.flow.collectLatest
|
||||
import timber.log.Timber
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultNetworksRepository(
|
||||
private val networksStatusesStore: NetworksStatusesStore,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,169 @@
|
|||
package com.tangem.data.tokens.repository
|
||||
|
||||
import com.tangem.blockchain.blockchains.polkadot.AccountCheckProvider
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys.POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys.POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys.POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectListSync
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectMap
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultPolkadotAccountHealthCheckRepository(
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
) : PolkadotAccountHealthCheckRepository {
|
||||
|
||||
private val hasImmortalTransaction = MutableSharedFlow<Boolean>()
|
||||
private val hasResetTransaction = MutableSharedFlow<Boolean>()
|
||||
|
||||
private val mutex = Mutex()
|
||||
|
||||
override suspend fun runCheck(userWalletId: UserWalletId, network: Network) {
|
||||
// Run Polkadot account health check
|
||||
if (Blockchain.fromId(network.id.value) != Blockchain.Polkadot) return
|
||||
|
||||
mutex.withLock {
|
||||
val walletManager = walletManagersFacade.getOrCreateWalletManager(userWalletId, network)
|
||||
val accountCheckProvider = requireNotNull(walletManager as AccountCheckProvider) {
|
||||
Timber.e("Unable to cast wallet manager to AccountCheckProvider")
|
||||
return
|
||||
}
|
||||
val address = walletManager.wallet.address
|
||||
|
||||
checkHasReset(accountCheckProvider, address)
|
||||
checkHasImmortal(accountCheckProvider, address)
|
||||
}
|
||||
}
|
||||
|
||||
override fun subscribeToHasImmortalResults() = hasImmortalTransaction.asSharedFlow()
|
||||
|
||||
override fun subscribeToHasResetResults() = hasResetTransaction.asSharedFlow()
|
||||
|
||||
private suspend fun checkHasReset(polkadotManager: AccountCheckProvider, address: String) {
|
||||
val checkedAddresses = appPreferencesStore.getObjectListSync<String>(POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS)
|
||||
if (checkedAddresses.contains(address)) return
|
||||
runCatching {
|
||||
val accountInfo = requireNotNull(polkadotManager.getAccountInfo().account) {
|
||||
Timber.e("Account info is null")
|
||||
}
|
||||
val nonce = accountInfo.nonce
|
||||
val extrinsicCount = accountInfo.countExtrinsic
|
||||
|
||||
// Account was reset
|
||||
if (nonce != null && extrinsicCount != null) {
|
||||
hasResetTransaction.emit(nonce < extrinsicCount)
|
||||
updateCheckedResetAddressesList(address)
|
||||
}
|
||||
}.onFailure {
|
||||
if ((it as? BlockchainSdkError.CustomError)?.customMessage == ACCOUNT_NOT_FOUND) {
|
||||
updateCheckedResetAddressesList(address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun checkHasImmortal(polkadotManager: AccountCheckProvider, address: String) {
|
||||
val checkedAddresses = appPreferencesStore.getObjectListSync<String>(POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS)
|
||||
if (checkedAddresses.contains(address)) return
|
||||
|
||||
runCatching {
|
||||
do {
|
||||
// Getting batch of extrinsics to check
|
||||
val lastChecked = appPreferencesStore.getObjectMap<Long>(POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX)
|
||||
val lastExtrinsic = lastChecked[address]
|
||||
val extrinsicListResult = polkadotManager.getExtrinsicList(afterExtrinsicId = lastExtrinsic)
|
||||
// Checking extrinsic one by one
|
||||
extrinsicListResult.extrinsic?.forEach { tx ->
|
||||
val hash = tx.hash
|
||||
val id = tx.id
|
||||
if (hash != null && id != null) {
|
||||
val details = polkadotManager.getExtrinsicDetail(hash)
|
||||
|
||||
// We found an `immortal` transaction
|
||||
if (details.lifetime == null) {
|
||||
hasImmortalTransaction.emit(true)
|
||||
updateCheckedImmutableAddressesList(address)
|
||||
clearLastCheckedTransaction(address)
|
||||
return
|
||||
}
|
||||
|
||||
// Saving last checked transaction
|
||||
updateLastCheckedTransaction(address, id)
|
||||
}
|
||||
}
|
||||
} while (!extrinsicListResult.extrinsic.isNullOrEmpty())
|
||||
|
||||
// We checked all transactions up to current moment and did not found an `immortal` transaction
|
||||
hasImmortalTransaction.emit(false)
|
||||
updateCheckedImmutableAddressesList(address)
|
||||
clearLastCheckedTransaction(address)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateLastCheckedTransaction(address: String, txId: Long) {
|
||||
appPreferencesStore.editData {
|
||||
val savedList = it.getObjectMap<Long>(POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX)
|
||||
val updatedList = savedList.toMutableMap()
|
||||
updatedList[address] = txId
|
||||
it.setObjectMap(POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX, updatedList)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun clearLastCheckedTransaction(address: String) {
|
||||
appPreferencesStore.editData { mutablePreferences ->
|
||||
val savedList = mutablePreferences.getObjectMap<Long>(POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX)
|
||||
val updatedList = savedList.toMutableMap()
|
||||
updatedList.remove(address)
|
||||
mutablePreferences.setObjectMap(POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX, updatedList)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateCheckedImmutableAddressesList(address: String) {
|
||||
appPreferencesStore.editData { mutablePreferences ->
|
||||
val savedList = mutablePreferences.getObjectList<String>(POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS)
|
||||
val updatedList = savedList?.toMutableList()
|
||||
updatedList?.addOrReplace(address) { it == address }
|
||||
|
||||
if (updatedList != null) {
|
||||
mutablePreferences.setObjectList(
|
||||
POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS,
|
||||
updatedList.toList(),
|
||||
)
|
||||
} else {
|
||||
mutablePreferences.remove(POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateCheckedResetAddressesList(address: String) {
|
||||
appPreferencesStore.editData { mutablePreferences ->
|
||||
val savedList = mutablePreferences.getObjectList<String>(POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS)
|
||||
val updatedList = savedList?.toMutableList()
|
||||
updatedList?.addOrReplace(address) { it == address }
|
||||
|
||||
if (updatedList != null) {
|
||||
mutablePreferences.setObjectList(
|
||||
POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS,
|
||||
updatedList.toList(),
|
||||
)
|
||||
} else {
|
||||
mutablePreferences.remove(POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val ACCOUNT_NOT_FOUND = "Record Not Found"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class GetPolkadotCheckHasImmortalUseCase(
|
||||
private val polkadotAccountHealthCheckRepository: PolkadotAccountHealthCheckRepository,
|
||||
) {
|
||||
operator fun invoke(): Flow<Boolean> = polkadotAccountHealthCheckRepository.subscribeToHasImmortalResults()
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class GetPolkadotCheckHasResetUseCase(
|
||||
private val polkadotAccountHealthCheckRepository: PolkadotAccountHealthCheckRepository,
|
||||
) {
|
||||
|
||||
operator fun invoke(): Flow<Boolean> = polkadotAccountHealthCheckRepository.subscribeToHasResetResults()
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class RunPolkadotAccountHealthCheckUseCase(
|
||||
private val polkadotAccountHealthCheckRepository: PolkadotAccountHealthCheckRepository,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(userWalletId: UserWalletId, network: Network) = withContext(dispatchers.io) {
|
||||
polkadotAccountHealthCheckRepository.runCheck(userWalletId, network)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.domain.tokens.repository
|
||||
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface PolkadotAccountHealthCheckRepository {
|
||||
|
||||
suspend fun runCheck(userWalletId: UserWalletId, network: Network)
|
||||
|
||||
fun subscribeToHasImmortalResults(): Flow<Boolean>
|
||||
|
||||
fun subscribeToHasResetResults(): Flow<Boolean>
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@ sealed class WalletScreenAnalyticsEvent {
|
|||
override val oneTimeEventId: String = id + userWalletId.stringValue
|
||||
}
|
||||
|
||||
object WalletOpened : Basic(event = "Wallet Opened")
|
||||
data object WalletOpened : Basic(event = "Wallet Opened")
|
||||
|
||||
class CardWasScanned(source: AnalyticsParam.ScannedFrom) : Basic(
|
||||
event = "Card Was Scanned",
|
||||
|
|
@ -48,13 +48,33 @@ sealed class WalletScreenAnalyticsEvent {
|
|||
)
|
||||
}
|
||||
|
||||
sealed class Token(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent(category = "Token", event = event, params = params) {
|
||||
|
||||
class PolkadotAccountReset(hasReset: Boolean) : Token(
|
||||
event = "Polkadot Account Reset",
|
||||
params = mapOf(
|
||||
AnalyticsParam.STATE to if (hasReset) "Yes" else "No",
|
||||
),
|
||||
)
|
||||
|
||||
class PolkadotImmortalTransactions(hasImmortalTransaction: Boolean) : Token(
|
||||
event = "Polkadot Immortal Transactions",
|
||||
params = mapOf(
|
||||
AnalyticsParam.STATE to if (hasImmortalTransaction) "Yes" else "No",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
sealed class MainScreen(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent(category = "Main Screen", event = event, params = params) {
|
||||
|
||||
object ScreenOpened : MainScreen(event = "Screen opened")
|
||||
object WalletSwipe : MainScreen(event = "Wallet Swipe")
|
||||
data object ScreenOpened : MainScreen(event = "Screen opened")
|
||||
data object WalletSwipe : MainScreen(event = "Wallet Swipe")
|
||||
|
||||
class EnableBiometrics(state: AnalyticsParam.OnOffState) : MainScreen(
|
||||
event = "Enable Biometric",
|
||||
|
|
@ -66,37 +86,37 @@ sealed class WalletScreenAnalyticsEvent {
|
|||
params = mapOf("Result" to result.value),
|
||||
)
|
||||
|
||||
object NoticeBackupYourWalletTapped : MainScreen(event = "Notice - Backup Your Wallet Tapped")
|
||||
object NoticeScanYourCardTapped : MainScreen(event = "Notice - Scan Your Card Tapped")
|
||||
object NoticeWalletLocked : MainScreen(event = "Notice - Wallet Locked")
|
||||
object WalletUnlockTapped : MainScreen(event = "Notice - Wallet Unlock Tapped")
|
||||
data object NoticeBackupYourWalletTapped : MainScreen(event = "Notice - Backup Your Wallet Tapped")
|
||||
data object NoticeScanYourCardTapped : MainScreen(event = "Notice - Scan Your Card Tapped")
|
||||
data object NoticeWalletLocked : MainScreen(event = "Notice - Wallet Locked")
|
||||
data object WalletUnlockTapped : MainScreen(event = "Notice - Wallet Unlock Tapped")
|
||||
|
||||
object NetworksUnreachable : MainScreen(event = "Notice - Networks Unreachable")
|
||||
data object NetworksUnreachable : MainScreen(event = "Notice - Networks Unreachable")
|
||||
|
||||
object MissingAddresses : MainScreen(event = "Notice - Missing Addresses")
|
||||
data object MissingAddresses : MainScreen(event = "Notice - Missing Addresses")
|
||||
|
||||
object CardSignedTransactions : MainScreen(event = "Notice - Card Signed Transactions")
|
||||
data object CardSignedTransactions : MainScreen(event = "Notice - Card Signed Transactions")
|
||||
|
||||
object HowDoYouLikeTangem : MainScreen(event = "Notice - How Do You Like Tangem")
|
||||
data object HowDoYouLikeTangem : MainScreen(event = "Notice - How Do You Like Tangem")
|
||||
|
||||
object ProductSampleCard : MainScreen(event = "Notice - Product Sample Card")
|
||||
data object ProductSampleCard : MainScreen(event = "Notice - Product Sample Card")
|
||||
|
||||
object TestnetCard : MainScreen(event = "Notice - Testnet Card")
|
||||
data object TestnetCard : MainScreen(event = "Notice - Testnet Card")
|
||||
|
||||
object DemoCard : MainScreen(event = "Notice - Demo Card")
|
||||
data object DemoCard : MainScreen(event = "Notice - Demo Card")
|
||||
|
||||
object DevelopmentCard : MainScreen(event = "Notice - Development Card")
|
||||
data object DevelopmentCard : MainScreen(event = "Notice - Development Card")
|
||||
|
||||
object WalletUnlock : MainScreen(event = "Notice - Wallet Unlock")
|
||||
data object WalletUnlock : MainScreen(event = "Notice - Wallet Unlock")
|
||||
|
||||
object BackupYourWallet : MainScreen(event = "Notice - Backup Your Wallet")
|
||||
data object BackupYourWallet : MainScreen(event = "Notice - Backup Your Wallet")
|
||||
|
||||
object UnlockAllWithBiometrics : MainScreen(event = "Button - Unlock All With Biometrics")
|
||||
data object UnlockAllWithBiometrics : MainScreen(event = "Button - Unlock All With Biometrics")
|
||||
|
||||
object UnlockWithCardScan : MainScreen(event = "Button - Unlock With Card Scan")
|
||||
data object UnlockWithCardScan : MainScreen(event = "Button - Unlock With Card Scan")
|
||||
|
||||
object EditWalletTapped : MainScreen(event = "Button - Edit Wallet Tapped")
|
||||
data object EditWalletTapped : MainScreen(event = "Button - Edit Wallet Tapped")
|
||||
|
||||
object DeleteWalletTapped : MainScreen(event = "Button - Delete Wallet Tapped")
|
||||
data object DeleteWalletTapped : MainScreen(event = "Button - Delete Wallet Tapped")
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
|||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
|
||||
import com.tangem.domain.tokens.GetTokenListUseCase
|
||||
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
||||
|
|
@ -29,6 +30,7 @@ internal class MultiWalletContentLoader(
|
|||
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
|
||||
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
|
||||
private val reduxStateHolder: ReduxStateHolder,
|
||||
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
|
||||
) : WalletContentLoader(id = userWallet.walletId) {
|
||||
|
||||
override fun create(): List<WalletSubscriber> {
|
||||
|
|
@ -42,6 +44,7 @@ internal class MultiWalletContentLoader(
|
|||
getTokenListUseCase = getTokenListUseCase,
|
||||
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
|
||||
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
|
||||
),
|
||||
MultiWalletWarningsSubscriber(
|
||||
userWallet = userWallet,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
|||
import com.tangem.domain.redux.ReduxStateHolder
|
||||
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
|
||||
import com.tangem.domain.tokens.GetTokenListUseCase
|
||||
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
||||
|
|
@ -26,6 +27,7 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
|
|||
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
|
||||
private val reduxStateHolder: ReduxStateHolder,
|
||||
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
|
||||
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
|
||||
) {
|
||||
|
||||
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): WalletContentLoader {
|
||||
|
|
@ -41,6 +43,7 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
|
|||
reduxStateHolder = reduxStateHolder,
|
||||
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
|
||||
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
|
||||
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
|
|||
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.tokens.GetCardTokensListUseCase
|
||||
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
||||
|
|
@ -24,6 +25,7 @@ internal class SingleWalletWithTokenContentLoader(
|
|||
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
|
||||
private val getCardTokensListUseCase: GetCardTokensListUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
|
||||
) : WalletContentLoader(id = userWallet.walletId) {
|
||||
|
||||
override fun create(): List<WalletSubscriber> {
|
||||
|
|
@ -36,6 +38,7 @@ internal class SingleWalletWithTokenContentLoader(
|
|||
walletWithFundsChecker = walletWithFundsChecker,
|
||||
getCardTokensListUseCase = getCardTokensListUseCase,
|
||||
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
|
||||
),
|
||||
MultiWalletWarningsSubscriber(
|
||||
userWallet = userWallet,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
|
|||
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.tokens.GetCardTokensListUseCase
|
||||
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
|
||||
|
|
@ -21,6 +22,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
|
|||
private val getCardTokensListUseCase: GetCardTokensListUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
|
||||
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
|
||||
) {
|
||||
|
||||
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): SingleWalletWithTokenContentLoader {
|
||||
|
|
@ -34,6 +36,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
|
|||
getCardTokensListUseCase = getCardTokensListUseCase,
|
||||
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
|
||||
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,9 @@ import arrow.core.Either
|
|||
import arrow.core.getOrElse
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.NetworkGroup
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||
|
|
@ -33,6 +35,7 @@ internal abstract class BasicTokenListSubscriber(
|
|||
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
|
||||
private val walletWithFundsChecker: WalletWithFundsChecker,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
|
||||
) : WalletSubscriber() {
|
||||
|
||||
private val sendAnalyticsJobHolder = JobHolder()
|
||||
|
|
@ -53,6 +56,8 @@ internal abstract class BasicTokenListSubscriber(
|
|||
coroutineScope.launch {
|
||||
onTokenListReceived(maybeTokenList)
|
||||
}.saveIn(onTokenListReceivedJobHolder)
|
||||
|
||||
coroutineScope.launch { startCheck(maybeTokenList) }
|
||||
},
|
||||
flow2 = getSelectedAppCurrencyUseCase().distinctUntilChanged(),
|
||||
transform = { maybeTokenList, maybeAppCurrency ->
|
||||
|
|
@ -72,6 +77,21 @@ internal abstract class BasicTokenListSubscriber(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun startCheck(maybeTokenList: Either<TokenListError, TokenList>) {
|
||||
// Run Polkadot account health check
|
||||
maybeTokenList.getOrNull()?.let { tokenList ->
|
||||
val cryptoCurrencies = when (tokenList) {
|
||||
is TokenList.GroupedByNetwork -> tokenList.groups.flatMap(NetworkGroup::currencies)
|
||||
is TokenList.Ungrouped -> tokenList.currencies
|
||||
is TokenList.Empty -> emptyList()
|
||||
}
|
||||
|
||||
cryptoCurrencies.forEach {
|
||||
runPolkadotAccountHealthCheckUseCase(userWallet.walletId, it.currency.network)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected open suspend fun onTokenListReceived(maybeTokenList: Either<TokenListError, TokenList>) {
|
||||
/* no-op */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import arrow.core.getOrElse
|
|||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
|
||||
import com.tangem.domain.tokens.GetTokenListUseCase
|
||||
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
|
|
@ -24,6 +25,7 @@ internal class MultiWalletTokenListSubscriber(
|
|||
tokenListAnalyticsSender: TokenListAnalyticsSender,
|
||||
walletWithFundsChecker: WalletWithFundsChecker,
|
||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
|
||||
) : BasicTokenListSubscriber(
|
||||
userWallet = userWallet,
|
||||
stateHolder = stateHolder,
|
||||
|
|
@ -31,6 +33,7 @@ internal class MultiWalletTokenListSubscriber(
|
|||
tokenListAnalyticsSender = tokenListAnalyticsSender,
|
||||
walletWithFundsChecker = walletWithFundsChecker,
|
||||
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
|
||||
) {
|
||||
|
||||
override fun tokenListFlow(): MaybeTokenListFlow = getTokenListUseCase(userWallet.walletId)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers
|
|||
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.tokens.GetCardTokensListUseCase
|
||||
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
|
||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
|
||||
|
|
@ -17,6 +18,7 @@ internal class SingleWalletWithTokenListSubscriber(
|
|||
tokenListAnalyticsSender: TokenListAnalyticsSender,
|
||||
walletWithFundsChecker: WalletWithFundsChecker,
|
||||
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
|
||||
) : BasicTokenListSubscriber(
|
||||
userWallet = userWallet,
|
||||
stateHolder = stateHolder,
|
||||
|
|
@ -24,6 +26,7 @@ internal class SingleWalletWithTokenListSubscriber(
|
|||
tokenListAnalyticsSender = tokenListAnalyticsSender,
|
||||
walletWithFundsChecker = walletWithFundsChecker,
|
||||
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
|
||||
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
|
||||
) {
|
||||
|
||||
override fun tokenListFlow(): MaybeTokenListFlow = getCardTokensListUseCase(userWallet.walletId)
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ web3j = "4.10.1"
|
|||
# endregion Other libraries
|
||||
|
||||
# region Tangem
|
||||
tangemBlockchainSdk = "release-app_5.8-536"
|
||||
tangemBlockchainSdk = "release-app_5.8-542"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "release-app_5.8-338"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue