From 57ec369ab04deb97c87423c3ed5ea31f016c4fc3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 5 May 2025 12:43:58 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../tap/di/domain/TransactionDomainModule.kt | 9 -- .../DefaultTransactionRepository.kt | 35 ++++-- .../transaction/TransactionRepository.kt | 2 +- .../CreateTransferTransactionUseCase.kt | 21 ++++ .../usecase/GetTransferFeeUseCase.kt | 102 ------------------ .../v2/send/confirm/model/SendConfirmModel.kt | 6 +- .../features/send/v2/send/model/SendModel.kt | 26 +++-- .../send/impl/presentation/model/SendModel.kt | 21 +++- 8 files changed, 86 insertions(+), 136 deletions(-) delete mode 100644 domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/GetTransferFeeUseCase.kt diff --git a/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt index 77c2518104..b0b9e8f8ad 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/TransactionDomainModule.kt @@ -36,15 +36,6 @@ internal object TransactionDomainModule { return GetEthSpecificFeeUseCase(walletManagersFacade = walletManagersFacade) } - @Provides - @Singleton - fun provideTransferGetFeeUseCase(walletManagersFacade: WalletManagersFacade): GetTransferFeeUseCase { - return GetTransferFeeUseCase( - walletManagersFacade = walletManagersFacade, - demoConfig = DemoConfig(), - ) - } - @Provides @Singleton fun provideSendTransactionUseCase( diff --git a/data/transaction/src/main/java/com/tangem/data/transaction/DefaultTransactionRepository.kt b/data/transaction/src/main/java/com/tangem/data/transaction/DefaultTransactionRepository.kt index e76e34479a..6ba07ef2e1 100644 --- a/data/transaction/src/main/java/com/tangem/data/transaction/DefaultTransactionRepository.kt +++ b/data/transaction/src/main/java/com/tangem/data/transaction/DefaultTransactionRepository.kt @@ -77,13 +77,18 @@ internal class DefaultTransactionRepository( override suspend fun createTransferTransaction( amount: Amount, - fee: Fee, + fee: Fee?, memo: String?, destination: String, userWalletId: UserWalletId, network: Network, ): TransactionData.Uncompiled = withContext(coroutineDispatcherProvider.io) { val blockchain = Blockchain.fromId(network.id.value) + val walletManager = walletManagersFacade.getOrCreateWalletManager( + userWalletId = userWalletId, + blockchain = blockchain, + derivationPath = network.derivationPath.value, + ) ?: error("Wallet manager not found") val callData = SmartContractCallDataProviderFactory.getTokenTransferCallData( destinationAddress = destination, @@ -102,15 +107,25 @@ internal class DefaultTransactionRepository( null } - return@withContext createTransaction( - amount = amount, - fee = fee, - memo = null, - destination = destination, - userWalletId = userWalletId, - network = network, - txExtras = getMemoExtras(networkId = network.id.value, memo = memo) ?: extras, - ) + return@withContext if (fee != null) { + createTransaction( + amount = amount, + fee = fee, + memo = null, + destination = destination, + userWalletId = userWalletId, + network = network, + txExtras = getMemoExtras(networkId = network.id.value, memo = memo) ?: extras, + ) + } else { + TransactionData.Uncompiled( + amount = amount, + sourceAddress = walletManager.wallet.address, + destinationAddress = destination, + extras = getMemoExtras(networkId = network.id.value, memo = memo) ?: extras, + fee = null, + ) + } } override suspend fun createApprovalTransaction( diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/TransactionRepository.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/TransactionRepository.kt index 2149911b09..ac3045a6eb 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/TransactionRepository.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/TransactionRepository.kt @@ -28,7 +28,7 @@ interface TransactionRepository { @Suppress("LongParameterList") suspend fun createTransferTransaction( amount: Amount, - fee: Fee, + fee: Fee?, memo: String?, destination: String, userWalletId: UserWalletId, diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/CreateTransferTransactionUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/CreateTransferTransactionUseCase.kt index 64457a93b8..21834aa068 100644 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/CreateTransferTransactionUseCase.kt +++ b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/CreateTransferTransactionUseCase.kt @@ -38,4 +38,25 @@ class CreateTransferTransactionUseCase( network = network, ) } + + /** + * [REDACTED_TODO_COMMENT] + */ + @Suppress("LongParameterList") + suspend operator fun invoke( + amount: Amount, + memo: String?, + destination: String, + userWalletId: UserWalletId, + network: Network, + ) = Either.catch { + transactionRepository.createTransferTransaction( + amount = amount, + memo = memo, + fee = null, + destination = destination, + userWalletId = userWalletId, + network = network, + ) + } } \ No newline at end of file diff --git a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/GetTransferFeeUseCase.kt b/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/GetTransferFeeUseCase.kt deleted file mode 100644 index 0a1582967d..0000000000 --- a/domain/transaction/src/main/java/com/tangem/domain/transaction/usecase/GetTransferFeeUseCase.kt +++ /dev/null @@ -1,102 +0,0 @@ -package com.tangem.domain.transaction.usecase - -import arrow.core.raise.catch -import arrow.core.raise.either -import com.tangem.blockchain.common.* -import com.tangem.blockchain.common.smartcontract.SmartContractCallDataProviderFactory -import com.tangem.blockchain.extensions.Result -import com.tangem.domain.demo.DemoConfig -import com.tangem.domain.demo.DemoTransactionSender -import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.domain.transaction.error.GetFeeError -import com.tangem.domain.transaction.error.mapToFeeError -import com.tangem.domain.walletmanager.WalletManagersFacade -import com.tangem.domain.wallets.models.UserWallet -import java.math.BigDecimal - -/** - * Use case to get transfer transaction fee - * - * !!!IMPORTANT - * Use when transaction data is compiled by us using BlockchainSDK methods - */ -class GetTransferFeeUseCase( - private val walletManagersFacade: WalletManagersFacade, - private val demoConfig: DemoConfig, -) { - suspend operator fun invoke( - amount: BigDecimal, - destination: String, - userWallet: UserWallet, - cryptoCurrency: CryptoCurrency, - ) = either { - catch( - block = { - val amountData = convertCryptoCurrencyToAmount(cryptoCurrency, amount) - - val result = if (demoConfig.isDemoCardId(userWallet.scanResponse.card.cardId)) { - demoTransactionSender(userWallet, cryptoCurrency).getFee( - amount = amountData, - destination = destination, - ) - } else { - val walletManager = walletManagersFacade.getOrCreateWalletManager( - userWalletId = userWallet.walletId, - network = cryptoCurrency.network, - ) - val smartContractCallData = if (amountData.type is AmountType.Token) { - SmartContractCallDataProviderFactory.getTokenTransferCallData( - amount = amountData, - destinationAddress = destination, - blockchain = Blockchain.fromId(cryptoCurrency.network.id.value), - ) - } else { - null - } - - (walletManager as? TransactionSender)?.getFee( - amount = amountData, - destination = destination, - callData = smartContractCallData, - ) ?: error("Fee is null") - } - - val maybeFee = when (result) { - is Result.Success -> result.data - is Result.Failure -> raise(result.mapToFeeError()) - } - maybeFee - }, - catch = { - raise(GetFeeError.DataError(it)) - }, - ) - } - - private suspend fun demoTransactionSender( - userWallet: UserWallet, - cryptoCurrency: CryptoCurrency, - ): DemoTransactionSender { - return DemoTransactionSender( - walletManagersFacade - .getOrCreateWalletManager(userWallet.walletId, cryptoCurrency.network) - ?: error("WalletManager is null"), - ) - } - - private fun convertCryptoCurrencyToAmount(cryptoCurrency: CryptoCurrency, amount: BigDecimal) = Amount( - currencySymbol = cryptoCurrency.symbol, - value = amount, - decimals = cryptoCurrency.decimals, - type = when (cryptoCurrency) { - is CryptoCurrency.Coin -> AmountType.Coin - is CryptoCurrency.Token -> AmountType.Token( - token = Token( - symbol = cryptoCurrency.symbol, - contractAddress = cryptoCurrency.contractAddress, - decimals = cryptoCurrency.decimals, - ), - ) - }, - ) -} \ No newline at end of file diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmModel.kt index f130895489..e810d725d9 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmModel.kt @@ -26,7 +26,7 @@ import com.tangem.domain.settings.NeverShowTapHelpUseCase import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase import com.tangem.domain.tokens.IsAmountSubtractAvailableUseCase import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.domain.transaction.usecase.CreateTransactionUseCase +import com.tangem.domain.transaction.usecase.CreateTransferTransactionUseCase import com.tangem.domain.transaction.usecase.SendTransactionUseCase import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase import com.tangem.domain.utils.convertToSdkAmount @@ -74,7 +74,7 @@ internal class SendConfirmModel @Inject constructor( private val router: Router, private val isSendTapHelpEnabledUseCase: IsSendTapHelpEnabledUseCase, private val neverShowTapHelpUseCase: NeverShowTapHelpUseCase, - private val createTransactionUseCase: CreateTransactionUseCase, + private val createTransferTransactionUseCase: CreateTransferTransactionUseCase, private val sendTransactionUseCase: SendTransactionUseCase, private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase, private val getCardInfoUseCase: GetCardInfoUseCase, @@ -326,7 +326,7 @@ internal class SendConfirmModel @Inject constructor( ) modelScope.launch { - createTransactionUseCase( + createTransferTransactionUseCase( amount = receivingAmount.convertToSdkAmount(cryptoCurrency), fee = fee, memo = memo, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt index d379946a64..250e790576 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt @@ -3,6 +3,7 @@ package com.tangem.features.send.v2.send.model import androidx.compose.runtime.Stable import arrow.core.Either import arrow.core.getOrElse +import arrow.core.left import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.common.ui.amountScreen.models.AmountState import com.tangem.core.decompose.di.ModelScoped @@ -28,16 +29,18 @@ import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase import com.tangem.domain.tokens.error.CurrencyStatusError import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.transaction.error.GetFeeError -import com.tangem.domain.transaction.usecase.GetTransferFeeUseCase +import com.tangem.domain.transaction.usecase.CreateTransferTransactionUseCase +import com.tangem.domain.transaction.usecase.GetFeeUseCase +import com.tangem.domain.utils.convertToSdkAmount import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.features.send.v2.api.SendComponent import com.tangem.features.send.v2.common.CommonSendRoute import com.tangem.features.send.v2.common.PredefinedValues +import com.tangem.features.send.v2.common.SendConfirmAlertFactory import com.tangem.features.send.v2.common.ui.state.ConfirmUM import com.tangem.features.send.v2.common.ui.state.NavigationUM import com.tangem.features.send.v2.send.confirm.SendConfirmComponent -import com.tangem.features.send.v2.common.SendConfirmAlertFactory import com.tangem.features.send.v2.send.ui.state.SendUM import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponent import com.tangem.features.send.v2.subcomponents.amount.SendAmountUpdateQRTrigger @@ -80,7 +83,8 @@ internal class SendModel @Inject constructor( private val getCardInfoUseCase: GetCardInfoUseCase, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, - private val getTransferFeeUseCase: GetTransferFeeUseCase, + private val createTransferTransactionUseCase: CreateTransferTransactionUseCase, + private val getFeeUseCase: GetFeeUseCase, private val sendAmountUpdateQRTrigger: SendAmountUpdateQRTrigger, ) : Model(), SendComponentCallback { @@ -135,13 +139,23 @@ internal class SendModel @Inject constructor( val destinationUM = uiState.value.destinationUM as? DestinationUM.Content ?: error("Invalid destination") val amountUM = uiState.value.amountUM as? AmountState.Data ?: error("Invalid amount") val enteredDestinationAddress = destinationUM.addressTextField.value + val enteredMemo = destinationUM.memoTextField?.value val enteredAmount = amountUM.amountTextField.cryptoAmount.value ?: error("Invalid amount") - return getTransferFeeUseCase( + val transferTransaction = createTransferTransactionUseCase( + amount = enteredAmount.convertToSdkAmount(cryptoCurrency), + memo = enteredMemo, destination = enteredDestinationAddress, - amount = enteredAmount, + userWalletId = userWallet.walletId, + network = cryptoCurrency.network, + ).getOrElse { + return GetFeeError.DataError(it).left() + } + + return getFeeUseCase( + transactionData = transferTransaction, userWallet = userWallet, - cryptoCurrency = params.currency, + network = params.currency.network, ) } diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt index fbcd15cc1f..63bbdb92ed 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/model/SendModel.kt @@ -92,9 +92,9 @@ internal class SendModel @Inject constructor( private val getTxHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase, private val getTxHistoryItemsUseCase: GetTxHistoryItemsUseCase, private val getFixedTxHistoryItemsUseCase: GetFixedTxHistoryItemsUseCase, - private val getTransferFeeUseCase: GetTransferFeeUseCase, private val sendTransactionUseCase: SendTransactionUseCase, private val createTransferTransactionUseCase: CreateTransferTransactionUseCase, + private val getFeeUseCase: GetFeeUseCase, private val validateWalletAddressUseCase: ValidateWalletAddressUseCase, private val isAmountSubtractAvailableUseCase: IsAmountSubtractAvailableUseCase, private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, @@ -825,12 +825,23 @@ internal class SendModel @Inject constructor( val amountState = uiState.value.getAmountState(isFromConfirmation) as? AmountState.Data ?: return null val recipientState = uiState.value.getRecipientState(isFromConfirmation) ?: return null val amount = amountState.amountTextField.cryptoAmount.value ?: return null + val destinationAddress = recipientState.addressTextField.value + val memo = recipientState.memoTextField?.value - return getTransferFeeUseCase.invoke( - amount = amount, - destination = recipientState.addressTextField.value, + val transferTransaction = createTransferTransactionUseCase( + amount = amount.convertToSdkAmount(cryptoCurrency), + memo = memo, + destination = destinationAddress, + userWalletId = userWallet.walletId, + network = cryptoCurrency.network, + ).getOrElse { + return GetFeeError.DataError(it).left() + } + + return getFeeUseCase( + transactionData = transferTransaction, userWallet = userWallet, - cryptoCurrency = cryptoCurrencyStatus.currency, + network = params.currency.network, ) } // endregion