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 6d1b520c2f..5701b7eb2e 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,6 +1,10 @@ package com.tangem.data.walletmanager.utils +import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras 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.blockchainsdk.models.UpdateWalletManagerResult.Address import com.tangem.domain.models.network.TxInfo import com.tangem.utils.converter.Converter @@ -40,7 +44,18 @@ internal class TransactionDataToTxHistoryItemConverter( TransactionStatus.Confirmed -> TxInfo.TransactionStatus.Confirmed TransactionStatus.Unconfirmed -> TxInfo.TransactionStatus.Unconfirmed }, - type = TxInfo.TransactionType.Transfer, + 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 + }, amount = amount, ) } diff --git a/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyTransactionRepository.kt b/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyTransactionRepository.kt index d2f3ce9120..f9767b60f8 100644 --- a/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyTransactionRepository.kt +++ b/data/yield-supply/src/main/java/com/tangem/data/yield/supply/DefaultYieldSupplyTransactionRepository.kt @@ -12,6 +12,7 @@ import com.tangem.blockchainsdk.utils.toBlockchain 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.models.yield.supply.YieldSupplyStatus import com.tangem.domain.utils.convertToSdkAmount import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.yield.supply.YieldSupplyTransactionRepository @@ -56,7 +57,7 @@ internal class DefaultYieldSupplyTransactionRepository( return buildEnterTransactions( walletManager = walletManager, cryptoCurrencyStatus = cryptoCurrencyStatus, - existingYieldContractAddress = existingYieldContractAddress, + existingYieldAddress = existingYieldContractAddress, calculatedYieldContractAddress = calculatedYieldContractAddress, maxNetworkFee = maxNetworkFee, ) @@ -109,21 +110,23 @@ internal class DefaultYieldSupplyTransactionRepository( } @Suppress("LongParameterList") - private fun buildEnterTransactions( + private suspend fun buildEnterTransactions( walletManager: WalletManager, cryptoCurrencyStatus: CryptoCurrencyStatus, - existingYieldContractAddress: String?, + existingYieldAddress: String?, calculatedYieldContractAddress: String, maxNetworkFee: Amount, ): MutableList { val enterTransactions = mutableListOf() val cryptoCurrency = cryptoCurrencyStatus.currency as CryptoCurrency.Token - val yieldSupplyStatus = cryptoCurrencyStatus.value.yieldSupplyStatus + val yieldSupplyStatus = getYieldTokenStatus(walletManager, cryptoCurrency) - val amount = BigDecimal.ZERO.convertToSdkAmount(cryptoCurrencyStatus) + val amount = getEnterAmount(cryptoCurrency, yieldSupplyStatus) + + val emptyContractAddress = existingYieldAddress == null || existingYieldAddress == EthereumUtils.ZERO_ADDRESS when { - existingYieldContractAddress == null || existingYieldContractAddress == EthereumUtils.ZERO_ADDRESS -> { + yieldSupplyStatus == null || emptyContractAddress -> { enterTransactions.add( createDeployTransaction( walletManager = walletManager, @@ -133,7 +136,6 @@ internal class DefaultYieldSupplyTransactionRepository( ), ) } - yieldSupplyStatus == null -> error("Yield token status is null") !yieldSupplyStatus.isInitialized -> enterTransactions.add( createInitTokenTransaction( walletManager = walletManager, @@ -211,6 +213,28 @@ internal class DefaultYieldSupplyTransactionRepository( }.onFailure(Timber::e).getOrNull() } + private suspend fun getYieldTokenStatus( + walletManager: WalletManager, + cryptoCurrency: CryptoCurrency.Token, + ): YieldSupplyStatus? = withContext(dispatchers.io) { + runCatching { + val sdkSupplyStatus = walletManager.getYieldSupplyStatus(cryptoCurrency.contractAddress) + val isAllowedToSpend = walletManager.isAllowedToSpend( + Token( + symbol = cryptoCurrency.symbol, + contractAddress = cryptoCurrency.contractAddress, + decimals = cryptoCurrency.decimals, + ), + ) + + YieldSupplyStatus( + isActive = sdkSupplyStatus?.isActive == true, + isInitialized = sdkSupplyStatus?.isInitialized == true, + isAllowedToSpend = isAllowedToSpend, + ) + }.onFailure(Timber::e).getOrNull() + } + private fun createDeployTransaction( walletManager: WalletManager, cryptoCurrency: CryptoCurrency.Token, @@ -356,4 +380,20 @@ internal class DefaultYieldSupplyTransactionRepository( else -> error("Data extras not supported for $blockchain") } } + + private fun getEnterAmount(cryptoCurrency: CryptoCurrency.Token, yieldSupplyStatus: YieldSupplyStatus?) = Amount( + currencySymbol = cryptoCurrency.symbol, + value = BigDecimal.ZERO, + decimals = cryptoCurrency.decimals, + type = AmountType.TokenYieldSupply( + token = Token( + symbol = cryptoCurrency.symbol, + contractAddress = cryptoCurrency.contractAddress, + decimals = cryptoCurrency.decimals, + ), + isActive = yieldSupplyStatus?.isActive ?: false, + isInitialized = yieldSupplyStatus?.isInitialized ?: false, + isAllowedToSpend = yieldSupplyStatus?.isAllowedToSpend ?: false, + ), + ) } \ No newline at end of file diff --git a/data/yield-supply/src/test/java/com/tangem/data/yield/supply/DefaultYieldSupplyTransactionRepositoryTest.kt b/data/yield-supply/src/test/java/com/tangem/data/yield/supply/DefaultYieldSupplyTransactionRepositoryTest.kt index 7421ab8399..3dc4924651 100644 --- a/data/yield-supply/src/test/java/com/tangem/data/yield/supply/DefaultYieldSupplyTransactionRepositoryTest.kt +++ b/data/yield-supply/src/test/java/com/tangem/data/yield/supply/DefaultYieldSupplyTransactionRepositoryTest.kt @@ -12,7 +12,6 @@ import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.network.Network import com.tangem.domain.models.wallet.UserWalletId -import com.tangem.domain.models.yield.supply.YieldSupplyStatus import com.tangem.domain.utils.convertToSdkAmount import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider @@ -69,10 +68,10 @@ class DefaultYieldSupplyTransactionRepositoryTest { @Test fun `createEnterTransactions returns deploy-approve-enter transactions`() = runTest { - coEvery { walletManager.getYieldContract() } returns EthereumUtils.ZERO_ADDRESS + coEvery { walletManager.getYieldModuleAddress() } returns EthereumUtils.ZERO_ADDRESS coEvery { walletManager.getYieldSupplyStatus(any()) } returns null coEvery { walletManager.isAllowedToSpend(any()) } returns false - coEvery { walletManager.calculateYieldContract() } returns yieldContractAddress + coEvery { walletManager.calculateYieldModuleAddress() } returns yieldContractAddress val result = repository.createEnterTransactions( userWalletId = userWalletId, @@ -119,8 +118,8 @@ class DefaultYieldSupplyTransactionRepositoryTest { @Test fun `createEnterTransactions returns init-approve-enter transactions`() = runTest { - coEvery { walletManager.getYieldContract() } returns yieldContractAddress - coEvery { walletManager.calculateYieldContract() } returns yieldContractAddress + coEvery { walletManager.getYieldModuleAddress() } returns yieldContractAddress + coEvery { walletManager.calculateYieldModuleAddress() } returns yieldContractAddress coEvery { walletManager.isAllowedToSpend(any()) } returns false coEvery { walletManager.getYieldSupplyStatus(any()) } returns SDKYieldSupplyStatus( isActive = false, @@ -172,8 +171,8 @@ class DefaultYieldSupplyTransactionRepositoryTest { @Test fun `createEnterTransactions returns reactivate-approve-enter transactions`() = runTest { - coEvery { walletManager.getYieldContract() } returns yieldContractAddress - coEvery { walletManager.calculateYieldContract() } returns yieldContractAddress + coEvery { walletManager.getYieldModuleAddress() } returns yieldContractAddress + coEvery { walletManager.calculateYieldModuleAddress() } returns yieldContractAddress coEvery { walletManager.isAllowedToSpend(any()) } returns false coEvery { walletManager.getYieldSupplyStatus(any()) } returns SDKYieldSupplyStatus( isActive = false, @@ -225,8 +224,8 @@ class DefaultYieldSupplyTransactionRepositoryTest { @Test fun `createEnterTransactions returns reactivate-enter transactions`() = runTest { - coEvery { walletManager.getYieldContract() } returns yieldContractAddress - coEvery { walletManager.calculateYieldContract() } returns yieldContractAddress + coEvery { walletManager.getYieldModuleAddress() } returns yieldContractAddress + coEvery { walletManager.calculateYieldModuleAddress() } returns yieldContractAddress coEvery { walletManager.getYieldSupplyStatus(any()) } returns SDKYieldSupplyStatus( isActive = false, isInitialized = true, @@ -266,8 +265,8 @@ class DefaultYieldSupplyTransactionRepositoryTest { @Test fun `createEnterTransactions returns enter transactions`() = runTest { - coEvery { walletManager.getYieldContract() } returns yieldContractAddress - coEvery { walletManager.calculateYieldContract() } returns yieldContractAddress + coEvery { walletManager.getYieldModuleAddress() } returns yieldContractAddress + coEvery { walletManager.calculateYieldModuleAddress() } returns yieldContractAddress coEvery { walletManager.getYieldSupplyStatus(any()) } returns SDKYieldSupplyStatus( isActive = true, isInitialized = true, @@ -299,9 +298,7 @@ class DefaultYieldSupplyTransactionRepositoryTest { val expectedCallData = YieldSupplyContractCallDataProviderFactory.getExitCallData(mockedContractAddress) - val yieldSupplyStatus = mockk(relaxed = true) - - val result = repository.createExitTransaction(userWalletId, cryptoCurrency, yieldSupplyStatus, null) + val result = repository.createExitTransaction(userWalletId, cryptoCurrencyStatus, null) Truth.assertThat(result).isNotNull() Truth.assertThat(result.extras).isInstanceOf(EthereumTransactionExtras::class.java) diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt index d5bb077099..ed13b42827 100644 --- a/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/network/TxInfo.kt @@ -107,6 +107,16 @@ data class TxInfo( @Serializable data class Operation(val name: String) : TransactionType + @Serializable + sealed interface YieldSupply : TransactionType { + + @Serializable + data object Enter : YieldSupply + + @Serializable + data object Exit : YieldSupply + } + @Serializable sealed interface Staking : TransactionType { diff --git a/features/kyc/mock/src/main/kotlin/com/tangem/features/kyc/MockKycComponent.kt b/features/kyc/mock/src/main/kotlin/com/tangem/features/kyc/MockKycComponent.kt index 7119fdd452..7002216067 100644 --- a/features/kyc/mock/src/main/kotlin/com/tangem/features/kyc/MockKycComponent.kt +++ b/features/kyc/mock/src/main/kotlin/com/tangem/features/kyc/MockKycComponent.kt @@ -1,11 +1,11 @@ package com.tangem.features.kyc import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import com.tangem.core.decompose.context.AppComponentContext import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import androidx.compose.ui.Modifier /** * Mocking it for release/external builds to exclude SumSub dependency diff --git a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt index 4b0fb801b0..f18879a60a 100644 --- a/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt +++ b/features/txhistory/impl/src/main/kotlin/com/tangem/features/txhistory/converter/TxHistoryItemToTransactionStateConverter.kt @@ -53,6 +53,7 @@ internal class TxHistoryItemToTransactionStateConverter( is TxInfo.TransactionType.Operation, is TxInfo.TransactionType.Swap, is TxInfo.TransactionType.Transfer, + is TxInfo.TransactionType.YieldSupply, is TxInfo.TransactionType.UnknownOperation, -> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24 } @@ -62,7 +63,9 @@ internal class TxHistoryItemToTransactionStateConverter( is TxInfo.TransactionType.Approve -> resourceReference(R.string.common_approval) is TxInfo.TransactionType.Operation -> stringReference(type.name) is TxInfo.TransactionType.Swap -> resourceReference(R.string.common_swap) - is TxInfo.TransactionType.Transfer -> resourceReference(R.string.common_transfer) + is TxInfo.TransactionType.YieldSupply, + is TxInfo.TransactionType.Transfer, + -> resourceReference(R.string.common_transfer) is TxInfo.TransactionType.Staking.Stake -> resourceReference(R.string.common_stake) is TxInfo.TransactionType.Staking.Unstake -> resourceReference(R.string.common_unstake) is TxInfo.TransactionType.Staking.Vote -> resourceReference(R.string.staking_vote) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt index 23364277ba..5db8fb0058 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TxHistoryItemStateConverter.kt @@ -61,6 +61,7 @@ internal class TxHistoryItemStateConverter( is TransactionType.Operation, is TransactionType.Swap, is TransactionType.Transfer, + is TransactionType.YieldSupply, is TransactionType.UnknownOperation, -> if (isOutgoing) R.drawable.ic_arrow_up_24 else R.drawable.ic_arrow_down_24 } @@ -70,7 +71,9 @@ internal class TxHistoryItemStateConverter( is TransactionType.Approve -> resourceReference(R.string.common_approval) is TransactionType.Operation -> stringReference(type.name) is TransactionType.Swap -> resourceReference(R.string.common_swap) - is TransactionType.Transfer -> resourceReference(R.string.common_transfer) + is TransactionType.YieldSupply, + is TransactionType.Transfer, + -> resourceReference(R.string.common_transfer) is TransactionType.Staking.Stake -> resourceReference(R.string.common_stake) is TransactionType.Staking.Unstake -> resourceReference(R.string.common_unstake) is TransactionType.Staking.Vote -> resourceReference(R.string.staking_vote) diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/YieldSupplyFeeUM.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/YieldSupplyFeeUM.kt index 2809ea5cb4..14baa04a9a 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/YieldSupplyFeeUM.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/YieldSupplyFeeUM.kt @@ -26,4 +26,5 @@ internal data class YieldSupplyActionUM( val currencyIconState: CurrencyIconState, val yieldSupplyFeeUM: YieldSupplyFeeUM, val isPrimaryButtonEnabled: Boolean, + val isTransactionSending: Boolean, ) \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/transformer/YieldSupplyTransactionInProgressTransformer.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/transformer/YieldSupplyTransactionInProgressTransformer.kt new file mode 100644 index 0000000000..0940c5be50 --- /dev/null +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/transformer/YieldSupplyTransactionInProgressTransformer.kt @@ -0,0 +1,13 @@ +package com.tangem.features.yield.supply.impl.common.entity.transformer + +import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM +import com.tangem.utils.transformer.Transformer + +internal object YieldSupplyTransactionInProgressTransformer : Transformer { + override fun transform(prevState: YieldSupplyActionUM): YieldSupplyActionUM { + return prevState.copy( + isPrimaryButtonEnabled = false, + isTransactionSending = true, + ) + } +} \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/transformer/YieldSupplyTransactionReadyTransformer.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/transformer/YieldSupplyTransactionReadyTransformer.kt new file mode 100644 index 0000000000..9652d1abd0 --- /dev/null +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/entity/transformer/YieldSupplyTransactionReadyTransformer.kt @@ -0,0 +1,13 @@ +package com.tangem.features.yield.supply.impl.common.entity.transformer + +import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM +import com.tangem.utils.transformer.Transformer + +internal object YieldSupplyTransactionReadyTransformer : Transformer { + override fun transform(prevState: YieldSupplyActionUM): YieldSupplyActionUM { + return prevState.copy( + isPrimaryButtonEnabled = true, + isTransactionSending = false, + ) + } +} \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyActionContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyActionContent.kt index abdd18d4dc..aea87550b9 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyActionContent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/common/ui/YieldSupplyActionContent.kt @@ -143,6 +143,7 @@ private class YieldSupplyActionContentPreviewProvider : PreviewParameterProvider maxNetworkFeeValue = stringReference("8.50 USDT • \$8.50"), ), isPrimaryButtonEnabled = false, + isTransactionSending = false, ), ) } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/entity/YieldSupplyUM.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/entity/YieldSupplyUM.kt index 1ea3ceddd4..7b0eff85c3 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/entity/YieldSupplyUM.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/entity/YieldSupplyUM.kt @@ -20,5 +20,9 @@ internal sealed class YieldSupplyUM { val isAllowedToSpend: Boolean, ) : YieldSupplyUM() - data object Processing : YieldSupplyUM() + @Immutable + sealed class Processing : YieldSupplyUM() { + data object Enter : Processing() + data object Exit : Processing() + } } \ 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 e8cab11656..6cfca46b35 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 @@ -11,19 +11,25 @@ import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.domain.models.currency.CryptoCurrencyStatus +import com.tangem.domain.models.network.TxInfo import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.tokens.FetchCurrencyStatusUseCase import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.features.yield.supply.api.YieldSupplyComponent import com.tangem.features.yield.supply.impl.R import com.tangem.features.yield.supply.impl.main.entity.YieldSupplyUM import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.coroutines.DelayedWork +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject import kotlin.properties.Delegates +@Suppress("LongParameterList") @ModelScoped internal class YieldSupplyModel @Inject constructor( paramsContainer: ParamsContainer, @@ -31,6 +37,8 @@ internal class YieldSupplyModel @Inject constructor( private val appRouter: AppRouter, private val getUserWalletUseCase: GetUserWalletUseCase, private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase, + private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase, + @DelayedWork private val coroutineScope: CoroutineScope, ) : Model(), YieldSupplyClickIntents { private val params = paramsContainer.require() @@ -100,9 +108,22 @@ internal class YieldSupplyModel @Inject constructor( private fun onDataLoaded(cryptoCurrencyStatus: CryptoCurrencyStatus) { val yieldSupplyStatus = cryptoCurrencyStatus.value.yieldSupplyStatus + val hasActiveTransaction = cryptoCurrencyStatus.value.hasCurrentNetworkTransactions + val yieldTransaction = cryptoCurrencyStatus.value.pendingTransactions.firstOrNull { + it.type is TxInfo.TransactionType.YieldSupply + }?.type as? TxInfo.TransactionType.YieldSupply - // todo yield supply add processing state val yieldSupplyUM = when { + hasActiveTransaction && yieldTransaction != null -> { + coroutineScope.launch(dispatchers.io) { + delay(PROCESSING_UPDATE_DELAY) + fetchCurrencyStatusUseCase(userWalletId = userWallet.walletId, cryptoCurrency.id) + } + when (yieldTransaction) { + TxInfo.TransactionType.YieldSupply.Enter -> YieldSupplyUM.Processing.Enter + TxInfo.TransactionType.YieldSupply.Exit -> YieldSupplyUM.Processing.Exit + } + } yieldSupplyStatus?.isActive == true -> YieldSupplyUM.Content( rewardsBalance = TextReference.EMPTY, @@ -121,4 +142,8 @@ internal class YieldSupplyModel @Inject constructor( uiState.update { yieldSupplyUM } } + + private companion object { + const val PROCESSING_UPDATE_DELAY = 10_000L + } } \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt index 7930a4eb89..3e8921209e 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/ui/YieldSupplyBlockContent.kt @@ -42,7 +42,12 @@ internal fun YieldSupplyBlockContent(yieldSupplyUM: YieldSupplyUM, modifier: Mod is YieldSupplyUM.Initial -> SupplyInitial(supplyUM) YieldSupplyUM.Loading -> SupplyLoading() is YieldSupplyUM.Content -> SupplyContent(supplyUM) - YieldSupplyUM.Processing -> SupplyProcessing() + YieldSupplyUM.Processing.Enter -> SupplyProcessing( + resourceReference(R.string.yield_module_token_details_earn_notification_processing), + ) + YieldSupplyUM.Processing.Exit -> SupplyProcessing( + resourceReference(R.string.yield_module_stop_earning), + ) } } } @@ -153,7 +158,7 @@ private fun SupplyContent(supplyUM: YieldSupplyUM.Content) { } @Composable -private fun SupplyProcessing() { +private fun SupplyProcessing(text: TextReference) { Column( verticalArrangement = Arrangement.spacedBy(4.dp), modifier = Modifier @@ -174,9 +179,7 @@ private fun SupplyProcessing() { horizontalArrangement = Arrangement.spacedBy(4.dp), ) { Text( - text = stringResourceSafe( - R.string.yield_module_token_details_earn_notification_processing, - ), + text = text.resolveReference(), style = TangemTheme.typography.body1, color = TangemTheme.colors.text.tertiary, ) @@ -248,7 +251,8 @@ private class PreviewProvider : PreviewParameterProvider { isAllowedToSpend = true, ), YieldSupplyUM.Loading, - YieldSupplyUM.Processing, + YieldSupplyUM.Processing.Enter, + YieldSupplyUM.Processing.Exit, ) } // endregion \ No newline at end of file diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt index 8d4982553f..0385e90b11 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt @@ -22,12 +22,15 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyGetContractAddressUseCa import com.tangem.features.yield.supply.impl.R import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM +import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionInProgressTransformer +import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionReadyTransformer import com.tangem.features.yield.supply.impl.subcomponents.approve.YieldSupplyApproveComponent import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsComponent import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsUpdateTrigger import com.tangem.features.yield.supply.impl.subcomponents.notifications.entity.YieldSupplyNotificationData import com.tangem.utils.StringsSigns.DOT import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import com.tangem.utils.transformer.update import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch @@ -82,6 +85,7 @@ internal class YieldSupplyApproveModel @Inject constructor( currencyIconState = CryptoCurrencyToIconStateConverter().convert(cryptoCurrency), yieldSupplyFeeUM = YieldSupplyFeeUM.Loading, isPrimaryButtonEnabled = false, + isTransactionSending = false, ), ) @@ -105,7 +109,7 @@ internal class YieldSupplyApproveModel @Inject constructor( fun onClick() { val yieldSupplyFeeUM = uiState.value.yieldSupplyFeeUM as? YieldSupplyFeeUM.Content ?: return - uiState.update { it.copy(isPrimaryButtonEnabled = false) } + uiState.update(YieldSupplyTransactionInProgressTransformer) modelScope.launch(dispatchers.default) { sendTransactionUseCase( @@ -115,6 +119,7 @@ internal class YieldSupplyApproveModel @Inject constructor( ).fold( ifLeft = { Timber.e(it.toString()) + uiState.update(YieldSupplyTransactionReadyTransformer) }, ifRight = { params.callback.onTransactionSent() @@ -136,7 +141,7 @@ internal class YieldSupplyApproveModel @Inject constructor( } private suspend fun onLoadFee() { - if (cryptoCurrency !is CryptoCurrency.Token) return + if (cryptoCurrency !is CryptoCurrency.Token || uiState.value.isTransactionSending) return val contractAddress = yieldSupplyGetContractAddressUseCase.invoke( userWalletId = userWallet.walletId, diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningEntryModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningEntryModel.kt index 1a9817b7af..b2b2db7f41 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningEntryModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningEntryModel.kt @@ -42,6 +42,7 @@ internal class YieldSupplyStartEarningEntryModel @Inject constructor( currencyIconState = CryptoCurrencyToIconStateConverter().convert(params.cryptoCurrency), yieldSupplyFeeUM = YieldSupplyFeeUM.Loading, isPrimaryButtonEnabled = false, + isTransactionSending = false, ), ) diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt index b32de495c6..a675b829ae 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt @@ -12,6 +12,7 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.tokens.FetchCurrencyStatusUseCase import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase import com.tangem.domain.transaction.usecase.SendTransactionUseCase @@ -21,6 +22,8 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyStartEarningUseCase import com.tangem.features.yield.supply.impl.R import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM +import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionInProgressTransformer +import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionReadyTransformer import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsComponent import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsUpdateTrigger import com.tangem.features.yield.supply.impl.subcomponents.notifications.entity.YieldSupplyNotificationData @@ -49,6 +52,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor( private val yieldSupplyEstimateEnterFeeUseCase: YieldSupplyEstimateEnterFeeUseCase, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val yieldSupplyNotificationsUpdateTrigger: YieldSupplyNotificationsUpdateTrigger, + private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase, ) : Model(), YieldSupplyNotificationsComponent.ModelCallback { private val params: YieldSupplyStartEarningComponent.Params = paramsContainer.require() @@ -84,6 +88,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor( currencyIconState = CryptoCurrencyToIconStateConverter().convert(params.cryptoCurrency), yieldSupplyFeeUM = YieldSupplyFeeUM.Loading, isPrimaryButtonEnabled = false, + isTransactionSending = false, ), ) @@ -100,7 +105,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor( } private suspend fun onLoadFee() { - if (cryptoCurrencyStatus.value is CryptoCurrencyStatus.Loading) return + if (cryptoCurrencyStatus.value is CryptoCurrencyStatus.Loading || uiState.value.isTransactionSending) return val transactionListData = yieldSupplyStartEarningUseCase( userWalletId = userWallet.walletId, @@ -155,7 +160,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor( fun onClick() { val yieldSupplyFeeUM = uiState.value.yieldSupplyFeeUM as? YieldSupplyFeeUM.Content ?: return - uiState.update { it.copy(isPrimaryButtonEnabled = false) } + uiState.update(YieldSupplyTransactionInProgressTransformer) modelScope.launch(dispatchers.default) { sendTransactionUseCase.invoke( txsData = yieldSupplyFeeUM.transactionDataList, @@ -163,11 +168,12 @@ internal class YieldSupplyStartEarningModel @Inject constructor( network = cryptoCurrency.network, sendMode = TransactionSender.MultipleTransactionSendMode.DEFAULT, ).fold( - ifLeft = { - Timber.e(it.toString()) - uiState.update { it.copy(isPrimaryButtonEnabled = true) } + ifLeft = { error -> + Timber.e(error.toString()) + uiState.update(YieldSupplyTransactionReadyTransformer) }, ifRight = { + fetchCurrencyStatusUseCase(userWalletId = userWallet.walletId, cryptoCurrency.id) modelScope.launch { params.callback.onTransactionSent() } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt index 28e269b07e..dc462586ca 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt @@ -10,6 +10,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase import com.tangem.domain.transaction.usecase.GetFeeUseCase @@ -18,6 +19,8 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyStopEarningUseCase import com.tangem.features.yield.supply.impl.R import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM +import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionInProgressTransformer +import com.tangem.features.yield.supply.impl.common.entity.transformer.YieldSupplyTransactionReadyTransformer import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsComponent import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsUpdateTrigger import com.tangem.features.yield.supply.impl.subcomponents.notifications.entity.YieldSupplyNotificationData @@ -78,6 +81,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor( currencyIconState = CryptoCurrencyToIconStateConverter().convert(cryptoCurrency), yieldSupplyFeeUM = YieldSupplyFeeUM.Loading, isPrimaryButtonEnabled = false, + isTransactionSending = false, ), ) @@ -101,7 +105,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor( fun onClick() { val yieldSupplyFeeUM = uiState.value.yieldSupplyFeeUM as? YieldSupplyFeeUM.Content ?: return - uiState.update { it.copy(isPrimaryButtonEnabled = false) } + uiState.update(YieldSupplyTransactionInProgressTransformer) modelScope.launch(dispatchers.default) { sendTransactionUseCase( @@ -111,6 +115,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor( ).fold( ifLeft = { Timber.e(it.toString()) + uiState.update(YieldSupplyTransactionReadyTransformer) }, ifRight = { params.callback.onTransactionSent() @@ -132,6 +137,8 @@ internal class YieldSupplyStopEarningModel @Inject constructor( } private suspend fun onLoadFee() { + if (cryptoCurrency !is CryptoCurrency.Token || uiState.value.isTransactionSending) return + val exitTransitionData = yieldSupplyStopEarningUseCase( userWalletId = userWallet.walletId, cryptoCurrencyStatus = cryptoCurrencyStatus, diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 718aa1fa53..7db050e5c3 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 = "develop-1245" +tangemBlockchainSdk = "develop-1246" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "develop-564" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^