diff --git a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt index 934f519967..799274946e 100644 --- a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt @@ -224,26 +224,33 @@ class TransactionManagerImpl( when (fee.data) { is TransactionFee.Single -> { val normalFee = (fee.data as TransactionFee.Single).normal - val singleFee = ProxyFee( - gasLimit = BigInteger.ZERO, - fee = convertToProxyAmount(amount = normalFee.amount), - ) - ProxyFees.SingleFee( - singleFee = singleFee, - ) + val singleFee = if (normalFee as? Fee.CardanoToken != null) { + ProxyFee.CardanoToken( + gasLimit = BigInteger.ZERO, + fee = convertToProxyAmount(amount = normalFee.amount), + minAdaValue = normalFee.minAdaValue, + ) + } else { + ProxyFee.Common( + gasLimit = BigInteger.ZERO, + fee = convertToProxyAmount(amount = normalFee.amount), + ) + } + + ProxyFees.SingleFee(singleFee = singleFee) } is TransactionFee.Choosable -> { val choosableFee = fee.data as TransactionFee.Choosable ProxyFees.MultipleFees( - minFee = ProxyFee( + minFee = ProxyFee.Common( gasLimit = BigInteger.ZERO, fee = convertToProxyAmount(amount = choosableFee.minimum.amount), ), - normalFee = ProxyFee( + normalFee = ProxyFee.Common( gasLimit = BigInteger.ZERO, fee = convertToProxyAmount(amount = choosableFee.normal.amount), ), - priorityFee = ProxyFee( + priorityFee = ProxyFee.Common( gasLimit = BigInteger.ZERO, fee = convertToProxyAmount(amount = choosableFee.priority.amount), ), @@ -300,15 +307,15 @@ class TransactionManagerImpl( is Result.Success -> { val choosableFee = fee.data - val minProxyFee = ProxyFee( + val minProxyFee = ProxyFee.Common( gasLimit = (choosableFee.minimum as Fee.Ethereum).gasLimit, fee = convertToProxyAmount(amount = choosableFee.minimum.amount), ) - val normalProxyFee = ProxyFee( + val normalProxyFee = ProxyFee.Common( gasLimit = (choosableFee.normal as Fee.Ethereum).gasLimit, fee = convertToProxyAmount(amount = choosableFee.normal.amount), ) - val priorityProxyFee = ProxyFee( + val priorityProxyFee = ProxyFee.Common( gasLimit = (choosableFee.priority as Fee.Ethereum).gasLimit, fee = convertToProxyAmount(amount = choosableFee.priority.amount), ) @@ -463,7 +470,7 @@ class TransactionManagerImpl( scale = blockchain.decimals(), mathContext = MathContext(blockchain.decimals(), RoundingMode.HALF_EVEN), ) - val minFee = ProxyFee( + val minFee = ProxyFee.Common( gasLimit = gasLimit, fee = ProxyAmount( currencySymbol = blockchain.currency, @@ -471,7 +478,7 @@ class TransactionManagerImpl( decimals = blockchain.decimals(), ), ) - val normalFee = ProxyFee( + val normalFee = ProxyFee.Common( gasLimit = gasLimit, fee = ProxyAmount( currencySymbol = blockchain.currency, @@ -479,7 +486,7 @@ class TransactionManagerImpl( decimals = blockchain.decimals(), ), ) - val priorityFee = ProxyFee( + val priorityFee = ProxyFee.Common( gasLimit = gasLimit, fee = ProxyAmount( currencySymbol = blockchain.currency, 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 cad609ee54..4016636877 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 @@ -57,7 +57,7 @@ internal class DefaultTransactionRepository( override suspend fun validateTransaction( amount: Amount, - fee: Fee, + fee: Fee?, memo: String?, destination: String, userWalletId: UserWalletId, @@ -65,9 +65,10 @@ internal class DefaultTransactionRepository( isSwap: Boolean, hash: String?, ): Result { + val blockchain = Blockchain.fromId(network.id.value) val walletManager = walletManagersStore.getSyncOrNull( userWalletId = userWalletId, - blockchain = Blockchain.fromId(network.id.value), + blockchain = blockchain, derivationPath = network.derivationPath.value, ) @@ -76,7 +77,7 @@ internal class DefaultTransactionRepository( return if (validator != null) { val transaction = walletManager.createTransactionInternal( amount = amount, - fee = fee, + fee = fee ?: Fee.Common(amount = amount), memo = memo, destination = destination, network = network, 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 4acf080799..156e2bb0fa 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 @@ -25,13 +25,13 @@ interface TransactionRepository { @Suppress("LongParameterList") suspend fun validateTransaction( amount: Amount, - fee: Fee, + fee: Fee?, memo: String?, destination: String, userWalletId: UserWalletId, network: Network, - isSwap: Boolean, - hash: String?, + isSwap: Boolean = false, + hash: String? = null, ): Result suspend fun sendTransaction( diff --git a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt index c0427ecfd2..57bb2ccffc 100644 --- a/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt +++ b/features/send/impl/src/main/java/com/tangem/features/send/impl/presentation/state/confirm/SendNotificationFactory.kt @@ -435,8 +435,6 @@ internal class SendNotificationFactory( addCardanoTransactionValidationError( error = it as? BlockchainSdkError.Cardano ?: return@fold, sendingCurrency = sendingCurrency, - sendingAmount = sendingAmount, - fee = fee, ) }, ifRight = { @@ -455,8 +453,6 @@ internal class SendNotificationFactory( private suspend fun MutableList.addCardanoTransactionValidationError( error: BlockchainSdkError.Cardano, sendingCurrency: CryptoCurrency, - sendingAmount: BigDecimal, - fee: Fee, ) { when (error) { BlockchainSdkError.Cardano.InsufficientMinAdaBalanceToSendToken -> { @@ -473,9 +469,15 @@ internal class SendNotificationFactory( BlockchainSdkError.Cardano.InsufficientRemainingBalance, BlockchainSdkError.Cardano.InsufficientSendingAdaAmount, -> { - addDustWarningNotification( - feeValue = fee.amount.value ?: BigDecimal.ZERO, - sendingAmount = sendingAmount, + val dustValue = currencyChecksRepository.getDustValue( + userWalletId = userWalletProvider().walletId, + network = sendingCurrency.network, + ) ?: return + + add( + SendNotification.Error.MinimumAmountError( + amount = dustValue.parseBigDecimal(sendingCurrency.decimals), + ), ) } } diff --git a/features/swap/domain/build.gradle.kts b/features/swap/domain/build.gradle.kts index 10ccde5b9f..73348d6d0b 100644 --- a/features/swap/domain/build.gradle.kts +++ b/features/swap/domain/build.gradle.kts @@ -47,5 +47,6 @@ dependencies { implementation(deps.arrow.core) implementation(deps.timber) implementation(deps.tangem.blockchain) + implementation(deps.tangem.card.core) implementation(deps.moshi) } \ No newline at end of file diff --git a/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/domain/Warning.kt b/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/domain/Warning.kt index 318b5635de..a7e59700b2 100644 --- a/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/domain/Warning.kt +++ b/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/domain/Warning.kt @@ -9,4 +9,13 @@ sealed class Warning { data class MinAmountWarning(val dustValue: BigDecimal) : Warning() data class ReduceAmountWarning(val tezosFeeThreshold: BigDecimal) : Warning() + + sealed class Cardano : Warning() { + + data class MinAdaValueCharged(val tokenName: String, val minAdaValue: String) : Cardano() + + data object InsufficientBalanceToTransferCoin : Cardano() + + data class InsufficientBalanceToTransferToken(val tokenName: String) : Cardano() + } } \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index 8deb74e13e..8bba53e589 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -5,9 +5,11 @@ import arrow.core.getOrElse import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.BlockchainSdkError import com.tangem.blockchain.common.transaction.Fee import com.tangem.blockchain.common.transaction.TransactionFee import com.tangem.blockchainsdk.utils.minimalAmount +import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.extenstions.unwrap import com.tangem.domain.appcurrency.repository.AppCurrencyRepository @@ -21,6 +23,8 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.CurrencyChecksRepository import com.tangem.domain.tokens.repository.QuotesRepository import com.tangem.domain.tokens.utils.convertToAmount +import com.tangem.domain.transaction.TransactionRepository +import com.tangem.domain.transaction.error.GetFeeError import com.tangem.domain.transaction.error.SendTransactionError import com.tangem.domain.transaction.usecase.CreateTransactionUseCase import com.tangem.domain.transaction.usecase.EstimateFeeUseCase @@ -36,15 +40,12 @@ import com.tangem.feature.swap.domain.models.SwapAmount import com.tangem.feature.swap.domain.models.domain.* import com.tangem.feature.swap.domain.models.toStringWithRightOffset import com.tangem.feature.swap.domain.models.ui.* +import com.tangem.lib.crypto.BlockchainUtils import com.tangem.lib.crypto.TransactionManager import com.tangem.lib.crypto.UserWalletManager -import com.tangem.lib.crypto.models.AnalyticsData -import com.tangem.lib.crypto.models.ApproveTxData -import com.tangem.lib.crypto.models.ProxyAmount -import com.tangem.lib.crypto.models.ProxyFees +import com.tangem.lib.crypto.models.* import com.tangem.lib.crypto.models.transactions.SendTxResult import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import com.tangem.utils.isNullOrZero import com.tangem.utils.toFiatString import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.firstOrNull @@ -73,6 +74,7 @@ internal class SwapInteractorImpl @Inject constructor( private val currenciesRepository: CurrenciesRepository, private val initialToCurrencyResolver: InitialToCurrencyResolver, private val demoConfig: DemoConfig, + private val transactionRepository: TransactionRepository, ) : SwapInteractor { private val estimateFeeUseCase by lazy(LazyThreadSafetyMode.NONE) { @@ -350,6 +352,7 @@ internal class SwapInteractorImpl @Inject constructor( isAllowedToSpend = isAllowedToSpend, isBalanceWithoutFeeEnough = isBalanceWithoutFeeEnough, txFee = TxFeeState.Empty, + transactionFee = null, includeFeeInAmount = IncludeFeeInAmount.Excluded, // exclude for dex ) } @@ -379,6 +382,7 @@ internal class SwapInteractorImpl @Inject constructor( fromTokenStatus: CryptoCurrencyStatus, amount: SwapAmount, feeState: TxFeeState, + minAdaValue: BigDecimal?, ): List { val fromToken = fromTokenStatus.currency val userWalletId = getSelectedWallet()?.walletId ?: return emptyList() @@ -386,6 +390,13 @@ internal class SwapInteractorImpl @Inject constructor( manageExistentialDepositWarning(warnings, userWalletId, amount, fromToken) manageDustWarning(warnings, feeState, userWalletId, fromTokenStatus, amount) manageReduceAmountWarning(warnings, fromTokenStatus, amount) + manageCardanoTransactionValidationWarnings( + warnings = warnings, + fromToken = fromToken, + amount = amount, + userWalletId = userWalletId, + minAdaValue = minAdaValue, + ) return warnings } @@ -414,23 +425,35 @@ internal class SwapInteractorImpl @Inject constructor( fromTokenStatus: CryptoCurrencyStatus, amount: SwapAmount, ) { + if (BlockchainUtils.isCardano(fromTokenStatus.currency.network.id.value)) return + val fee = when (feeState) { TxFeeState.Empty -> BigDecimal.ZERO is TxFeeState.MultipleFeeState -> feeState.priorityFee.feeValue is TxFeeState.SingleFeeState -> feeState.fee.feeValue } - val dust = currencyChecksRepository.getDustValue(userWalletId, fromTokenStatus.currency.network) - val balance = fromTokenStatus.value.amount ?: BigDecimal.ZERO - if (dust != null && - !balance.isNullOrZero() && - amount.value < balance - ) { - val change = balance - (amount.value + fee) - val isChangeLowerThanDust = change < dust && change != BigDecimal.ZERO - val isShowWarning = amount.value + fee < dust || isChangeLowerThanDust - if (isShowWarning) { - warnings.add(Warning.MinAmountWarning(dust)) + + val dustValue = currencyChecksRepository.getDustValue(userWalletId, fromTokenStatus.currency.network) ?: return + + val change = when (fromTokenStatus.currency) { + is CryptoCurrency.Coin -> { + val balance = fromTokenStatus.value.amount ?: BigDecimal.ZERO + balance - (fee + amount.value) } + is CryptoCurrency.Token -> { + val nativeTokenBalance = userWalletManager.getNativeTokenBalance( + fromTokenStatus.currency.network.id.value, + fromTokenStatus.currency.network.derivationPath.value, + ) + + nativeTokenBalance?.value?.minus(fee) ?: BigDecimal.ZERO + } + } + + val isChangeLowerThanDust = change < dustValue && change > BigDecimal.ZERO + + if (amount.value < dustValue || isChangeLowerThanDust) { + warnings.add(Warning.MinAmountWarning(dustValue)) } } @@ -445,6 +468,72 @@ internal class SwapInteractorImpl @Inject constructor( } } + private suspend fun manageCardanoTransactionValidationWarnings( + warnings: MutableList, + fromToken: CryptoCurrency, + amount: SwapAmount, + userWalletId: UserWalletId, + minAdaValue: BigDecimal?, + ) { + transactionRepository.validateTransaction( + amount = amount.value.convertToAmount(fromToken), + fee = null, + memo = null, + destination = getTokenAddress(fromToken), + userWalletId = userWalletId, + network = fromToken.network, + ) + .fold( + onFailure = { + addCardanoTransactionValidationError( + warnings = warnings, + error = it as? BlockchainSdkError.Cardano ?: return@fold, + fromToken = fromToken, + userWalletId = userWalletId, + ) + }, + onSuccess = { + minAdaValue?.let { + warnings.add( + Warning.Cardano.MinAdaValueCharged( + tokenName = fromToken.name, + minAdaValue = minAdaValue.parseBigDecimal(fromToken.decimals), + ), + ) + } + }, + ) + } + + private suspend fun addCardanoTransactionValidationError( + warnings: MutableList, + error: BlockchainSdkError.Cardano, + fromToken: CryptoCurrency, + userWalletId: UserWalletId, + ) { + when (error) { + BlockchainSdkError.Cardano.InsufficientMinAdaBalanceToSendToken -> { + Warning.Cardano.InsufficientBalanceToTransferToken(fromToken.name) + } + BlockchainSdkError.Cardano.InsufficientRemainingBalanceToWithdrawTokens -> { + when (fromToken) { + is CryptoCurrency.Coin -> Warning.Cardano.InsufficientBalanceToTransferCoin + is CryptoCurrency.Token -> { + Warning.Cardano.InsufficientBalanceToTransferToken(fromToken.name) + } + } + } + BlockchainSdkError.Cardano.InsufficientRemainingBalance, + BlockchainSdkError.Cardano.InsufficientSendingAdaAmount, + -> { + val dustValue = currencyChecksRepository.getDustValue(userWalletId, fromToken.network) ?: return + + Warning.MinAmountWarning(dustValue) + } + } + .let(warnings::add) // add warning to the list + } + override suspend fun onSwap( swapProvider: SwapProvider, swapData: SwapDataModel?, @@ -841,8 +930,16 @@ internal class SwapInteractorImpl @Inject constructor( val fromToken = fromTokenStatus.currency val toToken = toTokenStatus.currency return coroutineScope { + val txFeeResult = getSelectedWalletSyncUseCase().getOrNull()?.walletId?.let { userWalletId -> + getUnhandledFee( + amount = amount.value, + userWalletId = userWalletId, + cryptoCurrency = fromToken, + ) + } + val txFee = if (provider.type == ExchangeProviderType.CEX) { - getFeeForCex(amount, fromTokenStatus) + getFeeForCex(txFeeResult, fromTokenStatus) } else { TxFeeState.Empty } @@ -881,11 +978,13 @@ internal class SwapInteractorImpl @Inject constructor( isAllowedToSpend = isAllowedToSpend, isBalanceWithoutFeeEnough = isBalanceWithoutFeeEnough, txFee = txFee, + transactionFee = txFeeResult?.getOrNull(), includeFeeInAmount = includeFeeInAmount, ) } } + @Suppress("LongMethod") private suspend fun getQuotesState( exchangeProviderType: ExchangeProviderType, quoteDataModel: Either, @@ -896,6 +995,7 @@ internal class SwapInteractorImpl @Inject constructor( isAllowedToSpend: Boolean, isBalanceWithoutFeeEnough: Boolean, txFee: TxFeeState, + transactionFee: TransactionFee?, includeFeeInAmount: IncludeFeeInAmount, ): SwapState { return quoteDataModel.fold( @@ -909,7 +1009,12 @@ internal class SwapInteractorImpl @Inject constructor( swapData = null, txFeeState = txFee, ).copy( - warnings = manageWarnings(fromToken, amount, txFee), + warnings = manageWarnings( + fromTokenStatus = fromToken, + amount = amount, + feeState = txFee, + minAdaValue = (transactionFee?.normal as? Fee.CardanoToken)?.minAdaValue, + ), ) when (exchangeProviderType) { @@ -1113,7 +1218,14 @@ internal class SwapInteractorImpl @Inject constructor( ) swapState.copy( permissionState = PermissionDataState.Empty, - warnings = manageWarnings(fromToken, amount, txFeeState), + warnings = manageWarnings( + fromToken, + amount, + txFeeState, + (feeData as? ProxyFees.SingleFee)?.let { + (it.singleFee as? ProxyFee.CardanoToken)?.minAdaValue + }, + ), preparedSwapConfigState = PreparedSwapConfigState( isAllowedToSpend = true, isBalanceEnough = isBalanceIncludeFeeEnough, @@ -1179,23 +1291,26 @@ internal class SwapInteractorImpl @Inject constructor( ) } - private suspend fun getFeeForCex(amount: SwapAmount, fromToken: CryptoCurrencyStatus): TxFeeState { - getSelectedWalletSyncUseCase().getOrNull()?.walletId?.let { userWalletId -> - val txFeeResult = estimateFeeUseCase( - amount = amount.value, - userWalletId = userWalletId, - cryptoCurrency = fromToken.currency, - ).firstOrNull() - return txFeeResult?.fold( - ifLeft = { - TxFeeState.Empty - }, - ifRight = { txFee -> - txFee.toTxFeeState(fromToken.currency) - }, - ) ?: TxFeeState.Empty - } - return TxFeeState.Empty + private suspend fun getFeeForCex( + txFeeResult: Either?, + fromToken: CryptoCurrencyStatus, + ): TxFeeState { + return txFeeResult?.fold( + ifLeft = { TxFeeState.Empty }, + ifRight = { txFee -> txFee.toTxFeeState(fromToken.currency) }, + ) ?: TxFeeState.Empty + } + + private suspend fun getUnhandledFee( + amount: BigDecimal, + userWalletId: UserWalletId, + cryptoCurrency: CryptoCurrency, + ): Either? { + return estimateFeeUseCase( + amount = amount, + userWalletId = userWalletId, + cryptoCurrency = cryptoCurrency, + ).firstOrNull() } @Suppress("LongParameterList", "LongMethod") diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt index 9c2290da01..1a6a6e8b22 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt @@ -50,6 +50,7 @@ class SwapDomainModule { coroutineDispatcherProvider: CoroutineDispatcherProvider, initialToCurrencyResolver: InitialToCurrencyResolver, currenciesRepository: CurrenciesRepository, + transactionRepository: TransactionRepository, ): SwapInteractor { return SwapInteractorImpl( transactionManager = transactionManager, @@ -69,6 +70,7 @@ class SwapDomainModule { currenciesRepository = currenciesRepository, initialToCurrencyResolver = initialToCurrencyResolver, demoConfig = DemoConfig(), + transactionRepository = transactionRepository, ) } diff --git a/features/swap/presentation/build.gradle.kts b/features/swap/presentation/build.gradle.kts index c78375b5e4..643cf8f201 100644 --- a/features/swap/presentation/build.gradle.kts +++ b/features/swap/presentation/build.gradle.kts @@ -28,6 +28,7 @@ dependencies { implementation(projects.domain.balanceHiding.models) implementation(projects.domain.tokens) implementation(projects.domain.tokens.models) + implementation(projects.domain.transaction) implementation(projects.domain.wallets) implementation(projects.domain.wallets.models) implementation(projects.domain.settings) @@ -56,6 +57,9 @@ dependencies { implementation(projects.features.swap.api) implementation(projects.features.tokendetails.api) + /** Libs */ + implementation(projects.libs.crypto) + /** Other libraries */ implementation(deps.compose.shimmer) implementation(deps.compose.accompanist.webView) @@ -67,5 +71,4 @@ dependencies { /** DI */ implementation(deps.hilt.android) kapt(deps.hilt.kapt) - } \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt index 74d4f48e01..cd22de2a3b 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt @@ -110,6 +110,7 @@ sealed interface SwapWarning { val type: GenericWarningType = GenericWarningType.OTHER, val onClick: () -> Unit, ) : SwapWarning + data class GeneralError(val notificationConfig: NotificationConfig) : SwapWarning data class UnableToCoverFeeWarning(val notificationConfig: NotificationConfig) : SwapWarning data class GeneralWarning(val notificationConfig: NotificationConfig) : SwapWarning @@ -117,6 +118,16 @@ sealed interface SwapWarning { data class TransactionInProgressWarning(val title: TextReference, val description: TextReference) : SwapWarning data class NeedReserveToCreateAccount(val notificationConfig: NotificationConfig) : SwapWarning data class ReduceAmount(val notificationConfig: NotificationConfig) : SwapWarning + + sealed interface Cardano : SwapWarning { + val notificationConfig: NotificationConfig + + data class MinAdaValueCharged(override val notificationConfig: NotificationConfig) : Cardano + + data class InsufficientBalanceToTransferCoin(override val notificationConfig: NotificationConfig) : Cardano + + data class InsufficientBalanceToTransferToken(override val notificationConfig: NotificationConfig) : Cardano + } } enum class GenericWarningType { diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index b4557850a7..4e12e4c227 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -405,6 +405,15 @@ internal class StateBuilder( ), ) } + Warning.Cardano.InsufficientBalanceToTransferCoin -> { + warnings.add(createInsufficientBalanceToTransferCoin()) + } + is Warning.Cardano.InsufficientBalanceToTransferToken -> { + warnings.add(createInsufficientBalanceToTransferToken(tokenName = it.tokenName)) + } + is Warning.Cardano.MinAdaValueCharged -> { + warnings.add(createMinAdaValueCharged(minAdaValue = it.minAdaValue, tokenName = it.tokenName)) + } } } } @@ -1400,6 +1409,42 @@ internal class StateBuilder( iconResId = R.drawable.img_attention_20, ) } + + private fun createMinAdaValueCharged(minAdaValue: String, tokenName: String): SwapWarning { + return SwapWarning.Cardano.MinAdaValueCharged( + NotificationConfig( + title = resourceReference(id = R.string.cardano_coin_will_be_send_with_token_title), + subtitle = resourceReference( + id = R.string.cardano_coin_will_be_send_with_token_description, + formatArgs = wrappedList(minAdaValue, tokenName), + ), + iconResId = R.drawable.img_attention_20, + ), + ) + } + + private fun createInsufficientBalanceToTransferCoin(): SwapWarning { + return SwapWarning.Cardano.InsufficientBalanceToTransferCoin( + NotificationConfig( + title = resourceReference(id = R.string.cardano_max_amount_has_token_title), + subtitle = resourceReference(id = R.string.cardano_max_amount_has_token_description), + iconResId = R.drawable.img_attention_20, + ), + ) + } + + private fun createInsufficientBalanceToTransferToken(tokenName: String): SwapWarning { + return SwapWarning.Cardano.InsufficientBalanceToTransferToken( + NotificationConfig( + title = resourceReference(id = R.string.cardano_insufficient_balance_to_send_token_title), + subtitle = resourceReference( + id = R.string.cardano_insufficient_balance_to_send_token_description, + formatArgs = wrappedList(tokenName), + ), + iconResId = R.drawable.img_attention_20, + ), + ) + } // end region private fun getShortAddressValue(fullAddress: String): String { diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt index 1137f0f264..0cdecf9771 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/SwapScreenContent.kt @@ -391,7 +391,8 @@ private fun SwapWarnings(warnings: List) { }, ) } - else -> {} + is SwapWarning.Cardano -> Notification(config = warning.notificationConfig) + SwapWarning.InsufficientFunds -> Unit } SpacerH8() } diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/models/ProxyFee.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/models/ProxyFee.kt index 56b92d5688..a4643460ea 100644 --- a/libs/crypto/src/main/java/com/tangem/lib/crypto/models/ProxyFee.kt +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/models/ProxyFee.kt @@ -1,8 +1,21 @@ package com.tangem.lib.crypto.models +import java.math.BigDecimal import java.math.BigInteger -data class ProxyFee( - val gasLimit: BigInteger, - val fee: ProxyAmount, -) \ No newline at end of file +sealed interface ProxyFee { + + val gasLimit: BigInteger + val fee: ProxyAmount + + data class Common( + override val gasLimit: BigInteger, + override val fee: ProxyAmount, + ) : ProxyFee + + data class CardanoToken( + override val gasLimit: BigInteger, + override val fee: ProxyAmount, + val minAdaValue: BigDecimal, + ) : ProxyFee +} \ No newline at end of file