Updated on 2026-08-14
This commit is contained in:
parent
ef2cb2ce43
commit
eb0b9ca69c
4 changed files with 47 additions and 21 deletions
|
|
@ -37,6 +37,7 @@ sealed interface SwapState {
|
|||
data class SwapError(
|
||||
val fromTokenInfo: TokenSwapInfo,
|
||||
val error: DataError,
|
||||
val includeFeeInAmount: IncludeFeeInAmount,
|
||||
) : SwapState
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import kotlinx.coroutines.coroutineScope
|
|||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
import java.math.RoundingMode
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -263,7 +264,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
provider = provider,
|
||||
amount = amount,
|
||||
isBalanceWithoutFeeEnough = isBalanceWithoutFeeEnough,
|
||||
selectedFee = selectedFee,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -340,7 +340,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
provider: SwapProvider,
|
||||
amount: SwapAmount,
|
||||
isBalanceWithoutFeeEnough: Boolean,
|
||||
selectedFee: FeeType,
|
||||
): Pair<SwapProvider, SwapState> {
|
||||
return provider to loadCexQuoteData(
|
||||
exchangeProviderType = ExchangeProviderType.CEX,
|
||||
|
|
@ -351,7 +350,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
isAllowedToSpend = true,
|
||||
isBalanceWithoutFeeEnough = isBalanceWithoutFeeEnough,
|
||||
provider = provider,
|
||||
selectedFee = selectedFee,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -411,7 +409,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
txFee = state.txFee,
|
||||
amount = amount,
|
||||
fromToken = fromToken.currency,
|
||||
selectedFee = selectedFee,
|
||||
)
|
||||
return state.copy(
|
||||
permissionState = PermissionDataState.Empty,
|
||||
|
|
@ -580,10 +577,11 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
)
|
||||
|
||||
return if (fee.gasLimit != 0) {
|
||||
val feeAmountWithDecimals = feeAmountValue.movePointRight(fee.decimals)
|
||||
Fee.Ethereum(
|
||||
amount = feeAmount,
|
||||
gasLimit = fee.gasLimit.toBigInteger(),
|
||||
gasPrice = (feeAmountValue / fee.gasLimit.toBigDecimal()).toBigInteger(),
|
||||
gasPrice = (feeAmountWithDecimals / fee.gasLimit.toBigDecimal()).toBigInteger(),
|
||||
)
|
||||
} else {
|
||||
Fee.Common(feeAmount)
|
||||
|
|
@ -709,7 +707,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
provider: SwapProvider,
|
||||
isAllowedToSpend: Boolean,
|
||||
isBalanceWithoutFeeEnough: Boolean,
|
||||
selectedFee: FeeType,
|
||||
): SwapState {
|
||||
val fromToken = fromTokenStatus.currency
|
||||
val toToken = toTokenStatus.currency
|
||||
|
|
@ -725,7 +722,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
txFee = txFee,
|
||||
amount = amount,
|
||||
fromToken = fromToken,
|
||||
selectedFee = selectedFee,
|
||||
)
|
||||
val amountToRequest = if (includeFeeInAmount is IncludeFeeInAmount.Included) {
|
||||
includeFeeInAmount.amountSubtractFee
|
||||
|
|
@ -824,7 +820,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
?: BigDecimal.ZERO,
|
||||
cryptoCurrencyStatus = fromToken,
|
||||
)
|
||||
return SwapState.SwapError(fromTokenSwapInfo, error)
|
||||
return SwapState.SwapError(fromTokenSwapInfo, error, includeFeeInAmount)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -834,7 +830,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
txFee: TxFeeState,
|
||||
amount: SwapAmount,
|
||||
fromToken: CryptoCurrency,
|
||||
selectedFee: FeeType,
|
||||
): IncludeFeeInAmount {
|
||||
if (fromToken is CryptoCurrency.Token) {
|
||||
return IncludeFeeInAmount.Excluded
|
||||
|
|
@ -851,11 +846,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
}
|
||||
val feeValue = when (txFee) {
|
||||
TxFeeState.Empty -> BigDecimal.ZERO
|
||||
is TxFeeState.MultipleFeeState -> if (selectedFee == FeeType.NORMAL) {
|
||||
txFee.normalFee.feeValue
|
||||
} else {
|
||||
txFee.priorityFee.feeValue
|
||||
}
|
||||
is TxFeeState.MultipleFeeState -> txFee.priorityFee.feeValue
|
||||
is TxFeeState.SingleFeeState -> txFee.fee.feeValue
|
||||
}
|
||||
|
||||
|
|
@ -965,6 +956,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
SwapState.SwapError(
|
||||
fromTokenSwapInfo,
|
||||
error,
|
||||
IncludeFeeInAmount.Excluded,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -1191,8 +1183,10 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
val decimals = transactionManager.getNativeTokenDecimals(networkId)
|
||||
return when (this) {
|
||||
is TransactionFee.Choosable -> {
|
||||
val feeNormal = this.normal.amount.value ?: BigDecimal.ZERO
|
||||
val feePriority = this.priority.amount.value ?: BigDecimal.ZERO
|
||||
val normalFee = this.normal.increaseGasLimitBy(INCREASE_GAS_LIMIT_FOR_SEND)
|
||||
val priorityFee = this.priority.increaseGasLimitBy(INCREASE_GAS_LIMIT_FOR_SEND)
|
||||
val feeNormal = normalFee.amount.value ?: BigDecimal.ZERO
|
||||
val feePriority = priorityFee.amount.value ?: BigDecimal.ZERO
|
||||
val normalFiatValue = getFormattedFiatFees(networkId, feeNormal)[0]
|
||||
val priorityFiatValue = getFormattedFiatFees(networkId, feePriority)[0]
|
||||
|
||||
|
|
@ -1207,7 +1201,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
TxFeeState.MultipleFeeState(
|
||||
normalFee = TxFee(
|
||||
feeValue = feeNormal,
|
||||
gasLimit = this.normal.getGasLimit(),
|
||||
gasLimit = normalFee.getGasLimit(),
|
||||
feeFiatFormatted = normalFiatValue,
|
||||
feeCryptoFormatted = normalCryptoFee,
|
||||
decimals = decimals,
|
||||
|
|
@ -1216,7 +1210,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
),
|
||||
priorityFee = TxFee(
|
||||
feeValue = feePriority,
|
||||
gasLimit = this.priority.getGasLimit(),
|
||||
gasLimit = priorityFee.getGasLimit(),
|
||||
feeFiatFormatted = priorityFiatValue,
|
||||
feeCryptoFormatted = priorityCryptoFee,
|
||||
decimals = decimals,
|
||||
|
|
@ -1247,6 +1241,26 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Workaround to increase gas limit cause we calculate fee for random address
|
||||
*/
|
||||
private fun Fee.increaseGasLimitBy(percentage: Int): Fee {
|
||||
if (this !is Fee.Ethereum) return this
|
||||
val gasLimit = this.gasLimit
|
||||
val increasedGasPrice = this.amount.value?.movePointRight(this.amount.decimals)
|
||||
?.divide(gasLimit.toBigDecimal(), RoundingMode.HALF_UP)
|
||||
val increaseGasLimit = gasLimit
|
||||
.multiply(percentage.toBigInteger())
|
||||
.divide(BigInteger("100"))
|
||||
val increasedAmount = this.amount.copy(
|
||||
value = increaseGasLimit.toBigDecimal().multiply(increasedGasPrice).movePointLeft(this.amount.decimals),
|
||||
)
|
||||
return this.copy(
|
||||
amount = increasedAmount,
|
||||
gasLimit = increaseGasLimit,
|
||||
)
|
||||
}
|
||||
|
||||
private fun hasOutgoingTransaction(cryptoCurrencyStatuses: CryptoCurrencyStatus): Boolean {
|
||||
return cryptoCurrencyStatuses.value.pendingTransactions.any { it.isOutgoing }
|
||||
}
|
||||
|
|
@ -1377,6 +1391,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
companion object {
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private const val INCREASE_GAS_LIMIT_BY = 112 // 12%
|
||||
private const val INCREASE_GAS_LIMIT_FOR_SEND = 105 // 5%
|
||||
private const val INFINITY_SYMBOL = "∞"
|
||||
|
||||
private val ONE_INCH_SUPPORTED_NETWORKS = listOf(
|
||||
|
|
|
|||
|
|
@ -394,12 +394,21 @@ internal class StateBuilder(
|
|||
swapProvider: SwapProvider,
|
||||
fromToken: TokenSwapInfo,
|
||||
toToken: CryptoCurrencyStatus?,
|
||||
includeFeeInAmount: IncludeFeeInAmount,
|
||||
dataError: DataError,
|
||||
isReverseSwapPossible: Boolean,
|
||||
): SwapStateHolder {
|
||||
if (uiStateHolder.sendCardData !is SwapCardState.SwapCardData) return uiStateHolder
|
||||
if (uiStateHolder.receiveCardData !is SwapCardState.SwapCardData) return uiStateHolder
|
||||
val warning = getWarningForError(dataError, fromToken.cryptoCurrencyStatus.currency)
|
||||
val warnings = mutableListOf<SwapWarning>()
|
||||
warnings.add(getWarningForError(dataError, fromToken.cryptoCurrencyStatus.currency))
|
||||
if (includeFeeInAmount is IncludeFeeInAmount.Included) {
|
||||
warnings.add(
|
||||
SwapWarning.GeneralWarning(
|
||||
createNetworkFeeCoverageNotificationConfig(),
|
||||
),
|
||||
)
|
||||
}
|
||||
val providerState = getProviderStateForError(
|
||||
swapProvider = swapProvider,
|
||||
fromToken = fromToken.cryptoCurrencyStatus.currency,
|
||||
|
|
@ -437,7 +446,7 @@ internal class StateBuilder(
|
|||
amountEquivalent = getFormattedFiatAmount(fromToken.amountFiat),
|
||||
),
|
||||
receiveCardData = receiveCardData,
|
||||
warnings = listOf(warning),
|
||||
warnings = warnings,
|
||||
permissionState = SwapPermissionState.Empty,
|
||||
fee = FeeItemState.Empty,
|
||||
swapButton = SwapButton(
|
||||
|
|
@ -1221,7 +1230,7 @@ internal class StateBuilder(
|
|||
}
|
||||
|
||||
private fun SwapAmount.getFormattedCryptoAmount(token: CryptoCurrency): String {
|
||||
return "${this.formatToUIRepresentation()} ${token.network.currencySymbol}"
|
||||
return "${this.formatToUIRepresentation()} ${token.symbol}"
|
||||
}
|
||||
|
||||
private fun BigDecimal.calculateRate(to: BigDecimal, decimals: Int): BigDecimal {
|
||||
|
|
|
|||
|
|
@ -344,6 +344,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
fromToken = state.fromTokenInfo,
|
||||
toToken = dataState.toCryptoCurrency,
|
||||
dataError = state.error,
|
||||
includeFeeInAmount = state.includeFeeInAmount,
|
||||
isReverseSwapPossible = isReverseSwapPossible(),
|
||||
)
|
||||
sendErrorAnalyticsEvent(state.error, provider)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue