diff --git a/app/src/main/assets/testnet_tokens.json b/app/src/main/assets/testnet_tokens.json index cbc9238746..6be450bd32 100644 --- a/app/src/main/assets/testnet_tokens.json +++ b/app/src/main/assets/testnet_tokens.json @@ -405,7 +405,7 @@ { "id" : "vechain", "symbol" : "VET", - "name" : "Vechain", + "name" : "VeChain", "networks" : [ { "networkId" : "vechain/test" @@ -419,7 +419,7 @@ "networks": [ { "networkId": "vechain/test", - "contractAddress": "0x0000000000000000000000000000456E65726779", + "contractAddress": "0x0000000000000000000000000000456e65726779", "decimalCount": 18 } ] 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 f6fe0f4b00..6556e4518b 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 @@ -42,7 +42,6 @@ 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/customtoken/impl/data/converters/FoundTokenConverter.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/data/converters/FoundTokenConverter.kt index 977869feb2..33271e9fb6 100644 --- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/data/converters/FoundTokenConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/data/converters/FoundTokenConverter.kt @@ -20,7 +20,7 @@ object FoundTokenConverter : Converter { network = value.networks.firstOrNull()?.let { network -> FoundToken.Network( id = network.networkId, - address = requireNotNull(network.contractAddress), + contractAddress = requireNotNull(network.contractAddress), decimalCount = requireNotNull(network.decimalCount).toString(), ) } ?: error("Found token networks is empty"), diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/domain/models/FoundToken.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/domain/models/FoundToken.kt index 6ca52f5eb5..5b39f2dd52 100644 --- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/domain/models/FoundToken.kt +++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/domain/models/FoundToken.kt @@ -22,9 +22,9 @@ data class FoundToken( /** * Found token network * - * @property id id - * @property address address - * @property decimalCount decimal count + * @property id id + * @property contractAddress address + * @property decimalCount decimal count */ - data class Network(val id: String, val address: String, val decimalCount: String) + data class Network(val id: String, val contractAddress: String, val decimalCount: String) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt index 1e8a78eb4f..aedff94b31 100644 --- a/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/customtoken/impl/presentation/viewmodels/AddCustomTokenViewModel.kt @@ -827,11 +827,13 @@ internal class AddCustomTokenViewModel @Inject constructor( val currency = when (getCustomTokenType()) { CustomTokenType.TOKEN -> { + val contractAddress = foundToken?.network?.contractAddress + ?: uiState.form.contractAddressInputField.value CustomCurrency.CustomToken( token = Token( name = uiState.form.tokenNameInputField.value, symbol = uiState.form.tokenSymbolInputField.value, - contractAddress = uiState.form.contractAddressInputField.value, + contractAddress = contractAddress, decimals = requireNotNull(uiState.form.decimalsInputField.value.toIntOrNull()), id = foundToken?.id, ), diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index dc57a6bb45..f039fbb8b1 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -7,6 +7,7 @@ import com.tangem.common.core.TangemSdkError import com.tangem.common.core.UserCodeRequestPolicy import com.tangem.common.extensions.guard import com.tangem.core.analytics.Analytics +import com.tangem.core.analytics.models.Basic import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction import com.tangem.core.ui.extensions.TextReference @@ -22,8 +23,6 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.legacy.isLockedSync import com.tangem.tap.* import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.core.analytics.models.AnalyticsParam as CoreAnalyticsParam -import com.tangem.core.analytics.models.Basic import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchOnMain @@ -48,6 +47,7 @@ import kotlinx.coroutines.withContext import org.rekotlin.Action import org.rekotlin.Middleware import timber.log.Timber +import com.tangem.core.analytics.models.AnalyticsParam as CoreAnalyticsParam class DetailsMiddleware { private val eraseWalletMiddleware = EraseWalletMiddleware() @@ -522,7 +522,6 @@ class DetailsMiddleware { onWalletNotCreated = { // No need to rollback policy, continue with the policy set before the card scan store.dispatchWithMain(DetailsAction.ScanAndSaveUserWallet.Success) - store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Wallet)) }, disclaimerWillShow = { store.dispatchOnMain(NavigationAction.PopBackTo()) diff --git a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt index 92d7685a73..7ab41ec265 100644 --- a/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/saveWallet/redux/SaveWalletMiddleware.kt @@ -101,7 +101,17 @@ internal class SaveWalletMiddleware { val isFirstSavedWallet = !userWalletsListManager.hasUserWallets saveAccessCodeIfNeeded(state.backupInfo?.accessCode, userWallet.cardsInWallet) - .flatMap { userWalletsListManager.save(userWallet, canOverride = true) } + .flatMap { + // Save wallet only at first time (SaveWalletBottomSheet). + // Otherwise (Example, add new wallet in Details) userWalletsListManager.wallets subscribers will + // receive useless updates. + // See: OnboardingHelper.trySaveWalletAndNavigateToWalletScreen() + if (isFirstSavedWallet) { + userWalletsListManager.save(userWallet, canOverride = true) + } else { + CompletionResult.Success(Unit) + } + } .doOnFailure { error -> store.dispatchWithMain(SaveWalletAction.Save.Error(error)) } @@ -118,8 +128,8 @@ internal class SaveWalletMiddleware { ) } - store.dispatchWithMain(SaveWalletAction.Save.Success) - store.dispatchWithMain(NavigationAction.PopBackTo(AppScreen.Wallet)) + store.dispatchOnMain(SaveWalletAction.Save.Success) + store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Wallet)) } } } diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt index e842fd4a01..a50de375f4 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/reducers/ReceiptReducer.kt @@ -183,12 +183,14 @@ class ReceiptReducer : SendInternalReducer { return ReceiptTokenCrypto("0", feeValue.stripZeroPlainString(), "0", symbols) } val tokensToSend = amountState.amountToSendCrypto + val amountType = amountState.typeOfAmount + val currencyConverter = when { + amountType is AmountType.Token && sendState.feeIsConvertible() -> sendState.tokenConverter + amountType is AmountType.Coin && sendState.feeIsConvertible() -> sendState.coinConverter + else -> null + } - return if (sendState.currencyIsConvertible() && sendState.feeIsConvertible()) { - val currencyConverter = when (amountState.typeOfAmount) { - is AmountType.Token -> sendState.tokenConverter!! - else -> sendState.coinConverter!! - } + return if (currencyConverter != null) { val currencyFiat = currencyConverter.toFiatUnscaled(tokensToSend) val feeFiat = sendState.customFeeConverter!!.toFiatUnscaled(feeValue) val totalFiat = currencyFiat.plus(feeFiat) @@ -218,11 +220,14 @@ class ReceiptReducer : SendInternalReducer { val tokensToSend = amountState.amountToSendCrypto - return if (sendState.currencyIsConvertible() && sendState.feeIsConvertible()) { - val currencyConverter = when (amountState.typeOfAmount) { - is AmountType.Token -> sendState.tokenConverter!! - else -> sendState.coinConverter!! - } + val amountType = amountState.typeOfAmount + val currencyConverter = when { + amountType is AmountType.Token && sendState.feeIsConvertible() -> sendState.tokenConverter + amountType is AmountType.Coin && sendState.feeIsConvertible() -> sendState.coinConverter + else -> null + } + + return if (currencyConverter != null) { val feeFiat = sendState.customFeeConverter!!.toFiatUnscaled(feeCoin) val amountFiat = currencyConverter.toFiatUnscaled(tokensToSend) val totalFiat = amountFiat.plus(feeFiat) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt b/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt index 1159e1ff0d..b953ab71dd 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/states/SendState.kt @@ -102,8 +102,6 @@ data class SendState( fun coinIsConvertible(): Boolean = coinConverter != null fun tokenIsConvertible(): Boolean = tokenConverter != null - - fun currencyIsConvertible(): Boolean = coinConverter != null || tokenConverter != null fun feeIsConvertible(): Boolean = customFeeConverter != null fun mainCurrencyCanBeSwitched(): Boolean { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/CoinsResponseConverter.kt b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/CoinsResponseConverter.kt index b611e0a092..e2824e1022 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/CoinsResponseConverter.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/impl/data/converters/CoinsResponseConverter.kt @@ -25,7 +25,12 @@ internal object CoinsResponseConverter : Converter> { networks = token.networks.mapNotNull { network -> val blockchain = Blockchain.fromNetworkId(network.networkId) ?: return@mapNotNull null - if (!blockchain.canHandleTokens()) return@mapNotNull null + // filter tokens, if contractAddress != null, assume that it is a token + if (network.contractAddress != null && + !blockchain.canHandleTokens() + ) { + return@mapNotNull null + } Token.Network( id = network.networkId, 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 022b56497b..52beeb8387 100644 --- a/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt +++ b/app/src/main/java/com/tangem/tap/proxy/AppStateHolder.kt @@ -3,7 +3,6 @@ package com.tangem.tap.proxy import com.tangem.core.navigation.AppScreen import com.tangem.core.navigation.NavigationAction import com.tangem.core.navigation.ReduxNavController -import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.redux.ReduxStateHolder @@ -43,7 +42,6 @@ class AppStateHolder @Inject constructor() : WalletsStateHolder, ReduxNavControl var scanResponse: ScanResponse? = null var mainStore: Store? = null var tangemSdkManager: TangemSdkManager? = null - var appFiatCurrency: AppCurrency = AppCurrency.Default var exchangeService: ExchangeService? = null fun getActualCard(): CardDTO? { 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 836356c40e..14000bb456 100644 --- a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt @@ -16,13 +16,11 @@ 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.userWalletsListManager import timber.log.Timber import java.math.BigDecimal class UserWalletManagerImpl( - private val appStateHolder: AppStateHolder, private val walletManagersFacade: WalletManagersFacade, private val currenciesRepository: CurrenciesRepository, private val userWalletsStore: UserWalletsStore, @@ -171,15 +169,6 @@ class UserWalletManagerImpl( return blockchain.currency } - override fun getUserAppCurrency(): ProxyFiatCurrency { - val appCurrency = appStateHolder.appFiatCurrency - return ProxyFiatCurrency( - code = appCurrency.code, - name = appCurrency.name, - symbol = appCurrency.symbol, - ) - } - @Throws(IllegalArgumentException::class) private suspend fun getActualWalletManager(blockchain: Blockchain, derivationPath: String?): WalletManager { val selectedUserWallet = requireNotNull( diff --git a/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt b/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt index 263fc1eec8..8c0c4eda47 100644 --- a/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt +++ b/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt @@ -30,13 +30,11 @@ internal object ProxyModule { @Provides @Singleton fun provideUserWalletManager( - appStateHolder: AppStateHolder, walletManagersFacade: WalletManagersFacade, currenciesRepository: CurrenciesRepository, userWalletsStore: UserWalletsStore, ): UserWalletManager { return UserWalletManagerImpl( - appStateHolder = appStateHolder, walletManagersFacade = walletManagersFacade, currenciesRepository = currenciesRepository, userWalletsStore = userWalletsStore, diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkStatusFactory.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkStatusFactory.kt index 1fa432ab89..5f01503b2f 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkStatusFactory.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/NetworkStatusFactory.kt @@ -52,7 +52,7 @@ internal class NetworkStatusFactory { amounts.firstOrNull { amount -> amount is CryptoCurrencyAmount.Token && currency.id.rawCurrencyId == amount.tokenId && - currency.contractAddress == amount.tokenContractAddress + currency.contractAddress.equals(amount.tokenContractAddress, ignoreCase = true) } } } diff --git a/domain/app-currency/src/main/kotlin/com/tangem/domain/appcurrency/extenstions/UseCaseExtensions.kt b/domain/app-currency/src/main/kotlin/com/tangem/domain/appcurrency/extenstions/UseCaseExtensions.kt new file mode 100644 index 0000000000..724bddd8bc --- /dev/null +++ b/domain/app-currency/src/main/kotlin/com/tangem/domain/appcurrency/extenstions/UseCaseExtensions.kt @@ -0,0 +1,16 @@ +package com.tangem.domain.appcurrency.extenstions + +import arrow.core.getOrElse +import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase +import com.tangem.domain.appcurrency.model.AppCurrency +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.map + +suspend fun GetSelectedAppCurrencyUseCase.unwrap(): AppCurrency { + return this() + .map { maybeAppCurrency -> + maybeAppCurrency.getOrElse { AppCurrency.Default } + } + .firstOrNull() + ?: AppCurrency.Default +} \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt index eb399a3e08..9d0357e1f1 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt @@ -76,8 +76,8 @@ fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain? { "decimal/test" -> Blockchain.DecimalTestnet "xdc-network" -> Blockchain.XDC "xdc-network/test" -> Blockchain.XDCTestnet - "vechain" -> Blockchain.Vechain - "vechain/test" -> Blockchain.VechainTestnet + "vechain" -> Blockchain.VeChain + "vechain/test" -> Blockchain.VeChainTestnet "aptos" -> Blockchain.Aptos "aptos/test" -> Blockchain.AptosTestnet else -> null @@ -157,8 +157,8 @@ fun Blockchain.toNetworkId(): String { Blockchain.DecimalTestnet -> "decimal/test" Blockchain.XDC -> "xdc-network" Blockchain.XDCTestnet -> "xdc-network/test" - Blockchain.Vechain -> "vechain" - Blockchain.VechainTestnet -> "vechain/test" + Blockchain.VeChain -> "vechain" + Blockchain.VeChainTestnet -> "vechain/test" Blockchain.Aptos -> "aptos" Blockchain.AptosTestnet -> "aptos/test" } @@ -209,7 +209,7 @@ fun Blockchain.toCoinId(): String { Blockchain.NearTestnet -> "near/test" Blockchain.Decimal, Blockchain.DecimalTestnet -> "decimal" Blockchain.XDC, Blockchain.XDCTestnet -> "xdce-crowd-sale" - Blockchain.Vechain, Blockchain.VechainTestnet -> "vechain" + Blockchain.VeChain, Blockchain.VeChainTestnet -> "vechain" Blockchain.Aptos -> "aptos" Blockchain.AptosTestnet -> "aptos/test" Blockchain.Unknown -> "unknown" diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt index 45f2441c60..213a569e11 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt @@ -552,6 +552,7 @@ class DefaultWalletManagersFacade( blockchain = blockchain, derivationPath = derivationPath, ) + val feePaidCurrency = blockchain.feePaidCurrency() if (walletManager == null) { Timber.e("Unable to get a wallet manager for blockchain: $blockchain") @@ -560,6 +561,7 @@ class DefaultWalletManagersFacade( val transactionDataConverter = TransactionDataToTxHistoryItemConverter( walletAddresses = SdkAddressToAddressConverter.convertList(walletManager.wallet.addresses).toSet(), + feePaidCurrency = feePaidCurrency, ) return walletManager.wallet.recentTransactions.mapNotNull(transactionDataConverter::convert) diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt index d686b942ec..381b9cadd3 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/TransactionDataToTxHistoryItemConverter.kt @@ -1,8 +1,6 @@ package com.tangem.domain.walletmanager.utils -import com.tangem.blockchain.common.Amount -import com.tangem.blockchain.common.TransactionData -import com.tangem.blockchain.common.TransactionStatus +import com.tangem.blockchain.common.* import com.tangem.domain.txhistory.models.TxHistoryItem import com.tangem.domain.walletmanager.model.Address import com.tangem.utils.converter.Converter @@ -18,6 +16,7 @@ import java.math.BigDecimal */ internal class TransactionDataToTxHistoryItemConverter( private val walletAddresses: Set
, + private val feePaidCurrency: FeePaidCurrency, ) : Converter { override fun convert(value: TransactionData): TxHistoryItem? { @@ -48,12 +47,30 @@ internal class TransactionDataToTxHistoryItemConverter( private fun getTransactionAmountValue(amount: Amount, feeAmount: Amount?): BigDecimal? { val feeValue = feeAmount?.value ?: BigDecimal.ZERO - val value = amount.value?.plus(feeValue) + val value = amount.value if (value == null) { Timber.w("Transaction amount must not be null: ${amount.currencySymbol}") } - return value + return when (feePaidCurrency) { + FeePaidCurrency.SameCurrency -> value?.plus(feeValue) + FeePaidCurrency.Coin -> { + if (amount.type is AmountType.Coin) value?.plus(feeValue) else value + } + is FeePaidCurrency.Token -> { + val token = (amount.type as? AmountType.Token)?.token ?: return value + if (isSameToken(token, feePaidCurrency.token)) { + value?.plus(feeValue) + } else { + value + } + } + } + } + + private fun isSameToken(amountToken: Token, feeToken: Token): Boolean { + return amountToken.contractAddress.equals(feeToken.contractAddress, ignoreCase = true) && + amountToken.symbol.equals(feeToken.symbol, ignoreCase = true) } } \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt index 64600a36df..dbcc2c7ff5 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt @@ -15,24 +15,28 @@ internal class UpdateWalletManagerResultFactory { fun getResult(walletManager: WalletManager): UpdateWalletManagerResult.Verified { val wallet = walletManager.wallet val addresses = getAvailableAddresses(wallet.addresses) + val feePaidCurrency = wallet.blockchain.feePaidCurrency() + val txHistoryItemConverter = TransactionDataToTxHistoryItemConverter(addresses, feePaidCurrency) return UpdateWalletManagerResult.Verified( selectedAddress = wallet.address, addresses = addresses, currenciesAmounts = getTokensAmounts(wallet.amounts.values.toSet()), - currentTransactions = getCurrentTransactions(addresses, wallet.recentTransactions.toSet()), + currentTransactions = getCurrentTransactions(txHistoryItemConverter, wallet.recentTransactions.toSet()), ) } fun getDemoResult(walletManager: WalletManager, demoAmount: Amount): UpdateWalletManagerResult.Verified { val wallet = walletManager.wallet val addresses = getAvailableAddresses(wallet.addresses) + val feePaidCurrency = wallet.blockchain.feePaidCurrency() + val txHistoryItemConverter = TransactionDataToTxHistoryItemConverter(addresses, feePaidCurrency) return UpdateWalletManagerResult.Verified( selectedAddress = wallet.address, addresses = addresses, currenciesAmounts = getDemoTokensAmounts(demoAmount, walletManager.cardTokens), - currentTransactions = getCurrentTransactions(addresses, wallet.recentTransactions.toSet()), + currentTransactions = getCurrentTransactions(txHistoryItemConverter, wallet.recentTransactions.toSet()), ) } @@ -81,14 +85,19 @@ internal class UpdateWalletManagerResultFactory { } private fun getCurrentTransactions( - walletAddresses: Set
, + txHistoryItemConverter: TransactionDataToTxHistoryItemConverter, recentTransactions: Set, ): Set { val unconfirmedTransactions = recentTransactions.filter { it.status == TransactionStatus.Unconfirmed } - return unconfirmedTransactions.mapNotNullTo(hashSetOf()) { createCurrencyTransaction(walletAddresses, it) } + return unconfirmedTransactions.mapNotNullTo(hashSetOf()) { + createCurrencyTransaction( + txHistoryItemConverter = txHistoryItemConverter, + data = it, + ) + } } private fun createCurrencyAmount(amount: Amount): CryptoCurrencyAmount? { @@ -106,10 +115,9 @@ internal class UpdateWalletManagerResultFactory { } private fun createCurrencyTransaction( - walletAddresses: Set
, + txHistoryItemConverter: TransactionDataToTxHistoryItemConverter, data: TransactionData, ): CryptoCurrencyTransaction? { - val txHistoryItemConverter = TransactionDataToTxHistoryItemConverter(walletAddresses) return when (val type = data.amount.type) { is AmountType.Coin -> { val txHistoryItem = txHistoryItemConverter.convert(data) ?: return null diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/AddCryptoCurrenciesUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/AddCryptoCurrenciesUseCase.kt index 0f2c594510..21613763a1 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/AddCryptoCurrenciesUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/AddCryptoCurrenciesUseCase.kt @@ -81,7 +81,18 @@ class AddCryptoCurrenciesUseCase( .filter { hasCoinForToken(existingCurrencies, it) } .mapTo(hashSetOf(), CryptoCurrency.Token::network) - catch({ networksRepository.getNetworkStatusesSync(userWalletId, networksToUpdate, refresh = true) }) { + val networkToUpdate = currenciesToAdd.map { it.network } + .subtract(existingCurrencies.map { it.network }.toSet()) + + catch( + { + networksRepository.getNetworkStatusesSync( + userWalletId = userWalletId, + networks = networksToUpdate + networkToUpdate, + refresh = true, + ) + }, + ) { raise(AddCurrencyError.DataError(it)) } } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt index b62cccb971..b43052898e 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCurrencyWarningsUseCase.kt @@ -200,7 +200,8 @@ class GetCurrencyWarningsUseCase( } feePaidCurrency is FeePaidCurrency.Token -> { val feePaidTokenBalance = feePaidCurrency.balance - if (!tokenStatus.value.amount.isZero() && feePaidTokenBalance.isZero()) { + val amount = tokenStatus.value.amount ?: return null + if (!amount.isZero() && feePaidTokenBalance.isZero()) { constructTokenBalanceNotEnoughWarning( userWalletId = userWalletId, tokenStatus = tokenStatus, @@ -222,7 +223,9 @@ class GetCurrencyWarningsUseCase( val token = currenciesRepository .getMultiCurrencyWalletCurrenciesSync(userWalletId) .find { - it is CryptoCurrency.Token && it.contractAddress.equals(feePaidToken.contractAddress, ignoreCase = true) + it is CryptoCurrency.Token && + it.contractAddress.equals(feePaidToken.contractAddress, ignoreCase = true) && + it.network.derivationPath == tokenStatus.currency.network.derivationPath } return if (token != null) { CryptoCurrencyWarning.CustomTokenNotEnoughForFee( diff --git a/features/swap/domain/build.gradle.kts b/features/swap/domain/build.gradle.kts index 762f7f0252..e0cb9a413a 100644 --- a/features/swap/domain/build.gradle.kts +++ b/features/swap/domain/build.gradle.kts @@ -19,6 +19,7 @@ dependencies { kapt(deps.hilt.kapt) /** Domain */ + implementation(projects.domain.appCurrency) implementation(projects.domain.models) implementation(projects.domain.tokens) implementation(projects.domain.tokens.models) 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 4d2d187879..0928f9385a 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 @@ -7,6 +7,9 @@ import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.transaction.Fee import com.tangem.blockchain.common.transaction.TransactionFee +import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase +import com.tangem.domain.appcurrency.extenstions.unwrap +import com.tangem.domain.appcurrency.repository.AppCurrencyRepository import com.tangem.domain.tokens.GetCryptoCurrencyStatusesSyncUseCase import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus @@ -55,6 +58,7 @@ internal class SwapInteractorImpl @Inject constructor( private val quotesRepository: QuotesRepository, private val dispatcher: CoroutineDispatcherProvider, private val swapTransactionRepository: SwapTransactionRepository, + private val appCurrencyRepository: AppCurrencyRepository, private val initialToCurrencyResolver: InitialToCurrencyResolver, ) : SwapInteractor { @@ -62,6 +66,10 @@ internal class SwapInteractorImpl @Inject constructor( EstimateFeeUseCase(walletManagersFacade, dispatcher) } + private val getSelectedAppCurrencyUseCase by lazy(LazyThreadSafetyMode.NONE) { + GetSelectedAppCurrencyUseCase(appCurrencyRepository) + } + private val swapCurrencyConverter = SwapCurrencyConverter() private val amountFormatter = AmountFormatter() private val hundredPercent = BigInteger("100") @@ -638,8 +646,8 @@ internal class SwapInteractorImpl @Inject constructor( type = AmountType.Coin, ) - return when (blockchain) { - Blockchain.Ethereum -> { + return when { + blockchain.isEvm() -> { val feeAmountWithDecimals = feeAmountValue.movePointRight(fee.decimals) Fee.Ethereum( amount = feeAmount, @@ -647,11 +655,12 @@ internal class SwapInteractorImpl @Inject constructor( gasPrice = (feeAmountWithDecimals / fee.gasLimit.toBigDecimal()).toBigInteger(), ) } - Blockchain.Vechain -> Fee.Vechain( + blockchain == Blockchain.VeChain -> Fee.VeChain( amount = feeAmount, - gasPriceCoef = fee.gasLimit, + gasPriceCoef = Fee.VeChain.getGasPriceCoef(fee.gasLimit.toLong(), fee.feeValue), + gasLimit = fee.gasLimit.toLong(), ) - Blockchain.Aptos -> { + blockchain == Blockchain.Aptos -> { Fee.Aptos( amount = feeAmount, gasUnitPrice = fee.feeValue.toLong() / fee.gasLimit, @@ -754,8 +763,8 @@ internal class SwapInteractorImpl @Inject constructor( ) } - private fun createEmptyAmountState(): SwapState { - val appCurrency = userWalletManager.getUserAppCurrency() + private suspend fun createEmptyAmountState(): SwapState { + val appCurrency = getSelectedAppCurrencyUseCase.unwrap() return SwapState.EmptyAmountState( zeroAmountEquivalent = BigDecimal.ZERO.toFiatString( rateValue = BigDecimal.ONE, @@ -947,7 +956,7 @@ internal class SwapInteractorImpl @Inject constructor( } private suspend fun getFormattedFiatFees(networkId: String, vararg fees: BigDecimal): List { - val appCurrency = userWalletManager.getUserAppCurrency() + val appCurrency = getSelectedAppCurrencyUseCase.unwrap() val nativeToken = repository.getNativeTokenForNetwork(networkId) val rates = getQuotes(nativeToken.id) return rates[nativeToken.id]?.fiatRate?.let { rate -> @@ -1345,7 +1354,7 @@ internal class SwapInteractorImpl @Inject constructor( return when (this) { is Fee.Common -> 0 is Fee.Ethereum -> gasLimit.toInt() - is Fee.Vechain -> gasPriceCoef + is Fee.VeChain -> gasLimit.toInt() is Fee.Aptos -> amount.longValue?.div(gasUnitPrice)?.toInt() ?: 0 } } diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt index bfa910c669..cbf8cd6d81 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt @@ -1,5 +1,6 @@ package com.tangem.feature.swap.domain.di +import com.tangem.domain.appcurrency.repository.AppCurrencyRepository import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.demo.DemoConfig import com.tangem.domain.demo.IsDemoCardUseCase @@ -40,6 +41,7 @@ class SwapDomainModule { @SwapScope sendTransactionUseCase: SendTransactionUseCase, quotesRepository: QuotesRepository, swapTransactionRepository: SwapTransactionRepository, + appCurrencyRepository: AppCurrencyRepository, walletManagersFacade: WalletManagersFacade, coroutineDispatcherProvider: CoroutineDispatcherProvider, initialToCurrencyResolver: InitialToCurrencyResolver, @@ -56,6 +58,7 @@ class SwapDomainModule { walletManagersFacade = walletManagersFacade, dispatcher = coroutineDispatcherProvider, swapTransactionRepository = swapTransactionRepository, + appCurrencyRepository = appCurrencyRepository, initialToCurrencyResolver = initialToCurrencyResolver, ) } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt index 1bff8e17bc..fe66191de0 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsSwapTransactionsStateConverter.kt @@ -55,7 +55,7 @@ internal class TokenDetailsSwapTransactionsStateConverter( val toAmount = transaction.toCryptoAmount val fromAmount = transaction.fromCryptoAmount val toFiatAmount = quotes.firstOrNull { - it.rawCurrencyId == swapCurrency.fromCryptoCurrency.id.rawCurrencyId + it.rawCurrencyId == swapCurrency.toCryptoCurrency.id.rawCurrencyId }?.fiatRate?.multiply(toAmount) val fromFiatAmount = quotes.firstOrNull { it.rawCurrencyId == swapCurrency.fromCryptoCurrency.id.rawCurrencyId diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt index 1595df6158..79fef13194 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt @@ -83,7 +83,7 @@ sealed class WalletScreenAnalyticsEvent { object BackupYourWallet : MainScreen(event = "Notice - Backup Your Wallet") - object UnlockAllWithFaceID : MainScreen(event = "Button - Unlock All With Face ID") + object UnlockAllWithBiometrics : MainScreen(event = "Button - Unlock All With Biometrics") object UnlockWithCardScan : MainScreen(event = "Button - Unlock With Card Scan") diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/UseCaseExt.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/UseCaseExt.kt index 7e62eb79e3..1ab1765968 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/UseCaseExt.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/UseCaseExt.kt @@ -1,9 +1,6 @@ package com.tangem.feature.wallet.presentation.wallet.domain import arrow.core.Either -import arrow.core.getOrElse -import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase -import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase import com.tangem.domain.tokens.error.CurrencyStatusError import com.tangem.domain.tokens.model.CryptoCurrencyStatus @@ -38,15 +35,6 @@ internal suspend fun GetPrimaryCurrencyStatusUpdatesUseCase.unwrap(userWalletId: ) } -internal suspend fun GetSelectedAppCurrencyUseCase.unwrap(): AppCurrency { - return this() - .map { maybeAppCurrency -> - maybeAppCurrency.getOrElse { AppCurrency.Default } - } - .firstOrNull() - ?: AppCurrency.Default -} - internal suspend fun GetPrimaryCurrencyStatusUpdatesUseCase.collectLatest( userWalletId: UserWalletId, onRight: suspend (CryptoCurrencyStatus) -> Unit, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolverV2.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolverV2.kt index e1f8088ebe..1c8a3f7b26 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolverV2.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/WalletsUpdateActionResolverV2.kt @@ -211,7 +211,7 @@ internal class WalletsUpdateActionResolverV2 @Inject constructor( override fun toString(): String { return """ - Initialize( + InitializeWallets( selectedWalletIndex = $selectedWalletIndex, selectedWallet = ${selectedWallet.walletId}, wallets = ${wallets.joinToString { it.walletId.toString() }} diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt index 198af9b84d..25c2b29527 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt @@ -10,6 +10,7 @@ import com.tangem.core.ui.components.bottomsheets.tokenreceive.mapToAddressModel import com.tangem.core.ui.extensions.WrappedList import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase +import com.tangem.domain.appcurrency.extenstions.unwrap import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.redux.ReduxStateHolder diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt index 11ed6a3b00..ae87db6d02 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletWarningsClickIntents.kt @@ -231,7 +231,7 @@ internal class WalletWarningsClickIntentsImplementer @Inject constructor( } override fun onUnlockWalletClick() { - analyticsEventHandler.send(MainScreen.UnlockAllWithFaceID) + analyticsEventHandler.send(MainScreen.UnlockAllWithBiometrics) viewModelScope.launch(dispatchers.main) { unlockWalletsUseCase(throwIfNotAllWalletsUnlocked = true) diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index d9c45fa3cf..4f8cc49e6f 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -85,9 +85,9 @@ spr-client = "3.6.2" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "develop-467" +tangemBlockchainSdk = "develop-470" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "develop-319" +tangemCardSdk = "develop-324" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ # endregion Tangem 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 34322c70b2..82b89c030b 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 @@ -2,7 +2,6 @@ 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 @@ -67,11 +66,6 @@ interface UserWalletManager { @Throws(IllegalStateException::class) fun getNetworkCurrency(networkId: String): String - /** - * Returns selected app currency - */ - fun getUserAppCurrency(): ProxyFiatCurrency - @Throws(IllegalStateException::class) suspend fun getLastTransactionHash(networkId: String, derivationPath: String?): String? } \ No newline at end of file