diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt index 543e734f8f..4dc8390a9c 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt @@ -39,6 +39,7 @@ fun globalReducer(action: Action, state: AppState, appStateHolder: AppStateHolde globalState.copy(scanResponse = action.scanResponse) } is GlobalAction.ChangeAppCurrency -> { + appStateHolder.appFiatCurrency = action.appCurrency globalState.copy(appCurrency = action.appCurrency) } is GlobalAction.RestoreAppCurrency.Success -> { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index 4a3dabc865..17be87d7b4 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -28,7 +28,7 @@ import com.tangem.tap.store import kotlinx.coroutines.launch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -import com.tangem.feature.swap.domain.models.data.Currency as SwapCurrency +import com.tangem.feature.swap.domain.models.Currency as SwapCurrency class TradeCryptoMiddleware { fun handle(state: () -> AppState?, action: WalletAction.TradeCryptoAction) { diff --git a/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt b/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt index 110652b772..ed21a083df 100644 --- a/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt +++ b/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt @@ -3,6 +3,7 @@ package com.tangem.tap.proxy import com.tangem.TangemSdk import com.tangem.domain.common.CardDTO import com.tangem.domain.common.ScanResponse +import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.redux.AppState import com.tangem.tap.domain.TangemSdkManager import com.tangem.tap.domain.tokens.UserTokensRepository @@ -16,7 +17,7 @@ import javax.inject.Inject * Holds objects from old modules, that missing in DI graph * Object sets manually to use in new modules and [AppStateHolder] proxies its to DI */ -class AppStateHolder @Inject constructor(){ +class AppStateHolder @Inject constructor() { var scanResponse: ScanResponse? = null var walletState: WalletState? = null @@ -26,6 +27,7 @@ class AppStateHolder @Inject constructor(){ var tangemSdk: TangemSdk? = null var walletStoresManager: WalletStoresManager? = null var userWalletsListManager: UserWalletsListManager? = null + var appFiatCurrency: FiatCurrency = FiatCurrency.Default fun getActualCard(): CardDTO? { return scanResponse?.card diff --git a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt index 926eeb68b5..9ba2438963 100644 --- a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt @@ -3,6 +3,7 @@ package com.tangem.tap.proxy import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.DerivationParams import com.tangem.blockchain.common.DerivationStyle +import com.tangem.blockchain.common.WalletManager import com.tangem.blockchain.common.WalletManagerFactory import com.tangem.domain.common.CardDTO import com.tangem.domain.common.TapWorkarounds.derivationStyle @@ -12,11 +13,14 @@ import com.tangem.lib.crypto.UserWalletManager import com.tangem.lib.crypto.models.Currency import com.tangem.lib.crypto.models.Currency.NativeToken import com.tangem.lib.crypto.models.Currency.NonNativeToken +import com.tangem.lib.crypto.models.ProxyAmount +import com.tangem.lib.crypto.models.ProxyFiatCurrency import com.tangem.tap.domain.extensions.makeWalletManagerForApp import com.tangem.tap.domain.model.builders.UserWalletIdBuilder import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.redux.WalletAction import org.rekotlin.Action +import java.math.BigDecimal class UserWalletManagerImpl( private val appStateHolder: AppStateHolder, @@ -105,6 +109,28 @@ class UserWalletManagerImpl( } } + override fun getCurrentWalletTokensBalance(networkId: String): Map { + val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" } + val walletManager = getActualWalletManager(blockchain) + return walletManager.wallet.amounts.map { entry -> + val amount = entry.value + amount.currencySymbol to ProxyAmount( + amount.currencySymbol, + amount.value ?: BigDecimal.ZERO, + amount.decimals, + ) + }.toMap() + } + + override fun getUserAppCurrency(): ProxyFiatCurrency { + val appCurrency = appStateHolder.appFiatCurrency + return ProxyFiatCurrency( + code = appCurrency.code, + name = appCurrency.name, + symbol = appCurrency.symbol, + ) + } + private fun addNativeTokenToWalletAction(token: NativeToken, card: CardDTO): Action { val blockchain = Blockchain.fromNetworkId(token.networkId) val scanResponse = appStateHolder.scanResponse @@ -154,4 +180,10 @@ class UserWalletManagerImpl( private fun createDerivationParams(derivationStyle: DerivationStyle?): DerivationParams? { return derivationStyle?.let { DerivationParams.Default(derivationStyle) } //todo clarify if its need to add Custom } + + private fun getActualWalletManager(blockchain: Blockchain): WalletManager { + val card = requireNotNull(appStateHolder.getActualCard()) { "card not found" } + val blockchainNetwork = BlockchainNetwork(blockchain, card) + return requireNotNull(appStateHolder.walletState?.getWalletManager(blockchainNetwork)) { "no wallet manager found" } + } } \ No newline at end of file diff --git a/core/utils/src/main/java/com/tangem/utils/FormatExtensions.kt b/core/utils/src/main/java/com/tangem/utils/FormatExtensions.kt index 218d035d61..46b5621758 100644 --- a/core/utils/src/main/java/com/tangem/utils/FormatExtensions.kt +++ b/core/utils/src/main/java/com/tangem/utils/FormatExtensions.kt @@ -6,6 +6,7 @@ import java.text.DecimalFormat import java.text.DecimalFormatSymbols import java.util.* +//todo determine where to place this extensions fun BigDecimal.toFormattedString( decimals: Int, roundingMode: RoundingMode = RoundingMode.DOWN, locale: Locale = Locale.US, ): String { @@ -18,4 +19,51 @@ fun BigDecimal.toFormattedString( this.roundingMode = roundingMode } return df.format(this) +} + +fun BigDecimal.toFiatString( + rateValue: BigDecimal, + fiatCurrencyName: String, + formatWithSpaces: Boolean = false +): String { + val fiatValue = rateValue.multiply(this) + return fiatValue.toFormattedFiatValue(fiatCurrencyName, formatWithSpaces) +} + +fun BigDecimal.toFormattedFiatValue( + fiatCurrencyName: String, + formatWithSpaces: Boolean = false +): String { + val fiatValue = this.setScale(2, RoundingMode.HALF_UP) + .let { if (formatWithSpaces) it.formatWithSpaces() else it } + return " ${fiatValue}  $fiatCurrencyName" +} + +fun BigDecimal.formatWithSpaces(): String { + val str = this.toString() + var integerStr = str.substringBefore('.') + val reminderStr = str.substringAfter('.') + val packets = arrayListOf() + + var index: Int = integerStr.length + while (0 < index) { + if (index <= 3) { + packets.add(integerStr) + break + } + index -= 3 + packets.add(integerStr.substring(startIndex = index)) + integerStr = integerStr.substring(startIndex = 0, endIndex = index) + } + + return buildString { + packets.reversed().forEachIndexed { index, packet -> + append(packet) + if (index != packets.lastIndex) append(' ') + } + if (reminderStr.isNotBlank()) { + append('.') + append(reminderStr) + } + } } \ No newline at end of file diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt index 36e89a8e56..10cdf4a902 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt @@ -10,12 +10,12 @@ import com.tangem.feature.swap.converters.QuotesConverter import com.tangem.feature.swap.converters.SwapConverter import com.tangem.feature.swap.converters.TokensConverter import com.tangem.feature.swap.domain.SwapRepository -import com.tangem.feature.swap.domain.models.AggregatedSwapDataModel -import com.tangem.feature.swap.domain.models.data.ApproveModel -import com.tangem.feature.swap.domain.models.data.Currency -import com.tangem.feature.swap.domain.models.data.SwapDataModel -import com.tangem.feature.swap.domain.models.data.SwapState.QuoteModel -import com.tangem.feature.swap.domain.models.data.mapErrors +import com.tangem.feature.swap.domain.models.ApproveModel +import com.tangem.feature.swap.domain.models.Currency +import com.tangem.feature.swap.domain.models.QuoteModel +import com.tangem.feature.swap.domain.models.SwapDataModel +import com.tangem.feature.swap.domain.models.data.AggregatedSwapDataModel +import com.tangem.feature.swap.domain.models.mapErrors import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.withContext import javax.inject.Inject @@ -31,6 +31,12 @@ internal class SwapRepositoryImpl @Inject constructor( private val coroutineDispatcher: CoroutineDispatcherProvider, ) : SwapRepository { + override suspend fun getRates(currencyId: String, tokenIds: List): Map { + return withContext(coroutineDispatcher.io) { + tangemTechApi.getRates(currencyId.lowercase(), tokenIds.joinToString(",")).rates + } + } + override suspend fun getExchangeableTokens(networkId: String): List { return withContext(coroutineDispatcher.io) { tokensConverter.convertList(tangemTechApi.getCoins(exchangeable = true, networkIds = networkId).coins) diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ApproveConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ApproveConverter.kt index c5d5d0e600..4d3574869d 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ApproveConverter.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ApproveConverter.kt @@ -1,7 +1,7 @@ package com.tangem.feature.swap.converters import com.tangem.datasource.api.oneinch.models.ApproveCalldataResponse -import com.tangem.feature.swap.domain.models.data.ApproveModel +import com.tangem.feature.swap.domain.models.ApproveModel import com.tangem.utils.converter.Converter import javax.inject.Inject diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/QuotesConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/QuotesConverter.kt index 4cb95d4c03..57f0569e9c 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/QuotesConverter.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/QuotesConverter.kt @@ -1,8 +1,8 @@ package com.tangem.feature.swap.converters import com.tangem.datasource.api.oneinch.models.QuoteResponse -import com.tangem.feature.swap.domain.models.data.SwapState.QuoteModel -import com.tangem.feature.swap.domain.models.data.createFromAmountWithOffset +import com.tangem.feature.swap.domain.models.QuoteModel +import com.tangem.feature.swap.domain.models.createFromAmountWithOffset import com.tangem.utils.converter.Converter import javax.inject.Inject diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SwapConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SwapConverter.kt index 87dec263da..ebe2d92a13 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SwapConverter.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SwapConverter.kt @@ -2,8 +2,8 @@ package com.tangem.feature.swap.converters import com.tangem.datasource.api.oneinch.models.SwapResponse import com.tangem.datasource.api.oneinch.models.TransactionDto -import com.tangem.feature.swap.domain.models.data.SwapDataModel -import com.tangem.feature.swap.domain.models.data.TransactionModel +import com.tangem.feature.swap.domain.models.SwapDataModel +import com.tangem.feature.swap.domain.models.TransactionModel import com.tangem.utils.converter.Converter import javax.inject.Inject diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/TokensConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/TokensConverter.kt index c78b8b3638..8330c0c5f8 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/TokensConverter.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/TokensConverter.kt @@ -1,7 +1,7 @@ package com.tangem.feature.swap.converters import com.tangem.datasource.api.tangemTech.models.CoinsResponse -import com.tangem.feature.swap.domain.models.data.Currency +import com.tangem.feature.swap.domain.models.Currency import com.tangem.utils.converter.Converter import javax.inject.Inject diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt index 2741292876..421b21d439 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt @@ -1,15 +1,13 @@ package com.tangem.feature.swap.domain -import com.tangem.feature.swap.domain.models.data.Currency -import com.tangem.feature.swap.domain.models.data.SwapAmount -import com.tangem.feature.swap.domain.models.data.SwapState +import com.tangem.feature.swap.domain.models.Currency +import com.tangem.feature.swap.domain.models.SwapAmount +import com.tangem.feature.swap.domain.models.SwapState interface SwapInteractor { suspend fun getTokensToSwap(networkId: String): List - suspend fun getTokenBalance(tokenId: String): String - @Throws(IllegalStateException::class) suspend fun givePermissionToSwap(tokenToApprove: Currency) 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 9ffbf013a1..482f6c34a5 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 @@ -2,14 +2,17 @@ package com.tangem.feature.swap.domain import com.tangem.feature.swap.domain.cache.SwapDataCache import com.tangem.feature.swap.domain.converters.CryptoCurrencyConverter -import com.tangem.feature.swap.domain.models.data.Currency -import com.tangem.feature.swap.domain.models.data.DataError -import com.tangem.feature.swap.domain.models.data.SwapAmount -import com.tangem.feature.swap.domain.models.data.SwapState -import com.tangem.feature.swap.domain.models.data.TransactionModel -import com.tangem.feature.swap.domain.models.data.toStringWithRightOffset +import com.tangem.feature.swap.domain.models.Currency +import com.tangem.feature.swap.domain.models.DataError +import com.tangem.feature.swap.domain.models.QuoteModel +import com.tangem.feature.swap.domain.models.SwapAmount +import com.tangem.feature.swap.domain.models.SwapState +import com.tangem.feature.swap.domain.models.TransactionModel +import com.tangem.feature.swap.domain.models.toStringWithRightOffset import com.tangem.lib.crypto.TransactionManager import com.tangem.lib.crypto.UserWalletManager +import com.tangem.utils.toFiatString +import com.tangem.utils.toFormattedString import java.math.BigDecimal import javax.inject.Inject @@ -32,10 +35,6 @@ internal class SwapInteractorImpl @Inject constructor( } } - override suspend fun getTokenBalance(tokenId: String): String { - TODO("Not yet implemented") - } - override suspend fun givePermissionToSwap(tokenToApprove: Currency) { cache.getNetworkId()?.let { networkId -> if (tokenToApprove is Currency.NonNativeToken) { @@ -85,7 +84,7 @@ internal class SwapInteractorImpl @Inject constructor( fromCurrency = fromToken, toCurrency = toToken, ) - return quoteDataModel + return updateBalances(networkId, fromToken, toToken, quoteDataModel) } else { return SwapState.SwapError(quotes.error) } @@ -129,6 +128,41 @@ internal class SwapInteractorImpl @Inject constructor( } } + private suspend fun updateBalances( + networkId: String, + fromToken: Currency, + toToken: Currency, + quoteModel: QuoteModel, + ): SwapState.QuotesLoadedState { + val appCurrency = userWalletManager.getUserAppCurrency() + val rates = repository.getRates(appCurrency.code, listOf(fromToken.id, toToken.id)) + val tokensBalance = userWalletManager.getCurrentWalletTokensBalance(networkId) + val fromTokenBalance = tokensBalance[fromToken.symbol]?.let { + it.value.toFormattedString(it.decimals) + } + val toTokenBalance = tokensBalance[toToken.symbol]?.let { + it.value.toFormattedString(it.decimals) + } + return SwapState.QuotesLoadedState( + fromTokenAmount = quoteModel.fromTokenAmount, + toTokenAmount = quoteModel.toTokenAmount, + fromTokenAddress = quoteModel.fromTokenAddress, + toTokenAddress = quoteModel.toTokenAddress, + estimatedGas = quoteModel.estimatedGas, + isAllowedToSpend = quoteModel.isAllowedToSpend, + fromTokenWalletBalance = fromTokenBalance ?: ZERO_BALANCE, + fromTokenFiatBalance = quoteModel.fromTokenAmount.value.toFiatString( + rates[fromToken.id]?.toBigDecimal() ?: BigDecimal.ZERO, + appCurrency.symbol, + ), + toTokenWalletBalance = toTokenBalance ?: ZERO_BALANCE, + toTokenFiatBalance = quoteModel.fromTokenAmount.value.toFiatString( + rates[fromToken.id]?.toBigDecimal() ?: BigDecimal.ZERO, + appCurrency.symbol, + ), + ) + } + private fun getWalletAddress(networkId: String): String { return userWalletManager.getWalletAddress(networkId) } @@ -150,5 +184,6 @@ internal class SwapInteractorImpl @Inject constructor( companion object { private const val DEFAULT_SLIPPAGE = 2 + private const val ZERO_BALANCE = "0" } } \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt index 55a973b7e9..7082d123c4 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt @@ -1,13 +1,15 @@ package com.tangem.feature.swap.domain -import com.tangem.feature.swap.domain.models.AggregatedSwapDataModel -import com.tangem.feature.swap.domain.models.data.ApproveModel -import com.tangem.feature.swap.domain.models.data.Currency -import com.tangem.feature.swap.domain.models.data.SwapDataModel -import com.tangem.feature.swap.domain.models.data.SwapState +import com.tangem.feature.swap.domain.models.ApproveModel +import com.tangem.feature.swap.domain.models.Currency +import com.tangem.feature.swap.domain.models.QuoteModel +import com.tangem.feature.swap.domain.models.SwapDataModel +import com.tangem.feature.swap.domain.models.data.AggregatedSwapDataModel interface SwapRepository { + suspend fun getRates(currencyId: String, tokenIds: List): Map + suspend fun getExchangeableTokens(networkId: String): List suspend fun findBestQuote( @@ -15,7 +17,7 @@ interface SwapRepository { fromTokenAddress: String, toTokenAddress: String, amount: String, - ): AggregatedSwapDataModel + ): AggregatedSwapDataModel /** * Returns address of 1inch router that must be trusted diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCache.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCache.kt index 4318e5dbfc..6acefb6794 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCache.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCache.kt @@ -1,9 +1,9 @@ package com.tangem.feature.swap.domain.cache -import com.tangem.feature.swap.domain.models.ExchangeCurrencies -import com.tangem.feature.swap.domain.models.data.Currency -import com.tangem.feature.swap.domain.models.data.SwapAmount -import com.tangem.feature.swap.domain.models.data.SwapState.QuoteModel +import com.tangem.feature.swap.domain.models.Currency +import com.tangem.feature.swap.domain.models.QuoteModel +import com.tangem.feature.swap.domain.models.SwapAmount +import com.tangem.feature.swap.domain.models.cache.ExchangeCurrencies interface SwapDataCache { diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCacheImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCacheImpl.kt index 2ee0425726..0431b67ff0 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCacheImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/cache/SwapDataCacheImpl.kt @@ -1,10 +1,10 @@ package com.tangem.feature.swap.domain.cache -import com.tangem.feature.swap.domain.models.ExchangeCurrencies -import com.tangem.feature.swap.domain.models.SwapDataHolder -import com.tangem.feature.swap.domain.models.data.Currency -import com.tangem.feature.swap.domain.models.data.SwapAmount -import com.tangem.feature.swap.domain.models.data.SwapState.QuoteModel +import com.tangem.feature.swap.domain.models.Currency +import com.tangem.feature.swap.domain.models.QuoteModel +import com.tangem.feature.swap.domain.models.SwapAmount +import com.tangem.feature.swap.domain.models.cache.ExchangeCurrencies +import com.tangem.feature.swap.domain.models.cache.SwapDataHolder class SwapDataCacheImpl : SwapDataCache { diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/converters/CryptoCurrencyConverter.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/converters/CryptoCurrencyConverter.kt index 161f9661a2..68c3895f79 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/converters/CryptoCurrencyConverter.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/converters/CryptoCurrencyConverter.kt @@ -1,6 +1,6 @@ package com.tangem.feature.swap.domain.converters -import com.tangem.feature.swap.domain.models.data.Currency +import com.tangem.feature.swap.domain.models.Currency import com.tangem.utils.converter.Converter class CryptoCurrencyConverter : Converter { diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/ApproveModel.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ApproveModel.kt similarity index 88% rename from features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/ApproveModel.kt rename to features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ApproveModel.kt index a553a8d4bf..2fce5634f9 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/ApproveModel.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ApproveModel.kt @@ -1,4 +1,4 @@ -package com.tangem.feature.swap.domain.models.data +package com.tangem.feature.swap.domain.models /** * Approve model diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/Currency.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/Currency.kt similarity index 94% rename from features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/Currency.kt rename to features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/Currency.kt index 947c62e7bc..bcd8017e56 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/Currency.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/Currency.kt @@ -1,4 +1,4 @@ -package com.tangem.feature.swap.domain.models.data +package com.tangem.feature.swap.domain.models import kotlinx.serialization.Serializable diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/DataError.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/DataError.kt similarity index 91% rename from features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/DataError.kt rename to features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/DataError.kt index 60e80e094e..def35afd55 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/DataError.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/DataError.kt @@ -1,4 +1,4 @@ -package com.tangem.feature.swap.domain.models.data +package com.tangem.feature.swap.domain.models enum class DataError { NO_ERROR, diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/QuoteModel.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/QuoteModel.kt new file mode 100644 index 0000000000..1d4aa9afdb --- /dev/null +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/QuoteModel.kt @@ -0,0 +1,20 @@ +package com.tangem.feature.swap.domain.models + +/** + * Quote model holds data about current amounts of exchange and fees + * + * @property fromTokenAmount amount of token you want to exchange + * @property toTokenAmount amount of token you want to receive + * @property fromTokenAddress address token you want to exchange + * @property toTokenAddress address token you want to receive + * @property estimatedGas fee + * @property isAllowedToSpend does spend allowed + */ +data class QuoteModel( + val fromTokenAmount: SwapAmount, + val toTokenAmount: SwapAmount, + val fromTokenAddress: String, + val toTokenAddress: String, + val estimatedGas: Int, + val isAllowedToSpend: Boolean = false, +) \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/SwapAmount.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapAmount.kt similarity index 95% rename from features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/SwapAmount.kt rename to features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapAmount.kt index 9b5738306a..342ce251e7 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/SwapAmount.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapAmount.kt @@ -1,4 +1,4 @@ -package com.tangem.feature.swap.domain.models.data +package com.tangem.feature.swap.domain.models import com.tangem.utils.toFormattedString import java.math.BigDecimal diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/SwapDataModel.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapDataModel.kt similarity index 89% rename from features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/SwapDataModel.kt rename to features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapDataModel.kt index d7b70ca338..f18018c63e 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/SwapDataModel.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapDataModel.kt @@ -1,4 +1,4 @@ -package com.tangem.feature.swap.domain.models.data +package com.tangem.feature.swap.domain.models /** * Swap transaction model diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/SwapState.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapState.kt similarity index 66% rename from features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/SwapState.kt rename to features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapState.kt index 6b00f55db1..82bf5808f5 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/SwapState.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapState.kt @@ -1,12 +1,16 @@ -package com.tangem.feature.swap.domain.models.data +package com.tangem.feature.swap.domain.models sealed interface SwapState { - data class QuoteModel( + data class QuotesLoadedState( val fromTokenAmount: SwapAmount, val toTokenAmount: SwapAmount, val fromTokenAddress: String, val toTokenAddress: String, + val fromTokenWalletBalance: String, + val fromTokenFiatBalance: String, + val toTokenWalletBalance: String, + val toTokenFiatBalance: String, val estimatedGas: Int, val isAllowedToSpend: Boolean = false, ) : SwapState diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/TransactionModel.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/TransactionModel.kt similarity index 93% rename from features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/TransactionModel.kt rename to features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/TransactionModel.kt index 978c7e5ec7..eea39441ca 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/TransactionModel.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/TransactionModel.kt @@ -1,4 +1,4 @@ -package com.tangem.feature.swap.domain.models.data +package com.tangem.feature.swap.domain.models /** * Transaction model diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapDataHolder.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/cache/SwapDataHolder.kt similarity index 54% rename from features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapDataHolder.kt rename to features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/cache/SwapDataHolder.kt index e974b51f15..41e159253f 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/SwapDataHolder.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/cache/SwapDataHolder.kt @@ -1,9 +1,8 @@ -package com.tangem.feature.swap.domain.models +package com.tangem.feature.swap.domain.models.cache -import com.tangem.feature.swap.domain.models.data.Currency -import com.tangem.feature.swap.domain.models.data.SwapAmount -import com.tangem.feature.swap.domain.models.data.SwapState.QuoteModel -import java.math.BigDecimal +import com.tangem.feature.swap.domain.models.Currency +import com.tangem.feature.swap.domain.models.QuoteModel +import com.tangem.feature.swap.domain.models.SwapAmount data class SwapDataHolder( val quoteModel: QuoteModel? = null, diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/AggregatedSwapDataModel.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/AggregatedSwapDataModel.kt similarity index 75% rename from features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/AggregatedSwapDataModel.kt rename to features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/AggregatedSwapDataModel.kt index 2554398d3c..2a7eefc5b3 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/AggregatedSwapDataModel.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/data/AggregatedSwapDataModel.kt @@ -1,6 +1,6 @@ -package com.tangem.feature.swap.domain.models +package com.tangem.feature.swap.domain.models.data -import com.tangem.feature.swap.domain.models.data.DataError +import com.tangem.feature.swap.domain.models.DataError /** * Model that aggregate data model from repository return with error [DataError] if it exists 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 65a6894659..067ecab8bf 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 @@ -1,8 +1,8 @@ package com.tangem.feature.swap.ui -import com.tangem.feature.swap.domain.models.data.Currency -import com.tangem.feature.swap.domain.models.data.SwapState -import com.tangem.feature.swap.domain.models.data.formatToUIRepresentation +import com.tangem.feature.swap.domain.models.Currency +import com.tangem.feature.swap.domain.models.SwapState +import com.tangem.feature.swap.domain.models.formatToUIRepresentation import com.tangem.feature.swap.models.FeeState import com.tangem.feature.swap.models.SwapButton import com.tangem.feature.swap.models.SwapCardData @@ -50,7 +50,7 @@ class StateBuilder { ): SwapStateHolder { return uiStateHolder.copy( sendCardData = SwapCardData( - type = (uiStateHolder.sendCardData.type as TransactionCardType.SendCard), + type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard), amount = uiStateHolder.sendCardData.amount, amountEquivalent = uiStateHolder.sendCardData.amountEquivalent, tokenIconUrl = fromToken.logoUrl, @@ -72,16 +72,19 @@ class StateBuilder { fun createQuotesLoadedState( uiStateHolder: SwapStateHolder, - quoteModel: SwapState.QuoteModel, + quoteModel: SwapState.QuotesLoadedState, fromToken: Currency, onSwapClick: () -> Unit, ): SwapStateHolder { return uiStateHolder.copy( sendCardData = SwapCardData( - type = (uiStateHolder.sendCardData.type as TransactionCardType.SendCard) - .copy(permissionIsGiven = quoteModel.isAllowedToSpend), + type = requireNotNull(uiStateHolder.sendCardData.type as? TransactionCardType.SendCard) + .copy( + permissionIsGiven = quoteModel.isAllowedToSpend, + balance = quoteModel.fromTokenWalletBalance, + ), amount = quoteModel.fromTokenAmount.formatToUIRepresentation(), - amountEquivalent = uiStateHolder.sendCardData.amountEquivalent, + amountEquivalent = quoteModel.fromTokenFiatBalance, tokenIconUrl = uiStateHolder.sendCardData.tokenIconUrl, tokenCurrency = uiStateHolder.sendCardData.tokenCurrency, canSelectAnotherToken = uiStateHolder.sendCardData.canSelectAnotherToken, @@ -89,7 +92,7 @@ class StateBuilder { receiveCardData = SwapCardData( type = TransactionCardType.ReceiveCard(), amount = quoteModel.toTokenAmount.formatToUIRepresentation(), - amountEquivalent = uiStateHolder.receiveCardData.amountEquivalent, + amountEquivalent = quoteModel.toTokenFiatBalance, tokenIconUrl = uiStateHolder.receiveCardData.tokenIconUrl, tokenCurrency = uiStateHolder.receiveCardData.tokenCurrency, canSelectAnotherToken = uiStateHolder.receiveCardData.canSelectAnotherToken, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index 0609a4e8cf..dfcf661be7 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -8,9 +8,9 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.tangem.feature.swap.domain.SwapInteractor -import com.tangem.feature.swap.domain.models.data.Currency -import com.tangem.feature.swap.domain.models.data.SwapState -import com.tangem.feature.swap.domain.models.data.createFromAmountWithoutOffset +import com.tangem.feature.swap.domain.models.Currency +import com.tangem.feature.swap.domain.models.SwapState +import com.tangem.feature.swap.domain.models.createFromAmountWithoutOffset import com.tangem.feature.swap.models.SwapStateHolder import com.tangem.feature.swap.presentation.SwapFragment import com.tangem.feature.swap.router.SwapRouter @@ -97,7 +97,7 @@ internal class SwapViewModel @Inject constructor( } .onSuccess { swapState -> when (swapState) { - is SwapState.QuoteModel -> { + is SwapState.QuotesLoadedState -> { uiState = stateBuilder.createQuotesLoadedState(uiState, swapState, fromToken) { onSwapClick(toToken, swapState) } @@ -113,7 +113,7 @@ internal class SwapViewModel @Inject constructor( } } - private fun onSwapClick(toToken: Currency, quoteModel: SwapState.QuoteModel) { + private fun onSwapClick(toToken: Currency, quoteModel: SwapState.QuotesLoadedState) { viewModelScope.launch(dispatchers.main) { runCatching { if (!quoteModel.isAllowedToSpend) { diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/UserWalletManager.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/UserWalletManager.kt index ef60119263..b29cfc2535 100644 --- a/libs/crypto/src/main/java/com/tangem/lib/crypto/UserWalletManager.kt +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/UserWalletManager.kt @@ -1,6 +1,8 @@ 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.ProxyFiatCurrency /** * Provider for user tokens data @@ -37,4 +39,18 @@ interface UserWalletManager { * @param networkId for currency */ fun getWalletAddress(networkId: String): String + + /** + * Return balances from wallet found by networkId + * + * @param networkId + * @return map of + */ + @Throws(IllegalStateException::class) + fun getCurrentWalletTokensBalance(networkId: String): Map + + /** + * Returns selected app currency + */ + fun getUserAppCurrency(): ProxyFiatCurrency } \ No newline at end of file diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/models/ProxyFiatCurrency.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/models/ProxyFiatCurrency.kt new file mode 100644 index 0000000000..5a46bdef84 --- /dev/null +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/models/ProxyFiatCurrency.kt @@ -0,0 +1,7 @@ +package com.tangem.lib.crypto.models + +data class ProxyFiatCurrency( + val code: String, + val name: String, + val symbol: String, +) \ No newline at end of file