Updated on 2026-08-14
This commit is contained in:
parent
7e79305db7
commit
55942f2208
13 changed files with 281 additions and 71 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<Unit> {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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<Unit>
|
||||
|
||||
suspend fun sendTransaction(
|
||||
|
|
|
|||
|
|
@ -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<SendNotification>.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),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,5 +47,6 @@ dependencies {
|
|||
implementation(deps.arrow.core)
|
||||
implementation(deps.timber)
|
||||
implementation(deps.tangem.blockchain)
|
||||
implementation(deps.tangem.card.core)
|
||||
implementation(deps.moshi)
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Warning> {
|
||||
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<Warning>,
|
||||
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<Warning>,
|
||||
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<DataError, QuoteModel>,
|
||||
|
|
@ -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<GetFeeError, TransactionFee>?,
|
||||
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<GetFeeError, TransactionFee>? {
|
||||
return estimateFeeUseCase(
|
||||
amount = amount,
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
).firstOrNull()
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList", "LongMethod")
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -391,7 +391,8 @@ private fun SwapWarnings(warnings: List<SwapWarning>) {
|
|||
},
|
||||
)
|
||||
}
|
||||
else -> {}
|
||||
is SwapWarning.Cardano -> Notification(config = warning.notificationConfig)
|
||||
SwapWarning.InsufficientFunds -> Unit
|
||||
}
|
||||
SpacerH8()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue