Updated on 2026-08-14
This commit is contained in:
parent
7e35a4de75
commit
c0471dbf9f
20 changed files with 315 additions and 133 deletions
|
|
@ -8,6 +8,7 @@ import com.tangem.feature.swap.domain.models.createFromAmountWithOffset
|
|||
import com.tangem.feature.swap.domain.models.domain.ExpressTransactionModel
|
||||
import com.tangem.feature.swap.domain.models.domain.SwapDataModel
|
||||
import com.tangem.utils.converter.Converter
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class ExpressDataConverter : Converter<ExchangeDataResponseWithTxDetails, SwapDataModel> {
|
||||
|
||||
|
|
@ -24,19 +25,30 @@ internal class ExpressDataConverter : Converter<ExchangeDataResponseWithTxDetail
|
|||
dataResponse: ExchangeDataResponse,
|
||||
): ExpressTransactionModel {
|
||||
return if (transactionDto.txType == TxType.SWAP) {
|
||||
val otherNativeFeeWei = transactionDto.otherNativeFee?.let {
|
||||
if (it == "0") {
|
||||
BigDecimal.ZERO
|
||||
} else {
|
||||
requireNotNull(it.toBigDecimalOrNull()) { "wrong amount format, use only digits" }
|
||||
}
|
||||
}
|
||||
ExpressTransactionModel.DEX(
|
||||
fromAmount = createFromAmountWithOffset(dataResponse.fromAmount, dataResponse.fromDecimals),
|
||||
toAmount = createFromAmountWithOffset(dataResponse.toAmount, dataResponse.toDecimals),
|
||||
txValue = transactionDto.txValue,
|
||||
txId = dataResponse.txId,
|
||||
txTo = transactionDto.txTo,
|
||||
txFrom = requireNotNull(transactionDto.txFrom),
|
||||
txData = requireNotNull(transactionDto.txData),
|
||||
txExtraId = transactionDto.txExtraId,
|
||||
otherNativeFeeWei = otherNativeFeeWei,
|
||||
gas = transactionDto.gas?.toBigIntegerOrNull() ?: error("gas is empty"),
|
||||
)
|
||||
} else {
|
||||
ExpressTransactionModel.CEX(
|
||||
fromAmount = createFromAmountWithOffset(dataResponse.fromAmount, dataResponse.fromDecimals),
|
||||
toAmount = createFromAmountWithOffset(dataResponse.toAmount, dataResponse.toDecimals),
|
||||
txValue = transactionDto.txValue,
|
||||
txId = dataResponse.txId,
|
||||
txTo = transactionDto.txTo,
|
||||
externalTxId = requireNotNull(transactionDto.externalTxId),
|
||||
|
|
|
|||
|
|
@ -1,28 +1,38 @@
|
|||
package com.tangem.feature.swap.domain.models.domain
|
||||
|
||||
import com.tangem.feature.swap.domain.models.SwapAmount
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
|
||||
sealed class ExpressTransactionModel {
|
||||
|
||||
abstract val fromAmount: SwapAmount
|
||||
abstract val toAmount: SwapAmount
|
||||
abstract val txValue: String
|
||||
abstract val txId: String
|
||||
abstract val txTo: String
|
||||
abstract val txExtraId: String?
|
||||
|
||||
/**
|
||||
* @param txValue amount for tx, should use native coin decimals, this value will send as native amount in tx
|
||||
*/
|
||||
data class DEX(
|
||||
override val fromAmount: SwapAmount,
|
||||
override val toAmount: SwapAmount,
|
||||
override val txValue: String,
|
||||
override val txId: String,
|
||||
override val txTo: String,
|
||||
override val txExtraId: String?,
|
||||
val txFrom: String,
|
||||
val txData: String,
|
||||
val otherNativeFeeWei: BigDecimal?,
|
||||
val gas: BigInteger,
|
||||
) : ExpressTransactionModel()
|
||||
|
||||
data class CEX(
|
||||
override val fromAmount: SwapAmount,
|
||||
override val toAmount: SwapAmount,
|
||||
override val txValue: String,
|
||||
override val txId: String,
|
||||
override val txTo: String,
|
||||
override val txExtraId: String?,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ import java.math.BigDecimal
|
|||
|
||||
sealed interface SwapState {
|
||||
|
||||
/**
|
||||
* @param txFee fee state uses for calculation and build transaction
|
||||
* @param txFeeIncludeOtherNativeFee fee state uses for display and included otherNativeFee (specific for bridge)
|
||||
*/
|
||||
data class QuotesLoadedState(
|
||||
val fromTokenInfo: TokenSwapInfo,
|
||||
val toTokenInfo: TokenSwapInfo,
|
||||
|
|
@ -22,7 +26,9 @@ sealed interface SwapState {
|
|||
val permissionState: PermissionDataState = PermissionDataState.Empty,
|
||||
val swapDataModel: SwapDataModel? = null,
|
||||
val txFee: TxFeeState,
|
||||
// val txFeeIncludeOtherNativeFee: TxFeeState,
|
||||
val warnings: List<Warning> = emptyList(),
|
||||
val swapProvider: SwapProvider,
|
||||
) : SwapState
|
||||
|
||||
data class EmptyAmountState(val zeroAmountEquivalent: String) : SwapState
|
||||
|
|
@ -102,6 +108,9 @@ data class TxFee(
|
|||
val gasLimit: Int,
|
||||
val feeFiatFormatted: String,
|
||||
val feeCryptoFormatted: String,
|
||||
val feeIncludeOtherNativeFee: BigDecimal,
|
||||
val feeFiatFormattedWithNative: String,
|
||||
val feeCryptoFormattedWithNative: String,
|
||||
val decimals: Int,
|
||||
val cryptoSymbol: String,
|
||||
val feeType: FeeType,
|
||||
|
|
|
|||
|
|
@ -4,8 +4,11 @@ import arrow.core.Either
|
|||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.AmountType
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.blockchainsdk.utils.minimalAmount
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
|
|
@ -15,10 +18,8 @@ import com.tangem.domain.appcurrency.extenstions.unwrap
|
|||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyStatusesSyncUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.*
|
||||
import com.tangem.domain.tokens.model.FeePaidCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
|
|
@ -342,7 +343,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
)
|
||||
} else {
|
||||
provider to getQuotesState(
|
||||
exchangeProviderType = provider.type,
|
||||
provider = provider,
|
||||
quoteDataModel = quotes,
|
||||
amount = amount,
|
||||
fromToken = fromToken,
|
||||
|
|
@ -366,7 +367,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
isBalanceWithoutFeeEnough: Boolean,
|
||||
): Pair<SwapProvider, SwapState> {
|
||||
return provider to loadCexQuoteData(
|
||||
exchangeProviderType = ExchangeProviderType.CEX,
|
||||
networkId = networkId,
|
||||
amount = amount,
|
||||
fromTokenStatus = fromToken,
|
||||
|
|
@ -595,8 +595,8 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
swapData = requireNotNull(swapData),
|
||||
currencyToSendStatus = currencyToSend,
|
||||
currencyToGetStatus = currencyToGet,
|
||||
amountToSwap = amountToSwap,
|
||||
fee = fee,
|
||||
amountToSwap = amountToSwap,
|
||||
userWalletId = requireNotNull(getSelectedWallet()).walletId,
|
||||
)
|
||||
}
|
||||
|
|
@ -622,8 +622,8 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
)
|
||||
val fee = when (val txFee = state.txFee) {
|
||||
TxFeeState.Empty -> BigDecimal.ZERO
|
||||
is TxFeeState.MultipleFeeState -> txFee.priorityFee.feeValue
|
||||
is TxFeeState.SingleFeeState -> txFee.fee.feeValue
|
||||
is TxFeeState.MultipleFeeState -> txFee.priorityFee.feeIncludeOtherNativeFee
|
||||
is TxFeeState.SingleFeeState -> txFee.fee.feeIncludeOtherNativeFee
|
||||
}
|
||||
val feeState = getFeeState(
|
||||
fee = fee,
|
||||
|
|
@ -656,8 +656,9 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
val derivationPath = currencyToSendStatus.currency.network.derivationPath.value
|
||||
val dexTransaction = swapData.transaction as ExpressTransactionModel.DEX
|
||||
val dataToSign = dexTransaction.txData
|
||||
val amountToSend = createNativeAmountForDex(swapData.transaction.txValue, currencyToSendStatus.currency.network)
|
||||
val txData = createTransactionUseCase(
|
||||
amount = amount.value.convertToAmount(currencyToSendStatus.currency),
|
||||
amount = amountToSend,
|
||||
fee = getFeeForTransaction(
|
||||
fee = fee,
|
||||
blockchain = Blockchain.fromId(currencyToSendStatus.currency.network.id.value),
|
||||
|
|
@ -668,7 +669,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
network = currencyToSendStatus.currency.network,
|
||||
txExtras = createDexTxExtras(fee.gasLimit, dataToSign),
|
||||
hash = dataToSign,
|
||||
isSwap = true,
|
||||
).getOrElse {
|
||||
Timber.e(it)
|
||||
return SwapTransactionState.UnknownError
|
||||
|
|
@ -984,7 +984,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
*/
|
||||
@Suppress("LongParameterList")
|
||||
private suspend fun loadCexQuoteData(
|
||||
exchangeProviderType: ExchangeProviderType,
|
||||
networkId: String,
|
||||
amount: SwapAmount,
|
||||
fromTokenStatus: CryptoCurrencyStatus,
|
||||
|
|
@ -1035,7 +1034,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
)
|
||||
|
||||
getQuotesState(
|
||||
exchangeProviderType = exchangeProviderType,
|
||||
provider = provider,
|
||||
quoteDataModel = quotes,
|
||||
amount = amount,
|
||||
fromToken = fromTokenStatus,
|
||||
|
|
@ -1052,7 +1051,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
|
||||
@Suppress("LongMethod")
|
||||
private suspend fun getQuotesState(
|
||||
exchangeProviderType: ExchangeProviderType,
|
||||
provider: SwapProvider,
|
||||
quoteDataModel: Either<DataError, QuoteModel>,
|
||||
amount: SwapAmount,
|
||||
fromToken: CryptoCurrencyStatus,
|
||||
|
|
@ -1074,6 +1073,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
toTokenAmount = quoteModel.toTokenAmount,
|
||||
swapData = null,
|
||||
txFeeState = txFee,
|
||||
provider = provider,
|
||||
).copy(
|
||||
warnings = manageWarnings(
|
||||
fromTokenStatus = fromToken,
|
||||
|
|
@ -1083,7 +1083,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
),
|
||||
)
|
||||
|
||||
when (exchangeProviderType) {
|
||||
when (provider.type) {
|
||||
ExchangeProviderType.DEX, ExchangeProviderType.DEX_BRIDGE -> {
|
||||
val state = updatePermissionState(
|
||||
networkId = networkId,
|
||||
|
|
@ -1147,8 +1147,8 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
): IncludeFeeInAmount {
|
||||
val feeValue = when (txFee) {
|
||||
TxFeeState.Empty -> BigDecimal.ZERO
|
||||
is TxFeeState.MultipleFeeState -> txFee.priorityFee.feeValue
|
||||
is TxFeeState.SingleFeeState -> txFee.fee.feeValue
|
||||
is TxFeeState.MultipleFeeState -> txFee.priorityFee.feeIncludeOtherNativeFee
|
||||
is TxFeeState.SingleFeeState -> txFee.fee.feeIncludeOtherNativeFee
|
||||
}
|
||||
val feePaidCurrency = getFeePaidCurrency(
|
||||
userWalletId = requireNotNull(getSelectedWallet()).walletId,
|
||||
|
|
@ -1254,29 +1254,35 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
providerId = provider.providerId,
|
||||
rateType = RateType.FLOAT,
|
||||
toAddress = toToken.value.networkAddress?.defaultAddress?.value.orEmpty(),
|
||||
refundAddress = fromToken.value.networkAddress?.defaultAddress?.value,
|
||||
).fold(
|
||||
ifRight = { swapData ->
|
||||
val feeData = transactionManager.getFee(
|
||||
networkId = networkId,
|
||||
amountToSend = amount.value,
|
||||
currencyToSend = swapCurrencyConverter.convert(fromToken.currency),
|
||||
destinationAddress = swapData.transaction.txTo,
|
||||
increaseBy = INCREASE_GAS_LIMIT_BY,
|
||||
data = (swapData.transaction as ExpressTransactionModel.DEX).txData,
|
||||
derivationPath = fromToken.currency.network.derivationPath.value,
|
||||
)
|
||||
val txFeeState = when (feeData) {
|
||||
is ProxyFees.MultipleFees -> feeData.proxyFeesToFeeState(fromToken.currency)
|
||||
is ProxyFees.SingleFee -> feeData.proxyFeesToFeeState(fromToken.currency)
|
||||
val transaction = swapData.transaction as ExpressTransactionModel.DEX
|
||||
val nativeCoinDecimals = Blockchain.fromNetworkId(networkId)?.decimals()
|
||||
?: error("Blockchain not found")
|
||||
val otherNativeFee = transaction.otherNativeFeeWei
|
||||
?.movePointLeft(nativeCoinDecimals)
|
||||
?: BigDecimal.ZERO
|
||||
val txFeeState = when (val feeData = getFeeDataForDexSwap(networkId, transaction, fromToken.currency)) {
|
||||
is ProxyFees.MultipleFees -> feeData.proxyFeesToFeeState(fromToken.currency, otherNativeFee)
|
||||
is ProxyFees.SingleFee -> feeData.proxyFeesToFeeState(fromToken.currency, otherNativeFee)
|
||||
}
|
||||
val feeByPriority = selectFeeByType(feeType = selectedFee, txFeeState = txFeeState)
|
||||
val isBalanceIncludeFeeEnough = isBalanceEnough(fromToken, amount, feeByPriority)
|
||||
val feeToCheckFunds = feeByPriority + (otherNativeFee ?: BigDecimal.ZERO)
|
||||
val isBalanceIncludeFeeEnough = isBalanceEnough(fromToken, amount, feeToCheckFunds)
|
||||
val feeState = getFeeState(
|
||||
fee = feeByPriority,
|
||||
spendAmount = amount,
|
||||
networkId = networkId,
|
||||
fromTokenStatus = fromToken,
|
||||
)
|
||||
val preparedSwapConfigState = PreparedSwapConfigState(
|
||||
isAllowedToSpend = true,
|
||||
isBalanceEnough = isBalanceIncludeFeeEnough,
|
||||
feeState = feeState,
|
||||
hasOutgoingTransaction = hasOutgoingTransaction(fromToken),
|
||||
includeFeeInAmount = IncludeFeeInAmount.Excluded, // exclude for dex
|
||||
)
|
||||
val swapState = updateBalances(
|
||||
networkId = networkId,
|
||||
fromTokenStatus = fromToken,
|
||||
|
|
@ -1285,6 +1291,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
toTokenAmount = swapData.toTokenAmount,
|
||||
swapData = swapData,
|
||||
txFeeState = txFeeState,
|
||||
provider = provider,
|
||||
)
|
||||
swapState.copy(
|
||||
permissionState = PermissionDataState.Empty,
|
||||
|
|
@ -1292,17 +1299,9 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
fromTokenStatus = fromToken,
|
||||
amount = amount,
|
||||
feeState = txFeeState,
|
||||
minAdaValue = (feeData as? ProxyFees.SingleFee)?.let {
|
||||
(it.singleFee as? ProxyFee.CardanoToken)?.minAdaValue
|
||||
},
|
||||
),
|
||||
preparedSwapConfigState = PreparedSwapConfigState(
|
||||
isAllowedToSpend = true,
|
||||
isBalanceEnough = isBalanceIncludeFeeEnough,
|
||||
feeState = feeState,
|
||||
hasOutgoingTransaction = hasOutgoingTransaction(fromToken),
|
||||
includeFeeInAmount = IncludeFeeInAmount.Excluded, // exclude for dex
|
||||
minAdaValue = null, // no ADA in DEX
|
||||
),
|
||||
preparedSwapConfigState = preparedSwapConfigState,
|
||||
)
|
||||
},
|
||||
ifLeft = { error ->
|
||||
|
|
@ -1322,8 +1321,42 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun getFeeDataForDexSwap(
|
||||
networkId: String,
|
||||
transaction: ExpressTransactionModel.DEX,
|
||||
fromToken: CryptoCurrency,
|
||||
): ProxyFees {
|
||||
return try {
|
||||
val nativeBalance = userWalletManager.getNativeTokenBalance(
|
||||
networkId = networkId,
|
||||
derivationPath = fromToken.network.derivationPath.value,
|
||||
) ?: ProxyAmount.empty()
|
||||
val amountToSend = createNativeAmountForDex(transaction.txValue, fromToken.network)
|
||||
// transaction.txValue is always native coin
|
||||
if (nativeBalance.value < amountToSend.value) {
|
||||
error("It's impossible to calculate fee for nativeBalance.value < amountToSend.value")
|
||||
}
|
||||
transactionManager.getFee(
|
||||
networkId = networkId,
|
||||
amountToSend = amountToSend,
|
||||
currencyToSend = swapCurrencyConverter.convert(fromToken),
|
||||
destinationAddress = transaction.txTo,
|
||||
increaseBy = INCREASE_GAS_LIMIT_BY,
|
||||
data = transaction.txData,
|
||||
derivationPath = fromToken.network.derivationPath.value,
|
||||
)
|
||||
} catch (e: IllegalStateException) {
|
||||
transactionManager.getFeeForGas(
|
||||
networkId = networkId,
|
||||
gas = transaction.gas,
|
||||
derivationPath = fromToken.network.derivationPath.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
private suspend fun updateBalances(
|
||||
provider: SwapProvider,
|
||||
networkId: String,
|
||||
fromTokenStatus: CryptoCurrencyStatus,
|
||||
toTokenStatus: CryptoCurrencyStatus,
|
||||
|
|
@ -1335,7 +1368,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
val fromToken = fromTokenStatus.currency
|
||||
val toToken = toTokenStatus.currency
|
||||
val nativeToken = repository.getNativeTokenForNetwork(networkId)
|
||||
|
||||
val rates = getQuotes(fromToken.id, toToken.id, nativeToken.id)
|
||||
return SwapState.QuotesLoadedState(
|
||||
fromTokenInfo = TokenSwapInfo(
|
||||
|
|
@ -1358,6 +1390,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
),
|
||||
swapDataModel = swapData,
|
||||
txFee = txFeeState,
|
||||
swapProvider = provider,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -1367,7 +1400,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
): TxFeeState {
|
||||
return txFeeResult?.fold(
|
||||
ifLeft = { TxFeeState.Empty },
|
||||
ifRight = { txFee -> txFee.toTxFeeState(fromToken.currency) },
|
||||
ifRight = { txFee -> txFee.toTxFeeState(fromToken.currency, null) },
|
||||
) ?: TxFeeState.Empty
|
||||
}
|
||||
|
||||
|
|
@ -1427,7 +1460,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
try {
|
||||
transactionManager.getFee(
|
||||
networkId = networkId,
|
||||
amountToSend = BigDecimal.ZERO,
|
||||
amountToSend = createNativeAmountForDex("0", fromToken.network),
|
||||
currencyToSend = swapCurrencyConverter.convert(repository.getNativeTokenForNetwork(networkId)),
|
||||
destinationAddress = fromToken.getContractAddress(),
|
||||
increaseBy = INCREASE_GAS_LIMIT_BY,
|
||||
|
|
@ -1475,11 +1508,16 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun ProxyFees.MultipleFees.proxyFeesToFeeState(fromToken: CryptoCurrency): TxFeeState {
|
||||
private suspend fun ProxyFees.MultipleFees.proxyFeesToFeeState(
|
||||
fromToken: CryptoCurrency,
|
||||
otherNativeFee: BigDecimal? = null,
|
||||
): TxFeeState {
|
||||
val otherNativeFeeValue = otherNativeFee ?: BigDecimal.ZERO
|
||||
val normalFeeValue = this.minFee.fee.value // in swap for normal use min fee
|
||||
val normalFeeGas = this.minFee.gasLimit.toInt()
|
||||
val priorityFeeValue = this.normalFee.fee.value // in swap for priority use normal fee
|
||||
val priorityFeeGas = this.normalFee.gasLimit.toInt()
|
||||
// region fees to use
|
||||
val feesFiat = getFormattedFiatFees(fromToken, normalFeeValue, priorityFeeValue)
|
||||
val normalFiatFee = requireNotNull(feesFiat.getOrNull(0)) { "feesFiat item 0 couldn't be null" }
|
||||
val priorityFiatFee = requireNotNull(feesFiat.getOrNull(1)) { "feesFiat item 1 couldn't be null" }
|
||||
|
|
@ -1491,12 +1529,35 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
amount = priorityFeeValue,
|
||||
decimals = normalFee.fee.decimals,
|
||||
)
|
||||
//
|
||||
// region fees include otherNativeFee
|
||||
val feesFiatWithNative = getFormattedFiatFees(
|
||||
fromToken = fromToken,
|
||||
normalFeeValue + otherNativeFeeValue,
|
||||
priorityFeeValue + otherNativeFeeValue,
|
||||
)
|
||||
val normalFiatFeeWithNative =
|
||||
requireNotNull(feesFiatWithNative.getOrNull(0)) { "feesFiat item 0 couldn't be null" }
|
||||
val priorityFiatFeeWithNative =
|
||||
requireNotNull(feesFiatWithNative.getOrNull(1)) { "feesFiat item 1 couldn't be null" }
|
||||
val normalCryptoFeeWithNative = amountFormatter.formatBigDecimalAmountToUI(
|
||||
amount = normalFeeValue + otherNativeFeeValue,
|
||||
decimals = minFee.fee.decimals,
|
||||
)
|
||||
val priorityCryptoFeeWithNative = amountFormatter.formatBigDecimalAmountToUI(
|
||||
amount = priorityFeeValue + otherNativeFeeValue,
|
||||
decimals = normalFee.fee.decimals,
|
||||
)
|
||||
//
|
||||
return TxFeeState.MultipleFeeState(
|
||||
normalFee = TxFee(
|
||||
feeValue = normalFeeValue,
|
||||
gasLimit = normalFeeGas,
|
||||
feeFiatFormatted = normalFiatFee,
|
||||
feeCryptoFormatted = normalCryptoFee,
|
||||
feeIncludeOtherNativeFee = normalFeeValue + otherNativeFeeValue,
|
||||
feeFiatFormattedWithNative = normalFiatFeeWithNative,
|
||||
feeCryptoFormattedWithNative = normalCryptoFeeWithNative,
|
||||
decimals = minFee.fee.decimals,
|
||||
cryptoSymbol = minFee.fee.currencySymbol,
|
||||
feeType = FeeType.NORMAL,
|
||||
|
|
@ -1506,6 +1567,9 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
gasLimit = priorityFeeGas,
|
||||
feeFiatFormatted = priorityFiatFee,
|
||||
feeCryptoFormatted = priorityCryptoFee,
|
||||
feeIncludeOtherNativeFee = priorityFeeValue + otherNativeFeeValue,
|
||||
feeFiatFormattedWithNative = priorityFiatFeeWithNative,
|
||||
feeCryptoFormattedWithNative = priorityCryptoFeeWithNative,
|
||||
decimals = normalFee.fee.decimals,
|
||||
cryptoSymbol = normalFee.fee.currencySymbol,
|
||||
feeType = FeeType.PRIORITY,
|
||||
|
|
@ -1513,7 +1577,11 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun ProxyFees.SingleFee.proxyFeesToFeeState(fromToken: CryptoCurrency): TxFeeState {
|
||||
private suspend fun ProxyFees.SingleFee.proxyFeesToFeeState(
|
||||
fromToken: CryptoCurrency,
|
||||
otherNativeFee: BigDecimal? = null,
|
||||
): TxFeeState {
|
||||
val otherNativeFeeValue = otherNativeFee ?: BigDecimal.ZERO
|
||||
val normalFeeValue = this.singleFee.fee.value
|
||||
val normalFeeGas = this.singleFee.gasLimit.toInt()
|
||||
val feesFiat = getFormattedFiatFees(fromToken, normalFeeValue)
|
||||
|
|
@ -1522,12 +1590,28 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
amount = normalFeeValue,
|
||||
decimals = singleFee.fee.decimals,
|
||||
)
|
||||
// region fees include otherNativeFee
|
||||
val feesFiatWithNative = getFormattedFiatFees(
|
||||
fromToken = fromToken,
|
||||
normalFeeValue + otherNativeFeeValue,
|
||||
normalFeeValue + otherNativeFeeValue,
|
||||
)
|
||||
val normalFiatFeeWithNative =
|
||||
requireNotNull(feesFiatWithNative.getOrNull(0)) { "feesFiat item 0 couldn't be null" }
|
||||
val normalCryptoFeeWithNative = amountFormatter.formatBigDecimalAmountToUI(
|
||||
amount = normalFeeValue + otherNativeFeeValue,
|
||||
decimals = singleFee.fee.decimals,
|
||||
)
|
||||
//
|
||||
return TxFeeState.SingleFeeState(
|
||||
fee = TxFee(
|
||||
feeValue = normalFeeValue,
|
||||
gasLimit = normalFeeGas,
|
||||
feeFiatFormatted = normalFiatFee,
|
||||
feeCryptoFormatted = normalCryptoFee,
|
||||
feeIncludeOtherNativeFee = normalFeeValue + otherNativeFeeValue,
|
||||
feeFiatFormattedWithNative = normalFiatFeeWithNative,
|
||||
feeCryptoFormattedWithNative = normalCryptoFeeWithNative,
|
||||
decimals = singleFee.fee.decimals,
|
||||
cryptoSymbol = singleFee.fee.currencySymbol,
|
||||
feeType = FeeType.NORMAL,
|
||||
|
|
@ -1535,7 +1619,12 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun TransactionFee.toTxFeeState(fromToken: CryptoCurrency): TxFeeState {
|
||||
@Suppress("LongMethod")
|
||||
private suspend fun TransactionFee.toTxFeeState(
|
||||
fromToken: CryptoCurrency,
|
||||
otherNativeFee: BigDecimal?,
|
||||
): TxFeeState {
|
||||
val otherNativeFeeValue = otherNativeFee ?: BigDecimal.ZERO
|
||||
return when (this) {
|
||||
is TransactionFee.Choosable -> {
|
||||
val normalFee = this.normal.increaseGasLimitBy(INCREASE_GAS_LIMIT_FOR_SEND)
|
||||
|
|
@ -1553,12 +1642,31 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
amount = feePriority,
|
||||
decimals = priorityFee.amount.decimals,
|
||||
)
|
||||
|
||||
// region otherNativeFee
|
||||
val normalFeeWithOtherNative = feeNormal + otherNativeFeeValue
|
||||
val priorityFeeWithOtherNative = feeNormal + otherNativeFeeValue
|
||||
val normalFiatValueWithNative = getFormattedFiatFees(fromToken, normalFeeWithOtherNative)[0]
|
||||
val priorityFiatValueWithNative = getFormattedFiatFees(fromToken, priorityFeeWithOtherNative)[0]
|
||||
|
||||
val normalCryptoFeeWithNative = amountFormatter.formatBigDecimalAmountToUI(
|
||||
amount = normalFeeWithOtherNative,
|
||||
decimals = normalFee.amount.decimals,
|
||||
)
|
||||
val priorityCryptoFeeWithNative = amountFormatter.formatBigDecimalAmountToUI(
|
||||
amount = priorityFeeWithOtherNative,
|
||||
decimals = priorityFee.amount.decimals,
|
||||
)
|
||||
//
|
||||
TxFeeState.MultipleFeeState(
|
||||
normalFee = TxFee(
|
||||
feeValue = feeNormal,
|
||||
gasLimit = normalFee.getGasLimit(),
|
||||
feeFiatFormatted = normalFiatValue,
|
||||
feeCryptoFormatted = normalCryptoFee,
|
||||
feeIncludeOtherNativeFee = normalFeeWithOtherNative,
|
||||
feeFiatFormattedWithNative = normalFiatValueWithNative,
|
||||
feeCryptoFormattedWithNative = normalCryptoFeeWithNative,
|
||||
decimals = normalFee.amount.decimals,
|
||||
cryptoSymbol = normalFee.amount.currencySymbol,
|
||||
feeType = FeeType.NORMAL,
|
||||
|
|
@ -1568,6 +1676,9 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
gasLimit = priorityFee.getGasLimit(),
|
||||
feeFiatFormatted = priorityFiatValue,
|
||||
feeCryptoFormatted = priorityCryptoFee,
|
||||
feeIncludeOtherNativeFee = priorityFeeWithOtherNative,
|
||||
feeFiatFormattedWithNative = priorityFiatValueWithNative,
|
||||
feeCryptoFormattedWithNative = priorityCryptoFeeWithNative,
|
||||
decimals = priorityFee.amount.decimals,
|
||||
cryptoSymbol = priorityFee.amount.currencySymbol,
|
||||
feeType = FeeType.PRIORITY,
|
||||
|
|
@ -1581,12 +1692,24 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
amount = feeNormal,
|
||||
decimals = this.normal.amount.decimals,
|
||||
)
|
||||
// region otherNativeFee
|
||||
val normalFeeWithOtherNative = feeNormal + otherNativeFeeValue
|
||||
val normalFiatValueWithNative = getFormattedFiatFees(fromToken, normalFeeWithOtherNative)[0]
|
||||
|
||||
val normalCryptoFeeWithNative = amountFormatter.formatBigDecimalAmountToUI(
|
||||
amount = normalFeeWithOtherNative,
|
||||
decimals = this.normal.amount.decimals,
|
||||
)
|
||||
//
|
||||
TxFeeState.SingleFeeState(
|
||||
fee = TxFee(
|
||||
feeValue = this.normal.amount.value ?: BigDecimal.ZERO,
|
||||
gasLimit = this.normal.getGasLimit(),
|
||||
feeFiatFormatted = normalFiatValue,
|
||||
feeCryptoFormatted = normalCryptoFee,
|
||||
feeIncludeOtherNativeFee = normalFeeWithOtherNative,
|
||||
feeFiatFormattedWithNative = normalFiatValueWithNative,
|
||||
feeCryptoFormattedWithNative = normalCryptoFeeWithNative,
|
||||
decimals = normal.amount.decimals,
|
||||
cryptoSymbol = normal.amount.currencySymbol,
|
||||
feeType = FeeType.NORMAL,
|
||||
|
|
@ -1596,6 +1719,18 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun createNativeAmountForDex(txValueAmount: String, network: Network): Amount {
|
||||
val nativeDecimals = Blockchain.fromNetworkId(network.backendId)?.decimals()
|
||||
?: error("Blockchain not found")
|
||||
val decimalValue = txValueAmount.toBigDecimalOrNull()?.movePointLeft(nativeDecimals)
|
||||
?: error("txValue parse error")
|
||||
return Amount(
|
||||
currencySymbol = network.currencySymbol,
|
||||
value = decimalValue,
|
||||
decimals = nativeDecimals,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Workaround to increase gas limit cause we calculate fee for random address
|
||||
*/
|
||||
|
|
@ -1656,7 +1791,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
if (fromToken.currency is CryptoCurrency.Token) {
|
||||
tokenBalance >= amount.value
|
||||
} else {
|
||||
tokenBalance > amount.value.plus(fee ?: BigDecimal.ZERO)
|
||||
tokenBalance >= amount.value.plus(fee ?: BigDecimal.ZERO)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ sealed class SwapPermissionState {
|
|||
object Empty : SwapPermissionState()
|
||||
|
||||
data class ReadyForRequest(
|
||||
val providerName: String,
|
||||
val currency: String,
|
||||
val amount: String,
|
||||
val walletAddress: String,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.feature.swap.models
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
|
|
@ -74,18 +73,21 @@ data class SwapButton(
|
|||
|
||||
sealed interface TransactionCardType {
|
||||
|
||||
val headerResId: Int
|
||||
val header: TextReference
|
||||
val isError: Boolean
|
||||
|
||||
data class Inputtable(
|
||||
val onAmountChanged: ((String) -> Unit),
|
||||
val onFocusChanged: ((Boolean) -> Unit),
|
||||
@StringRes override val headerResId: Int = R.string.swapping_from_title,
|
||||
override val isError: Boolean,
|
||||
override val header: TextReference = TextReference.Res(R.string.swapping_from_title),
|
||||
) : TransactionCardType
|
||||
|
||||
data class ReadOnly(
|
||||
val showWarning: Boolean = false,
|
||||
val onWarningClick: (() -> Unit)? = null,
|
||||
@StringRes override val headerResId: Int = R.string.swapping_to_title,
|
||||
override val isError: Boolean = false,
|
||||
override val header: TextReference = TextReference.Res(R.string.swapping_to_title),
|
||||
) : TransactionCardType
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +104,7 @@ data class LegalState(
|
|||
|
||||
sealed interface SwapWarning {
|
||||
data class PermissionNeeded(val notificationConfig: NotificationConfig) : SwapWarning
|
||||
object InsufficientFunds : SwapWarning
|
||||
data object InsufficientFunds : SwapWarning
|
||||
data class NoAvailableTokensToSwap(val notificationConfig: NotificationConfig) : SwapWarning
|
||||
data class GenericWarning(
|
||||
val title: TextReference? = null,
|
||||
|
|
|
|||
|
|
@ -51,7 +51,11 @@ internal class StateBuilder(
|
|||
return SwapStateHolder(
|
||||
blockchainId = networkInfo.blockchainId,
|
||||
sendCardData = SwapCardState.SwapCardData(
|
||||
type = TransactionCardType.Inputtable(actions.onAmountChanged, actions.onAmountSelected),
|
||||
type = TransactionCardType.Inputtable(
|
||||
onAmountChanged = actions.onAmountChanged,
|
||||
onFocusChanged = actions.onAmountSelected,
|
||||
isError = false,
|
||||
),
|
||||
amountEquivalent = null,
|
||||
amountTextFieldValue = null,
|
||||
token = null,
|
||||
|
|
@ -152,9 +156,13 @@ internal class StateBuilder(
|
|||
val canSelectReceiveToken = mainTokenId != toToken.id.value
|
||||
if (uiStateHolder.sendCardData !is SwapCardState.SwapCardData) return uiStateHolder
|
||||
if (uiStateHolder.receiveCardData !is SwapCardState.SwapCardData) return uiStateHolder
|
||||
val sendInput = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.Inputtable).copy(
|
||||
isError = false,
|
||||
header = TextReference.Res(R.string.swapping_from_title),
|
||||
)
|
||||
return uiStateHolder.copy(
|
||||
sendCardData = SwapCardState.SwapCardData(
|
||||
type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.Inputtable),
|
||||
type = sendInput,
|
||||
amountTextFieldValue = uiStateHolder.sendCardData.amountTextFieldValue,
|
||||
amountEquivalent = null,
|
||||
token = uiStateHolder.sendCardData.token,
|
||||
|
|
@ -221,9 +229,19 @@ internal class StateBuilder(
|
|||
val feeState = createFeeState(quoteModel.txFee, selectedFeeType)
|
||||
val fromCurrencyStatus = quoteModel.fromTokenInfo.cryptoCurrencyStatus
|
||||
val toCurrencyStatus = quoteModel.toTokenInfo.cryptoCurrencyStatus
|
||||
val isInsufficientFunds = isInsufficientFundsCondition(quoteModel)
|
||||
val insufficientFundsHeader = if (isInsufficientFunds) {
|
||||
TextReference.Res(R.string.swapping_insufficient_funds)
|
||||
} else {
|
||||
TextReference.Res(R.string.swapping_from_title)
|
||||
}
|
||||
val sendInput = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.Inputtable).copy(
|
||||
isError = isInsufficientFunds,
|
||||
header = insufficientFundsHeader,
|
||||
)
|
||||
return uiStateHolder.copy(
|
||||
sendCardData = SwapCardState.SwapCardData(
|
||||
type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.Inputtable),
|
||||
type = sendInput,
|
||||
amountTextFieldValue = uiStateHolder.sendCardData.amountTextFieldValue,
|
||||
amountEquivalent = getFormattedFiatAmount(quoteModel.fromTokenInfo.amountFiat),
|
||||
token = fromCurrencyStatus,
|
||||
|
|
@ -257,6 +275,7 @@ internal class StateBuilder(
|
|||
permissionState = convertPermissionState(
|
||||
lastPermissionState = uiStateHolder.permissionState,
|
||||
permissionDataState = quoteModel.permissionState,
|
||||
providerName = quoteModel.swapProvider.name,
|
||||
onGivePermissionClick = actions.onGivePermissionClick,
|
||||
onChangeApproveType = actions.onChangeApproveType,
|
||||
),
|
||||
|
|
@ -320,7 +339,7 @@ internal class StateBuilder(
|
|||
val warnings = mutableListOf<SwapWarning>()
|
||||
maybeAddDomainWarnings(quoteModel, warnings)
|
||||
maybeAddNeedReserveToCreateAccountWarning(quoteModel, warnings)
|
||||
maybeAddPermissionNeededWarning(quoteModel, warnings, fromToken)
|
||||
maybeAddPermissionNeededWarning(quoteModel, warnings, fromToken, quoteModel.swapProvider.name)
|
||||
maybeAddNetworkFeeCoverageWarning(quoteModel, warnings, selectedFeeType)
|
||||
maybeAddUnableCoverFeeWarning(quoteModel, fromToken, warnings)
|
||||
maybeAddInsufficientFundsWarning(quoteModel, warnings)
|
||||
|
|
@ -468,6 +487,7 @@ internal class StateBuilder(
|
|||
quoteModel: SwapState.QuotesLoadedState,
|
||||
warnings: MutableList<SwapWarning>,
|
||||
fromToken: CryptoCurrency,
|
||||
providerName: String,
|
||||
) {
|
||||
if (!quoteModel.preparedSwapConfigState.isAllowedToSpend &&
|
||||
quoteModel.preparedSwapConfigState.feeState is SwapFeeState.Enough &&
|
||||
|
|
@ -475,7 +495,7 @@ internal class StateBuilder(
|
|||
) {
|
||||
warnings.add(
|
||||
SwapWarning.PermissionNeeded(
|
||||
createPermissionNotificationConfig(fromToken.symbol),
|
||||
createPermissionNotificationConfig(fromToken.symbol, providerName),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -493,8 +513,8 @@ internal class StateBuilder(
|
|||
warnings.add(
|
||||
SwapWarning.GeneralWarning(
|
||||
createNetworkFeeCoverageNotificationConfig(
|
||||
fee.feeCryptoFormatted,
|
||||
fee.feeFiatFormatted,
|
||||
fee.feeCryptoFormattedWithNative,
|
||||
fee.feeFiatFormattedWithNative,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -547,13 +567,16 @@ internal class StateBuilder(
|
|||
warnings: MutableList<SwapWarning>,
|
||||
) {
|
||||
// check isBalanceEnough, but for dex includeFeeInAmount always Excluded
|
||||
if (!quoteModel.preparedSwapConfigState.isBalanceEnough &&
|
||||
quoteModel.preparedSwapConfigState.includeFeeInAmount !is IncludeFeeInAmount.Included
|
||||
) {
|
||||
if (isInsufficientFundsCondition(quoteModel)) {
|
||||
warnings.add(SwapWarning.InsufficientFunds)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isInsufficientFundsCondition(quoteModel: SwapState.QuotesLoadedState): Boolean {
|
||||
return !quoteModel.preparedSwapConfigState.isBalanceEnough &&
|
||||
quoteModel.preparedSwapConfigState.includeFeeInAmount !is IncludeFeeInAmount.Included
|
||||
}
|
||||
|
||||
private fun getSwapButtonEnabled(quoteModel: SwapState.QuotesLoadedState): Boolean {
|
||||
val status = quoteModel.toTokenInfo.cryptoCurrencyStatus.value
|
||||
if (status is CryptoCurrencyStatus.NoAccount) {
|
||||
|
|
@ -964,9 +987,9 @@ internal class StateBuilder(
|
|||
return FeeItemState.Content(
|
||||
feeType = feeType,
|
||||
title = resourceReference(R.string.common_network_fee_title),
|
||||
amountCrypto = fee.feeCryptoFormatted,
|
||||
amountCrypto = fee.feeCryptoFormattedWithNative, // display fee with native as workaround for okx
|
||||
symbolCrypto = fee.cryptoSymbol,
|
||||
amountFiatFormatted = fee.feeFiatFormatted,
|
||||
amountFiatFormatted = fee.feeFiatFormattedWithNative, // display fee with native as workaround for okx
|
||||
isClickable = isClickable,
|
||||
onClick = actions.onClickFee,
|
||||
)
|
||||
|
|
@ -1017,7 +1040,7 @@ internal class StateBuilder(
|
|||
showStatusButton = shouldShowStatus,
|
||||
providerIcon = providerState.iconUrl,
|
||||
rate = providerState.subtitle,
|
||||
fee = stringReference("${fee.feeCryptoFormatted} (${fee.feeFiatFormatted})"),
|
||||
fee = stringReference("${fee.feeCryptoFormattedWithNative} (${fee.feeFiatFormattedWithNative})"),
|
||||
fromTokenAmount = stringReference(swapTransactionState.fromAmount.orEmpty()),
|
||||
toTokenAmount = stringReference(swapTransactionState.toAmount.orEmpty()),
|
||||
fromTokenFiatAmount = stringReference(fromFiatAmount),
|
||||
|
|
@ -1146,6 +1169,7 @@ internal class StateBuilder(
|
|||
private fun convertPermissionState(
|
||||
lastPermissionState: SwapPermissionState,
|
||||
permissionDataState: PermissionDataState,
|
||||
providerName: String,
|
||||
onGivePermissionClick: () -> Unit,
|
||||
onChangeApproveType: (ApproveType) -> Unit,
|
||||
): SwapPermissionState {
|
||||
|
|
@ -1165,6 +1189,7 @@ internal class StateBuilder(
|
|||
is TxFeeState.SingleFeeState -> fee.fee
|
||||
}
|
||||
SwapPermissionState.ReadyForRequest(
|
||||
providerName = providerName,
|
||||
currency = permissionDataState.currency,
|
||||
amount = permissionDataState.amount,
|
||||
approveType = approveType,
|
||||
|
|
@ -1358,18 +1383,18 @@ internal class StateBuilder(
|
|||
FeeItemState.Content(
|
||||
feeType = this.normalFee.feeType,
|
||||
title = resourceReference(R.string.common_network_fee_title),
|
||||
amountCrypto = this.normalFee.feeCryptoFormatted,
|
||||
amountCrypto = this.normalFee.feeCryptoFormattedWithNative,
|
||||
symbolCrypto = this.normalFee.cryptoSymbol,
|
||||
amountFiatFormatted = this.normalFee.feeFiatFormatted,
|
||||
amountFiatFormatted = this.normalFee.feeFiatFormattedWithNative,
|
||||
isClickable = true,
|
||||
onClick = {},
|
||||
),
|
||||
FeeItemState.Content(
|
||||
feeType = this.priorityFee.feeType,
|
||||
title = resourceReference(R.string.common_network_fee_title),
|
||||
amountCrypto = this.priorityFee.feeCryptoFormatted,
|
||||
amountCrypto = this.priorityFee.feeCryptoFormattedWithNative,
|
||||
symbolCrypto = this.priorityFee.cryptoSymbol,
|
||||
amountFiatFormatted = this.priorityFee.feeFiatFormatted,
|
||||
amountFiatFormatted = this.priorityFee.feeFiatFormattedWithNative,
|
||||
isClickable = true,
|
||||
onClick = {},
|
||||
),
|
||||
|
|
@ -1402,12 +1427,12 @@ internal class StateBuilder(
|
|||
}
|
||||
|
||||
// region warnings
|
||||
private fun createPermissionNotificationConfig(fromTokenSymbol: String): NotificationConfig {
|
||||
private fun createPermissionNotificationConfig(fromTokenSymbol: String, providerName: String): NotificationConfig {
|
||||
return NotificationConfig(
|
||||
title = resourceReference(R.string.express_provider_permission_needed),
|
||||
subtitle = resourceReference(
|
||||
id = R.string.swapping_permission_subheader,
|
||||
formatArgs = wrappedList(fromTokenSymbol),
|
||||
formatArgs = wrappedList(providerName, fromTokenSymbol),
|
||||
),
|
||||
iconResId = R.drawable.ic_locked_24,
|
||||
)
|
||||
|
|
@ -1604,7 +1629,7 @@ internal class StateBuilder(
|
|||
id = this.providerId,
|
||||
name = this.name,
|
||||
iconUrl = this.imageLarge,
|
||||
type = this.type.toString(),
|
||||
type = this.type.providerName,
|
||||
selectionType = selectionType,
|
||||
alertText = alertText,
|
||||
onProviderClick = onProviderClick,
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ private fun SwapPermissionBottomSheetContent(content: GivePermissionBottomSheetC
|
|||
Text(
|
||||
text = stringResource(
|
||||
id = R.string.swapping_permission_subheader,
|
||||
data.providerName,
|
||||
data.currency,
|
||||
),
|
||||
color = TangemTheme.colors.text.secondary,
|
||||
|
|
@ -303,6 +304,7 @@ private fun Preview_AgreementBottomSheet() {
|
|||
|
||||
private val previewData = GivePermissionBottomSheetConfig(
|
||||
data = SwapPermissionState.ReadyForRequest(
|
||||
providerName = "1icnh",
|
||||
currency = "DAI",
|
||||
amount = "∞",
|
||||
walletAddress = "",
|
||||
|
|
|
|||
|
|
@ -434,7 +434,7 @@ private fun MainButton(state: SwapStateHolder, onPermissionWarningClick: () -> U
|
|||
// region preview
|
||||
|
||||
private val sendCard = SwapCardState.SwapCardData(
|
||||
type = TransactionCardType.Inputtable({}, {}),
|
||||
type = TransactionCardType.Inputtable({}, {}, false),
|
||||
amountTextFieldValue = TextFieldValue(),
|
||||
amountEquivalent = "1 000 000",
|
||||
tokenIconUrl = "",
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import coil.compose.SubcomposeAsyncImage
|
|||
import coil.request.ImageRequest
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.components.*
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.core.ui.utils.ImageBackgroundContrastChecker
|
||||
|
|
@ -185,10 +186,14 @@ private fun Header(type: TransactionCardType, balance: String, modifier: Modifie
|
|||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val title = type.headerResId
|
||||
val titleColor = if (type.isError) {
|
||||
TangemTheme.colors.text.warning
|
||||
} else {
|
||||
TangemTheme.colors.text.tertiary
|
||||
}
|
||||
Text(
|
||||
text = stringResource(id = title),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
text = type.header.resolveReference(),
|
||||
color = titleColor,
|
||||
maxLines = 1,
|
||||
style = MaterialTheme.typography.subtitle2,
|
||||
modifier = Modifier
|
||||
|
|
@ -546,7 +551,7 @@ private fun Preview_TransactionCardWithoutPriceImpact_InDarkTheme() {
|
|||
@Composable
|
||||
private fun TransactionCardPreview() {
|
||||
TransactionCard(
|
||||
type = TransactionCardType.Inputtable({}, {}),
|
||||
type = TransactionCardType.Inputtable({}, {}, false),
|
||||
amountEquivalent = "1 000 000",
|
||||
tokenIconUrl = "",
|
||||
tokenCurrency = "DAI",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue