Updated on 2026-08-14
This commit is contained in:
commit
b577c3c21b
11 changed files with 76 additions and 34 deletions
|
|
@ -20,6 +20,7 @@ import com.tangem.domain.common.extensions.fromNetworkId
|
|||
import com.tangem.lib.crypto.TransactionManager
|
||||
import com.tangem.lib.crypto.models.Currency
|
||||
import com.tangem.lib.crypto.models.ProxyAmount
|
||||
import com.tangem.lib.crypto.models.ProxyNetworkInfo
|
||||
import com.tangem.lib.crypto.models.transactions.SendTxResult
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.TangemSigner
|
||||
|
|
@ -148,8 +149,13 @@ class TransactionManagerImpl(
|
|||
}
|
||||
}
|
||||
|
||||
override fun getBlockchainId(networkId: String): String {
|
||||
return requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }.id
|
||||
override fun getBlockchainInfo(networkId: String): ProxyNetworkInfo {
|
||||
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
|
||||
return ProxyNetworkInfo(
|
||||
name = blockchain.fullName,
|
||||
blockchainId = blockchain.id,
|
||||
blockchainCurrency = blockchain.currency,
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleSendResult(result: SimpleResult): SendTxResult {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ package com.tangem.core.ui.utils
|
|||
*/
|
||||
fun getValidatedNumberWithFixedDecimals(text: String, decimals: Int): String {
|
||||
val filteredChars = text.filterIndexed { index, c ->
|
||||
c.isDigit()
|
||||
|| (c == '.' && index != 0 && text.indexOf('.') == index)
|
||||
|| (c == '.' && index != 0 && text.count { it == '.' } <= 1)
|
||||
val isOneOrZeroPoint = c == '.' && index != 0 && text.count { it == '.' } <= 1
|
||||
val isIndexPointIndex = c == '.' && index != 0 && text.indexOf('.') == index
|
||||
c.isDigit() || isIndexPointIndex || isOneOrZeroPoint
|
||||
}
|
||||
// If dot is present, take first 3 digits before decimal and first decimals digits after decimal
|
||||
return if (filteredChars.count { it == '.' } == 1) {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ class TokensConverter @Inject constructor() : Converter<CoinsResponse.Coin, Curr
|
|||
|
||||
companion object {
|
||||
private const val DEFAULT_IMAGE_HOST = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/"
|
||||
private const val SMALL_ICON_PATH = "small"
|
||||
private const val LARGE_ICON_PATH = "large"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.feature.swap.domain
|
||||
|
||||
import com.tangem.feature.swap.domain.models.domain.Currency
|
||||
import com.tangem.feature.swap.domain.models.domain.NetworkInfo
|
||||
|
||||
interface BlockchainInteractor {
|
||||
|
||||
|
|
@ -11,5 +12,5 @@ interface BlockchainInteractor {
|
|||
*
|
||||
* workaround till not use backend only and not integrated server vs sdk
|
||||
*/
|
||||
fun getBlockchainId(networkId: String): String
|
||||
fun getBlockchainInfo(networkId: String): NetworkInfo
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.feature.swap.domain
|
||||
|
||||
import com.tangem.feature.swap.domain.models.domain.Currency
|
||||
import com.tangem.feature.swap.domain.models.domain.NetworkInfo
|
||||
import com.tangem.lib.crypto.TransactionManager
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -8,8 +9,14 @@ internal class BlockchainInteractorImpl @Inject constructor(
|
|||
private val transactionManager: TransactionManager,
|
||||
) : BlockchainInteractor {
|
||||
|
||||
override fun getBlockchainId(networkId: String): String {
|
||||
return transactionManager.getBlockchainId(networkId)
|
||||
override fun getBlockchainInfo(networkId: String): NetworkInfo {
|
||||
return transactionManager.getBlockchainInfo(networkId).let {
|
||||
NetworkInfo(
|
||||
name = it.name,
|
||||
blockchainId = it.blockchainId,
|
||||
blockchainCurrency = it.blockchainCurrency,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTokenDecimals(token: Currency): Int {
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
val isAllowedToSpend = checkAllowance(networkId, fromTokenAddress)
|
||||
val fee = getAndUpdateFee(networkId, fromToken)
|
||||
val isBalanceEnough = isBalanceEnough(fromToken, networkId, amount, fee)
|
||||
val isFeeEnough = checkFeeIsEnough(fee, amount, networkId)
|
||||
val isFeeEnough = checkFeeIsEnough(fee, amount, networkId, fromToken)
|
||||
if (isAllowedToSpend && allowPermissionsHandler.isAddressAllowanceInProgress(fromTokenAddress)) {
|
||||
allowPermissionsHandler.removeAddressFromProgress(fromTokenAddress)
|
||||
transactionManager.updateWalletManager(networkId)
|
||||
|
|
@ -497,6 +497,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
private fun updatePermissionState(
|
||||
networkId: String,
|
||||
fromToken: Currency,
|
||||
|
|
@ -526,13 +527,12 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
}
|
||||
|
||||
private fun isBalanceEnough(fromToken: Currency, networkId: String, amount: SwapAmount, fee: BigDecimal?): Boolean {
|
||||
val tokenBalance =
|
||||
userWalletManager.getCurrentWalletTokensBalance(networkId)[fromToken.symbol]?.value ?: BigDecimal.ZERO
|
||||
return if (fromToken is Currency.NonNativeToken) {
|
||||
(userWalletManager.getCurrentWalletTokensBalance(networkId)[fromToken.symbol]?.value
|
||||
?: BigDecimal.ZERO) >= amount.value
|
||||
tokenBalance >= amount.value
|
||||
} else {
|
||||
/** to compare [BigDecimal] use only comparator */
|
||||
(userWalletManager.getCurrentWalletTokensBalance(networkId)[fromToken.symbol]?.value
|
||||
?: BigDecimal.ZERO) > amount.value.plus(fee ?: BigDecimal.ZERO)
|
||||
tokenBalance > amount.value.plus(fee ?: BigDecimal.ZERO)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -551,16 +551,28 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun checkFeeIsEnough(fee: BigDecimal?, spendAmount: SwapAmount, networkId: String): Boolean {
|
||||
private fun checkFeeIsEnough(
|
||||
fee: BigDecimal?,
|
||||
spendAmount: SwapAmount,
|
||||
networkId: String,
|
||||
fromToken: Currency,
|
||||
): Boolean {
|
||||
if (fee == null) {
|
||||
return false
|
||||
}
|
||||
userWalletManager.getNativeTokenBalance(networkId)?.let { balance ->
|
||||
return balance.value.minus(spendAmount.value) > fee.multiply(
|
||||
BigDecimal.valueOf(
|
||||
INCREASE_FEE_TO_CHECK_ENOUGH_PERCENT,
|
||||
),
|
||||
)
|
||||
val nativeTokenBalance = userWalletManager.getNativeTokenBalance(networkId)
|
||||
val percentsToFeeIncrease = BigDecimal.valueOf(INCREASE_FEE_TO_CHECK_ENOUGH_PERCENT)
|
||||
return when (fromToken) {
|
||||
is Currency.NativeToken -> {
|
||||
nativeTokenBalance?.let { balance ->
|
||||
return balance.value.minus(spendAmount.value) > fee.multiply(percentsToFeeIncrease)
|
||||
} ?: false
|
||||
}
|
||||
is Currency.NonNativeToken -> {
|
||||
nativeTokenBalance?.let { balance ->
|
||||
return balance.value > fee.multiply(percentsToFeeIncrease)
|
||||
} ?: false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.feature.swap.domain.models.domain
|
||||
|
||||
data class NetworkInfo(
|
||||
val name: String,
|
||||
val blockchainId: String,
|
||||
val blockchainCurrency: String,
|
||||
)
|
||||
|
|
@ -3,6 +3,7 @@ package com.tangem.feature.swap.ui
|
|||
import com.tangem.feature.swap.converters.TokensDataConverter
|
||||
import com.tangem.feature.swap.domain.models.DataError
|
||||
import com.tangem.feature.swap.domain.models.domain.Currency
|
||||
import com.tangem.feature.swap.domain.models.domain.NetworkInfo
|
||||
import com.tangem.feature.swap.domain.models.domain.isNonNative
|
||||
import com.tangem.feature.swap.domain.models.formatToUIRepresentation
|
||||
import com.tangem.feature.swap.domain.models.ui.FoundTokensState
|
||||
|
|
@ -24,14 +25,14 @@ import com.tangem.feature.swap.models.UiActions
|
|||
/**
|
||||
* State builder creates a specific states for SwapScreen
|
||||
*/
|
||||
class StateBuilder(val actions: UiActions) {
|
||||
internal class StateBuilder(val actions: UiActions) {
|
||||
|
||||
private val tokensDataConverter = TokensDataConverter(actions.onSearchEntered, actions.onTokenSelected)
|
||||
|
||||
fun createInitialLoadingState(initialCurrency: Currency, blockchainId: String): SwapStateHolder {
|
||||
fun createInitialLoadingState(initialCurrency: Currency, networkInfo: NetworkInfo): SwapStateHolder {
|
||||
return SwapStateHolder(
|
||||
networkId = initialCurrency.networkId,
|
||||
blockchainId = blockchainId,
|
||||
blockchainId = networkInfo.blockchainId,
|
||||
sendCardData = SwapCardData(
|
||||
type = TransactionCardType.SendCard(actions.onAmountChanged),
|
||||
amount = null,
|
||||
|
|
@ -55,7 +56,7 @@ class StateBuilder(val actions: UiActions) {
|
|||
coinId = null,
|
||||
),
|
||||
fee = FeeState.Loading,
|
||||
networkCurrency = initialCurrency.symbol,
|
||||
networkCurrency = networkInfo.blockchainCurrency,
|
||||
swapButton = SwapButton(enabled = false, loading = true, onClick = {}),
|
||||
onRefresh = {},
|
||||
onBackClicked = actions.onBackClicked,
|
||||
|
|
@ -316,15 +317,15 @@ class StateBuilder(val actions: UiActions) {
|
|||
return "$firstAddressPart...$secondAddressPart"
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val ADDRESS_MIN_LENGTH = 11
|
||||
const val ADDRESS_FIRST_PART_LENGTH = 7
|
||||
const val ADDRESS_SECOND_PART_LENGTH = 4
|
||||
}
|
||||
|
||||
fun createSilentLoadState(uiState: SwapStateHolder): SwapStateHolder {
|
||||
return uiState.copy(
|
||||
updateInProgress = true,
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val ADDRESS_MIN_LENGTH = 11
|
||||
const val ADDRESS_FIRST_PART_LENGTH = 7
|
||||
const val ADDRESS_SECOND_PART_LENGTH = 4
|
||||
}
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@ import kotlinx.serialization.json.Json
|
|||
import javax.inject.Inject
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
@Suppress("LargeClass")
|
||||
@HiltViewModel
|
||||
internal class SwapViewModel @Inject constructor(
|
||||
private val swapInteractor: SwapInteractor,
|
||||
|
|
@ -59,7 +60,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
var uiState: SwapStateHolder by mutableStateOf(
|
||||
stateBuilder.createInitialLoadingState(
|
||||
initialCurrency = currency,
|
||||
blockchainId = blockchainInteractor.getBlockchainId(currency.networkId),
|
||||
networkInfo = blockchainInteractor.getBlockchainInfo(currency.networkId),
|
||||
),
|
||||
)
|
||||
private set
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.lib.crypto
|
|||
|
||||
import com.tangem.lib.crypto.models.Currency
|
||||
import com.tangem.lib.crypto.models.ProxyAmount
|
||||
import com.tangem.lib.crypto.models.ProxyNetworkInfo
|
||||
import com.tangem.lib.crypto.models.transactions.SendTxResult
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -51,5 +52,5 @@ interface TransactionManager {
|
|||
* workaround till not use backend only and not integrated server vs sdk
|
||||
*/
|
||||
@Throws(IllegalStateException::class)
|
||||
fun getBlockchainId(networkId: String): String
|
||||
fun getBlockchainInfo(networkId: String): ProxyNetworkInfo
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.lib.crypto.models
|
||||
|
||||
data class ProxyNetworkInfo(
|
||||
val name: String,
|
||||
val blockchainId: String,
|
||||
val blockchainCurrency: String,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue