From 0fb5081daf9b9189231e315bdec290519e857cef Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 13 Nov 2025 13:00:46 +0500 Subject: [PATCH] Updated on 2026-08-14 --- ...TransactionDataToTxHistoryItemConverter.kt | 57 ++++++++++++++----- data/yield-supply/build.gradle.kts | 1 + .../supply/DefaultYieldSupplyRepository.kt | 50 +++++++++++++++- .../yield/supply/YieldSupplyRepository.kt | 19 ++++++- .../impl/main/model/YieldSupplyModel.kt | 36 ++++++++---- gradle/tangem_dependencies.toml | 2 +- 6 files changed, 133 insertions(+), 32 deletions(-) diff --git a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt index 5701b7eb2e..dae65d3ec7 100644 --- a/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt +++ b/data/wallet-manager/src/main/java/com/tangem/data/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt @@ -1,10 +1,13 @@ package com.tangem.data.walletmanager.utils import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras +import com.tangem.blockchain.blockchains.ethereum.tokenmethods.ApprovalERC20TokenCallData import com.tangem.blockchain.common.* import com.tangem.blockchain.yieldsupply.providers.ethereum.factory.EthereumYieldSupplyDeployCallData import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyEnterCallData import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyExitCallData +import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyInitTokenCallData +import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyReactivateTokenCallData import com.tangem.blockchainsdk.models.UpdateWalletManagerResult.Address import com.tangem.domain.models.network.TxInfo import com.tangem.utils.converter.Converter @@ -37,25 +40,12 @@ internal class TransactionDataToTxHistoryItemConverter( addressType = TxInfo.AddressType.User(value.destinationAddress), ), sourceType = TxInfo.SourceType.Single(value.sourceAddress), - interactionAddressType = TxInfo.InteractionAddressType.User( - address = if (isOutgoing) value.destinationAddress else value.sourceAddress, - ), + interactionAddressType = getInteractionAddressType(value, isOutgoing), status = when (value.status) { TransactionStatus.Confirmed -> TxInfo.TransactionStatus.Confirmed TransactionStatus.Unconfirmed -> TxInfo.TransactionStatus.Unconfirmed }, - type = when (val extras = value.extras) { - is EthereumTransactionExtras -> { - when (extras.callData) { - is EthereumYieldSupplyDeployCallData, - is EthereumYieldSupplyEnterCallData, - -> TxInfo.TransactionType.YieldSupply.Enter - is EthereumYieldSupplyExitCallData -> TxInfo.TransactionType.YieldSupply.Exit - else -> TxInfo.TransactionType.Transfer - } - } - else -> TxInfo.TransactionType.Transfer - }, + type = getTransactionType(value.extras), amount = amount, ) } @@ -89,4 +79,41 @@ internal class TransactionDataToTxHistoryItemConverter( return amountToken.contractAddress.equals(feeToken.contractAddress, ignoreCase = true) && amountToken.symbol.equals(feeToken.symbol, ignoreCase = true) } + + private fun getInteractionAddressType( + value: TransactionData.Uncompiled, + isOutgoing: Boolean, + ): TxInfo.InteractionAddressType = when (val extras = value.extras) { + is EthereumTransactionExtras -> { + when (val callData = extras.callData) { + is ApprovalERC20TokenCallData -> TxInfo.InteractionAddressType.Contract( + address = callData.spenderAddress, + ) + else -> TxInfo.InteractionAddressType.User( + address = if (isOutgoing) value.destinationAddress else value.sourceAddress, + ) + } + } + else -> TxInfo.InteractionAddressType.User( + address = if (isOutgoing) value.destinationAddress else value.sourceAddress, + ) + } + + private fun getTransactionType(extras: TransactionExtras?): TxInfo.TransactionType { + return when (extras) { + is EthereumTransactionExtras -> { + when (extras.callData) { + is EthereumYieldSupplyDeployCallData, + is EthereumYieldSupplyReactivateTokenCallData, + is EthereumYieldSupplyInitTokenCallData, + is EthereumYieldSupplyEnterCallData, + -> TxInfo.TransactionType.YieldSupply.Enter + is EthereumYieldSupplyExitCallData -> TxInfo.TransactionType.YieldSupply.Exit + is ApprovalERC20TokenCallData -> TxInfo.TransactionType.Approve + else -> TxInfo.TransactionType.Transfer + } + } + else -> TxInfo.TransactionType.Transfer + } + } } \ No newline at end of file diff --git a/data/yield-supply/build.gradle.kts b/data/yield-supply/build.gradle.kts index 73b4ac8ab2..b53babcf05 100644 --- a/data/yield-supply/build.gradle.kts +++ b/data/yield-supply/build.gradle.kts @@ -28,6 +28,7 @@ dependencies { implementation(projects.domain.yieldSupply.models) implementation(projects.domain.walletManager) implementation(projects.domain.legacy) + implementation(projects.domain.txhistory.models) implementation(projects.libs.blockchainSdk) diff --git a/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt b/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt index cdc6d867fc..48badf6ec8 100644 --- a/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt +++ b/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyRepository.kt @@ -12,6 +12,8 @@ import com.tangem.datasource.api.tangemTech.YieldSupplyApi import com.tangem.datasource.api.tangemTech.models.YieldSupplyChangeTokenStatusBody import com.tangem.datasource.local.yieldsupply.YieldMarketsStore import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.domain.models.network.TxInfo import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.yield.supply.YieldSupplyRepository @@ -109,16 +111,21 @@ internal class DefaultYieldSupplyRepository( override suspend fun saveTokenProtocolStatus( userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency, - yieldSupplyEnterStatus: YieldSupplyEnterStatus, + yieldSupplyEnterStatus: YieldSupplyEnterStatus?, ) { - statusMap["${userWalletId}_${cryptoCurrency.id.value}"] = yieldSupplyEnterStatus + val key = getTokenProtocolStatusKey(userWalletId, cryptoCurrency) + if (yieldSupplyEnterStatus != null) { + statusMap[key] = yieldSupplyEnterStatus + } else { + statusMap.remove(key) + } } override fun getTokenProtocolStatus( userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency, ): YieldSupplyEnterStatus? { - return statusMap["${userWalletId}_${cryptoCurrency.id.value}"] + return statusMap[getTokenProtocolStatusKey(userWalletId, cryptoCurrency)] } private fun List.enrichNetworkIds(): List { @@ -127,4 +134,41 @@ internal class DefaultYieldSupplyRepository( token.copy(backendId = chainIdMap[token.chainId]) } } + + override suspend fun getTokenPendingStatus( + userWalletId: UserWalletId, + cryptoCurrencyStatus: CryptoCurrencyStatus, + ): YieldSupplyEnterStatus? { + val cryptoCurrency = cryptoCurrencyStatus.currency + val walletManager = walletManagersFacade.getOrCreateWalletManager( + userWalletId = userWalletId, + blockchain = cryptoCurrency.network.toBlockchain(), + derivationPath = cryptoCurrency.network.derivationPath.value, + ) ?: error("Wallet manager not found") + + val pendingTxs = cryptoCurrencyStatus.value.pendingTransactions + + val yieldAddress = walletManager.calculateYieldModuleAddress() + val hasRecentYieldEnterTxs = pendingTxs.hasYieldEnterTransactions(yieldAddress) + val hasRecentYieldExitTxs = pendingTxs.hasYieldExitTransactions() + + return when { + hasRecentYieldEnterTxs -> YieldSupplyEnterStatus.Enter + hasRecentYieldExitTxs -> YieldSupplyEnterStatus.Exit + else -> null + } + } + + private fun Set.hasYieldEnterTransactions(yieldAddress: String) = any { + it.type == TxInfo.TransactionType.YieldSupply.Enter || + it.type == TxInfo.TransactionType.Approve && + (it.interactionAddressType as? TxInfo.InteractionAddressType.Contract)?.address == yieldAddress + } + + private fun Set.hasYieldExitTransactions() = any { + it.type == TxInfo.TransactionType.YieldSupply.Exit + } + + private fun getTokenProtocolStatusKey(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): String = + "${userWalletId}_${cryptoCurrency.id.value}" } \ No newline at end of file diff --git a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyRepository.kt b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyRepository.kt index 7fbbc6d543..8ab13bbac1 100644 --- a/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyRepository.kt +++ b/domain/yield-supply/src/main/java/com/tangem/domain/yield/supply/YieldSupplyRepository.kt @@ -1,6 +1,7 @@ package com.tangem.domain.yield.supply import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.yield.supply.models.YieldMarketToken import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus @@ -76,7 +77,7 @@ interface YieldSupplyRepository { suspend fun saveTokenProtocolStatus( userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency, - yieldSupplyEnterStatus: YieldSupplyEnterStatus, + yieldSupplyEnterStatus: YieldSupplyEnterStatus?, ) /** @@ -91,4 +92,20 @@ interface YieldSupplyRepository { * @return the last action intent or null if nothing has been recorded */ fun getTokenProtocolStatus(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): YieldSupplyEnterStatus? + + /** + * Get the pending status of the yield protocol action for the given wallet and currency, if any. + * + * Used to determine whether the UI should display an intermediate "processing" state + * until the protocol status retrieved from backend reflects the change. The value is + * transient (in‑memory only) and is not persisted across app restarts. + * + * @param userWalletId the wallet to query + * @param cryptoCurrencyStatus the currency status to query + * @return the pending action intent or null if nothing has been recorded + */ + suspend fun getTokenPendingStatus( + userWalletId: UserWalletId, + cryptoCurrencyStatus: CryptoCurrencyStatus, + ): YieldSupplyEnterStatus? } \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt index 4ae0cf1e53..d83e344df8 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt @@ -35,9 +35,9 @@ import com.tangem.features.yield.supply.impl.main.entity.YieldSupplyUM import com.tangem.features.yield.supply.impl.main.model.transformers.YieldSupplyTokenStatusSuccessTransformer import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.DelayedWork -import com.tangem.utils.transformer.update import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn +import com.tangem.utils.transformer.update import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* @@ -193,42 +193,54 @@ internal class YieldSupplyModel @Inject constructor( } @Suppress("MaximumLineLength") - private fun onCryptoCurrencyStatusUpdated(cryptoCurrencyStatus: CryptoCurrencyStatus) { + private fun onCryptoCurrencyStatusUpdated(cryptoCurrencyStatus: CryptoCurrencyStatus) = modelScope.launch { val yieldSupplyStatus = cryptoCurrencyStatus.value.yieldSupplyStatus val tokenProtocolStatus = yieldSupplyRepository.getTokenProtocolStatus( userWallet.walletId, cryptoCurrency, ) + val tokenPendingStatus = yieldSupplyRepository.getTokenPendingStatus( + userWallet.walletId, + cryptoCurrencyStatus, + ) + val isActive = yieldSupplyStatus?.isActive == true val isCryptoCurrencyStatusFromCache = cryptoCurrencyStatus.value.sources.networkSource != StatusSource.ACTUAL val processing = uiState.value is YieldSupplyUM.Processing Timber.d( - "currentUiState ${uiState.value.javaClass} \n" + - "yieldSupplyStatus $yieldSupplyStatus" + + "YIELD " + + "yieldSupplyStatus $yieldSupplyStatus " + "tokenProtocolStatus $tokenProtocolStatus " + + "tokenPendingStatus $tokenPendingStatus " + "isActive $isActive " + "processing $processing " + "isCryptoCurrencyStatusFromCache $isCryptoCurrencyStatusFromCache", ) if (isCryptoCurrencyStatusFromCache && processing) { - return + return@launch } when { - !isActive && tokenProtocolStatus == YieldSupplyEnterStatus.Enter -> { - uiState.update { YieldSupplyUM.Processing.Enter } - fetchCurrencyWithDelay() - } - isActive && tokenProtocolStatus == YieldSupplyEnterStatus.Exit -> { - uiState.update { YieldSupplyUM.Processing.Exit } + tokenProtocolStatus != null && tokenPendingStatus != null -> { + uiState.update { + when (tokenPendingStatus) { + YieldSupplyEnterStatus.Enter -> YieldSupplyUM.Processing.Enter + YieldSupplyEnterStatus.Exit -> YieldSupplyUM.Processing.Exit + } + } fetchCurrencyWithDelay() } else -> { + yieldSupplyRepository.saveTokenProtocolStatus( + userWalletId = userWallet.walletId, + cryptoCurrency = cryptoCurrency, + yieldSupplyEnterStatus = null, + ) sendInfoAboutProtocolStatus(cryptoCurrencyStatus) if (isActive) { loadActiveState( cryptoCurrencyStatus = cryptoCurrencyStatus, - yieldSupplyStatus = requireNotNull(yieldSupplyStatus), + yieldSupplyStatus = yieldSupplyStatus, ) } else { loadTokenStatus() diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 852b769c33..4e7835869e 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,7 +5,7 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.30-1299" +tangemBlockchainSdk = "releases-5.30-1305" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "releases-5.30-567" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^