Updated on 2026-08-14
This commit is contained in:
parent
8027be74aa
commit
a730af0f1f
9 changed files with 174 additions and 35 deletions
|
|
@ -28,6 +28,14 @@ internal object TokensDomainModule {
|
|||
return FetchTokenListUseCase(currenciesRepository, networksRepository, quotesRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideFetchPendingTransactionsUseCase(
|
||||
networksRepository: NetworksRepository,
|
||||
): FetchPendingTransactionsUseCase {
|
||||
return FetchPendingTransactionsUseCase(networksRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetTokenListUseCase(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import com.tangem.blockchain.common.transaction.Fee
|
|||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
||||
|
|
@ -174,33 +173,35 @@ private fun sendTransaction(
|
|||
transactionExtras.tonMemoState?.memo?.let { txData = txData.copy(extras = TonTransactionExtras(it)) }
|
||||
|
||||
scope.launch {
|
||||
val updateWalletResult = walletManager.safeUpdate()
|
||||
if (updateWalletResult is Result.Failure) {
|
||||
withMainContext {
|
||||
when (val error = updateWalletResult.error) {
|
||||
is TapError -> store.dispatchErrorNotification(error)
|
||||
is BlockchainSdkError -> {
|
||||
updateFeedbackManagerInfo(
|
||||
walletManager = walletManager,
|
||||
amountToSend = amountToSend,
|
||||
feeAmount = fee.amount,
|
||||
destinationAddress = destinationAddress,
|
||||
)
|
||||
dispatch(SendAction.Dialog.SendTransactionFails.BlockchainSdkError(error = error))
|
||||
}
|
||||
else -> {
|
||||
val tapError = if (error.message == null) {
|
||||
TapError.UnknownError
|
||||
} else {
|
||||
TapError.CustomError(error.message!!)
|
||||
}
|
||||
store.dispatchErrorNotification(tapError)
|
||||
}
|
||||
}
|
||||
dispatch(SendAction.ChangeSendButtonState(ButtonState.ENABLED))
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
// TODO: Risky commented this part, unknown logic, need to test if removed
|
||||
// TODO: [REDACTED_JIRA]
|
||||
// val updateWalletResult = walletManager.safeUpdate()
|
||||
// if (updateWalletResult is Result.Failure) {
|
||||
// withMainContext {
|
||||
// when (val error = updateWalletResult.error) {
|
||||
// is TapError -> store.dispatchErrorNotification(error)
|
||||
// is BlockchainSdkError -> {
|
||||
// updateFeedbackManagerInfo(
|
||||
// walletManager = walletManager,
|
||||
// amountToSend = amountToSend,
|
||||
// feeAmount = fee.amount,
|
||||
// destinationAddress = destinationAddress,
|
||||
// )
|
||||
// dispatch(SendAction.Dialog.SendTransactionFails.BlockchainSdkError(error = error))
|
||||
// }
|
||||
// else -> {
|
||||
// val tapError = if (error.message == null) {
|
||||
// TapError.UnknownError
|
||||
// } else {
|
||||
// TapError.CustomError(error.message!!)
|
||||
// }
|
||||
// store.dispatchErrorNotification(tapError)
|
||||
// }
|
||||
// }
|
||||
// dispatch(SendAction.ChangeSendButtonState(ButtonState.ENABLED))
|
||||
// }
|
||||
// return@launch
|
||||
// }
|
||||
|
||||
val tangemSdk = store.state.daggerGraphState.get(DaggerGraphState::cardSdkConfigRepository).sdk
|
||||
val linkedTerminalState = tangemSdk.config.linkedTerminal
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.tap.features.send.ui
|
|||
import androidx.lifecycle.*
|
||||
import com.tangem.domain.balancehiding.IsBalanceHiddenUseCase
|
||||
import com.tangem.domain.balancehiding.ListenToFlipsUseCase
|
||||
import com.tangem.domain.tokens.FetchPendingTransactionsUseCase
|
||||
import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
|
|
@ -32,6 +33,7 @@ internal class SendViewModel @Inject constructor(
|
|||
private val listenToFlipsUseCase: ListenToFlipsUseCase,
|
||||
private val updateDelayedCurrencyStatusUseCase: UpdateDelayedNetworkStatusUseCase,
|
||||
private val getSelectedWalletUseCase: GetSelectedWalletUseCase,
|
||||
private val fetchPendingTransactionsUseCase: FetchPendingTransactionsUseCase,
|
||||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel(), DefaultLifecycleObserver {
|
||||
|
|
@ -75,12 +77,7 @@ internal class SendViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private suspend fun updateForPendingTx(userWallet: UserWallet, network: Network) {
|
||||
updateDelayedCurrencyStatusUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
network = network,
|
||||
delayMillis = UPDATE_PENDING_TX_DELAY_MILLIS,
|
||||
refresh = true,
|
||||
)
|
||||
fetchPendingTransactionsUseCase(userWallet.walletId, setOf(network))
|
||||
}
|
||||
|
||||
private suspend fun updateForBalance(userWallet: UserWallet, network: Network) {
|
||||
|
|
@ -94,7 +91,6 @@ internal class SendViewModel @Inject constructor(
|
|||
|
||||
companion object {
|
||||
private const val UPDATE_BALANCE_DELAY_MILLIS = 11000L
|
||||
private const val UPDATE_PENDING_TX_DELAY_MILLIS = 1000L
|
||||
private const val TAG = "SendViewModel"
|
||||
}
|
||||
}
|
||||
|
|
@ -51,6 +51,12 @@ internal class DefaultNetworksRepository(
|
|||
}
|
||||
}.cancellable()
|
||||
|
||||
override suspend fun fetchNetworkPendingTransactions(userWalletId: UserWalletId, networks: Set<Network>) {
|
||||
withContext(dispatchers.io) {
|
||||
fetchNetworksPendingTransactionsIfCacheExpired(userWalletId, networks, false)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getNetworkStatusesSync(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
|
|
@ -76,6 +82,22 @@ internal class DefaultNetworksRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchNetworksPendingTransactionsIfCacheExpired(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
coroutineScope {
|
||||
networks
|
||||
.map { network ->
|
||||
async {
|
||||
fetchNetworkPendingTransactionsIfCacheExpired(userWalletId, network, refresh)
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchNetworkStatusIfCacheExpired(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
|
|
@ -88,6 +110,20 @@ internal class DefaultNetworksRepository(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun fetchNetworkPendingTransactionsIfCacheExpired(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
val key = getNetworksStatusesCacheKey(userWalletId, network)
|
||||
cacheRegistry.invalidate(key)
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = key,
|
||||
skipCache = refresh,
|
||||
block = { fetchNetworkPendingTransactions(userWalletId, network) },
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun fetchNetworkStatus(userWalletId: UserWalletId, network: Network) {
|
||||
val currencies = getCurrencies(userWalletId, network)
|
||||
|
||||
|
|
@ -110,6 +146,27 @@ internal class DefaultNetworksRepository(
|
|||
networksStatusesStore.store(userWalletId, networkStatus)
|
||||
}
|
||||
|
||||
private suspend fun fetchNetworkPendingTransactions(userWalletId: UserWalletId, network: Network) {
|
||||
val currencies = getCurrencies(userWalletId, network)
|
||||
|
||||
val result = walletManagersFacade.updatePendingTransactions(
|
||||
userWalletId = userWalletId,
|
||||
network = network,
|
||||
)
|
||||
|
||||
withContext(NonCancellable) {
|
||||
invalidateCacheKeyIfNeeded(userWalletId, network, result)
|
||||
}
|
||||
|
||||
val networkStatus = networkStatusFactory.createNetworkStatus(
|
||||
network = network,
|
||||
result = result,
|
||||
currencies = currencies.toSet(),
|
||||
)
|
||||
|
||||
networksStatusesStore.store(userWalletId, networkStatus)
|
||||
}
|
||||
|
||||
private suspend fun getCurrencies(userWalletId: UserWalletId, network: Network): Sequence<CryptoCurrency> {
|
||||
val userWallet = requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
|
||||
"Unable to find user wallet with provided ID: $userWalletId"
|
||||
|
|
|
|||
|
|
@ -57,6 +57,28 @@ class DefaultWalletManagersFacade(
|
|||
return getAndUpdateWalletManager(userWallet, blockchain, derivationPath, extraTokens)
|
||||
}
|
||||
|
||||
override suspend fun updatePendingTransactions(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
): UpdateWalletManagerResult {
|
||||
val userWallet = getUserWallet(userWalletId)
|
||||
val blockchain = Blockchain.fromId(network.id.value)
|
||||
val derivationPath = network.derivationPath.value
|
||||
|
||||
if (derivationPath != null && !userWallet.scanResponse.hasDerivation(blockchain, derivationPath)) {
|
||||
Timber.w("Derivation missed for: $blockchain")
|
||||
return UpdateWalletManagerResult.MissedDerivation
|
||||
}
|
||||
|
||||
val walletManager = getOrCreateWalletManager(userWalletId, blockchain, derivationPath)
|
||||
if (walletManager == null || blockchain == Blockchain.Unknown) {
|
||||
Timber.w("Unable to get a wallet manager for blockchain: $blockchain")
|
||||
return UpdateWalletManagerResult.Unreachable
|
||||
}
|
||||
|
||||
return getLastWalletManagerResult(walletManager)
|
||||
}
|
||||
|
||||
override suspend fun getExploreUrl(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
|
|
@ -196,6 +218,18 @@ class DefaultWalletManagersFacade(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getLastWalletManagerResult(walletManager: WalletManager): UpdateWalletManagerResult {
|
||||
return try {
|
||||
resultFactory.getResult(walletManager)
|
||||
} catch (e: BlockchainSdkError.AccountNotFound) {
|
||||
resultFactory.getNoAccountResult(walletManager = walletManager, customMessage = e.customMessage)
|
||||
} catch (e: Throwable) {
|
||||
Timber.w(e, "Unable to update a wallet manager for: ${walletManager.wallet.blockchain}")
|
||||
|
||||
UpdateWalletManagerResult.Unreachable
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getOrCreateWalletManager(
|
||||
userWalletId: UserWalletId,
|
||||
blockchain: Blockchain,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,15 @@ interface WalletManagersFacade {
|
|||
extraTokens: Set<CryptoCurrency.Token>,
|
||||
): UpdateWalletManagerResult
|
||||
|
||||
/**
|
||||
* Returns [UpdateWalletManagerResult] with last pending transactions
|
||||
*
|
||||
* @param userWalletId The ID of the user's wallet.
|
||||
* @param network The network.
|
||||
* @return The result of updating the wallet manager.
|
||||
*/
|
||||
suspend fun updatePendingTransactions(userWalletId: UserWalletId, network: Network): UpdateWalletManagerResult
|
||||
|
||||
/**
|
||||
* Returns network explorer URL of the wallet manager associated with a user's wallet and network.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
|
||||
/**
|
||||
* Use case responsible for fetching current pending transactions
|
||||
*
|
||||
* @param networksRepository The repository for retrieving network-related data.
|
||||
*/
|
||||
class FetchPendingTransactionsUseCase(
|
||||
private val networksRepository: NetworksRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(userWalletId: UserWalletId, networks: Set<Network>) {
|
||||
coroutineScope {
|
||||
networksRepository.fetchNetworkPendingTransactions(userWalletId, networks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,14 @@ interface NetworksRepository {
|
|||
*/
|
||||
fun getNetworkStatusesUpdates(userWalletId: UserWalletId, networks: Set<Network>): Flow<Set<NetworkStatus>>
|
||||
|
||||
/**
|
||||
* Fetches pending transactions for given network
|
||||
*
|
||||
* @param userWalletId The unique identifier of the user wallet.
|
||||
* @param networks A set of network which statuses are to be retrieved.
|
||||
*/
|
||||
suspend fun fetchNetworkPendingTransactions(userWalletId: UserWalletId, networks: Set<Network>)
|
||||
|
||||
/**
|
||||
* Retrieves network statuses of specified blockchain networks for a specific user wallet.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ internal class MockNetworksRepository(
|
|||
return statuses.map { it.getOrElse { e -> throw e } }
|
||||
}
|
||||
|
||||
override suspend fun fetchNetworkPendingTransactions(userWalletId: UserWalletId, networks: Set<Network>) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
override suspend fun getNetworkStatusesSync(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue