diff --git a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt index 33823b5d36..a0db65cfba 100644 --- a/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/TransactionManagerImpl.kt @@ -2,9 +2,15 @@ package com.tangem.tap.proxy import com.google.firebase.crashlytics.FirebaseCrashlytics import com.tangem.Message +import com.tangem.blockchain.blockchains.binance.BinanceTransactionExtras +import com.tangem.blockchain.blockchains.cosmos.CosmosTransactionExtras import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager import com.tangem.blockchain.blockchains.optimism.OptimismWalletManager +import com.tangem.blockchain.blockchains.stellar.StellarMemo +import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras +import com.tangem.blockchain.blockchains.ton.TonTransactionExtras +import com.tangem.blockchain.blockchains.xrp.XrpTransactionBuilder import com.tangem.blockchain.common.* import com.tangem.blockchain.common.transaction.Fee import com.tangem.blockchain.common.transaction.TransactionFee @@ -18,6 +24,8 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.common.BlockchainNetwork import com.tangem.domain.common.extensions.fromNetworkId import com.tangem.domain.walletmanager.WalletManagersFacade +import com.tangem.features.send.impl.presentation.viewmodel.XlmMemoType +import com.tangem.features.send.impl.presentation.viewmodel.determineXlmMemoType import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import com.tangem.lib.crypto.TransactionManager import com.tangem.lib.crypto.models.* @@ -143,6 +151,25 @@ class TransactionManagerImpl( return blockchain.getExploreTxUrl(txAddress) } + override fun getMemoExtras(networkId: String, memo: String?): TransactionExtras? { + val blockchain = Blockchain.fromNetworkId(networkId) + if (memo == null) return null + return when (blockchain) { + Blockchain.Stellar -> { + val xmlMemo = when (determineXlmMemoType(memo)) { + XlmMemoType.TEXT -> StellarMemo.Text(memo) + XlmMemoType.ID -> StellarMemo.Id(memo.toBigInteger()) + } + StellarTransactionExtras(xmlMemo) + } + Blockchain.Binance -> BinanceTransactionExtras(memo) + Blockchain.XRP -> memo.toLongOrNull()?.let { XrpTransactionBuilder.XrpTransactionExtras(it) } + Blockchain.Cosmos -> CosmosTransactionExtras(memo) + Blockchain.TON -> TonTransactionExtras(memo) + else -> null + } + } + override fun getNativeTokenDecimals(networkId: String): Int { return Blockchain.fromNetworkId(networkId)?.decimals() ?: error("blockchain not found") } diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeDataResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeDataResponse.kt index 72deee1a57..b44fa2a019 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeDataResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeDataResponse.kt @@ -39,6 +39,12 @@ data class ExchangeDataResponse( @Json(name = "externalTxUrl") val externalTxUrl: String?, // null if DEX, url of provider exchange status page if CEX + + @Json(name = "txExtraIdName") + val txExtraIdName: String?, + + @Json(name = "txExtraId") + val txExtraId: String?, ) enum class TxType { diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt index ffa0aeee60..26d5b3cf08 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt @@ -45,7 +45,7 @@ object PreferencesKeys { val IS_WALLET_SWAP_PROMO_SHOW_KEY by lazy { booleanPreferencesKey(name = "isWalletSwapPromoShown") } - val IS_TOKEN_SWAP_PROMO_SHOW_KEY by lazy { stringSetPreferencesKey(name = "isTokenSwapPromoShown") } + val IS_TOKEN_SWAP_PROMO_SHOW_KEY by lazy { booleanPreferencesKey(name = "isTokenSwapPromoShown") } } /** Preferences keys set that should be migrated from "PreferencesDataSource" to a new DataStore */ diff --git a/data/settings/src/main/java/com/tangem/data/settings/DefaultSwapPromoRepository.kt b/data/settings/src/main/java/com/tangem/data/settings/DefaultSwapPromoRepository.kt index cfdc97ba1c..dd94a2e07c 100644 --- a/data/settings/src/main/java/com/tangem/data/settings/DefaultSwapPromoRepository.kt +++ b/data/settings/src/main/java/com/tangem/data/settings/DefaultSwapPromoRepository.kt @@ -21,9 +21,9 @@ class DefaultSwapPromoRepository( .map { it && checkPromoPeriod() } } - override fun isReadyToShowToken(userWalletId: String, currencyId: String): Flow { - return appPreferencesStore.get(IS_TOKEN_SWAP_PROMO_SHOW_KEY, emptySet()) - .map { !it.contains(userWalletId + currencyId) && checkPromoPeriod() } + override fun isReadyToShowToken(): Flow { + return appPreferencesStore.get(IS_TOKEN_SWAP_PROMO_SHOW_KEY, true) + .map { it && checkPromoPeriod() } } override suspend fun setNeverToShowWallet() { @@ -33,14 +33,11 @@ class DefaultSwapPromoRepository( ) } - override suspend fun setNeverToShowToken(userWalletId: String, currencyId: String) { - appPreferencesStore.editData { mutablePreferences -> - val storesCurrencies = mutablePreferences.getOrDefault(IS_TOKEN_SWAP_PROMO_SHOW_KEY, emptySet()) - mutablePreferences.set( - key = IS_TOKEN_SWAP_PROMO_SHOW_KEY, - value = storesCurrencies.toMutableSet().apply { add(userWalletId + currencyId) }, - ) - } + override suspend fun setNeverToShowToken() { + appPreferencesStore.store( + key = IS_TOKEN_SWAP_PROMO_SHOW_KEY, + value = false, + ) } private fun checkPromoPeriod(): Boolean { diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/ShouldShowSwapPromoTokenUseCase.kt b/domain/settings/src/main/java/com/tangem/domain/settings/ShouldShowSwapPromoTokenUseCase.kt index 6d7b0b30f9..0c75a4f52a 100644 --- a/domain/settings/src/main/java/com/tangem/domain/settings/ShouldShowSwapPromoTokenUseCase.kt +++ b/domain/settings/src/main/java/com/tangem/domain/settings/ShouldShowSwapPromoTokenUseCase.kt @@ -5,9 +5,7 @@ import kotlinx.coroutines.flow.Flow class ShouldShowSwapPromoTokenUseCase(private val swapPromoRepository: SwapPromoRepository) { - operator fun invoke(userWalletId: String, currencyId: String): Flow = - swapPromoRepository.isReadyToShowToken(userWalletId, currencyId) + operator fun invoke(): Flow = swapPromoRepository.isReadyToShowToken() - suspend fun neverToShow(userWalletId: String, currencyId: String) = - swapPromoRepository.setNeverToShowToken(userWalletId, currencyId) + suspend fun neverToShow() = swapPromoRepository.setNeverToShowToken() } \ No newline at end of file diff --git a/domain/settings/src/main/java/com/tangem/domain/settings/repositories/SwapPromoRepository.kt b/domain/settings/src/main/java/com/tangem/domain/settings/repositories/SwapPromoRepository.kt index 96d180f4df..95d31f65d8 100644 --- a/domain/settings/src/main/java/com/tangem/domain/settings/repositories/SwapPromoRepository.kt +++ b/domain/settings/src/main/java/com/tangem/domain/settings/repositories/SwapPromoRepository.kt @@ -5,9 +5,9 @@ import kotlinx.coroutines.flow.Flow interface SwapPromoRepository { fun isReadyToShowWallet(): Flow - fun isReadyToShowToken(userWalletId: String, currencyId: String): Flow + fun isReadyToShowToken(): Flow suspend fun setNeverToShowWallet() - suspend fun setNeverToShowToken(userWalletId: String, currencyId: String) + suspend fun setNeverToShowToken() } \ No newline at end of file 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 ae959e251d..2998ea46b9 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 @@ -85,7 +85,7 @@ class GetCurrencyWarningsUseCase( val currency = currencyStatus.currency val cryptoStatuses = operations.getCurrenciesStatusesSync() return combine( - showSwapPromoTokenUseCase(userWalletId.stringValue, currency.id.value).conflate(), + showSwapPromoTokenUseCase().conflate(), flowOf(marketCryptoCurrencyRepository.isExchangeable(userWalletId, currency)).conflate(), ) { shouldShowSwapPromo, isExchangeable -> if (shouldShowSwapPromo && isExchangeable) { 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 62c8ebb0b6..24fa9fb08f 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 @@ -30,10 +30,10 @@ import com.tangem.domain.wallets.legacy.WalletsStateHolder import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.swap.converters.* import com.tangem.feature.swap.domain.api.SwapRepository -import com.tangem.feature.swap.domain.models.domain.* import com.tangem.feature.swap.domain.models.DataError import com.tangem.feature.swap.domain.models.ExpressException import com.tangem.feature.swap.domain.models.createFromAmountWithOffset +import com.tangem.feature.swap.domain.models.domain.* import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.async import kotlinx.coroutines.withContext diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExpressDataConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExpressDataConverter.kt index 6746243002..86a75abcb7 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExpressDataConverter.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/ExpressDataConverter.kt @@ -34,6 +34,8 @@ class ExpressDataConverter : Converter { txTo = transactionDto.txTo, externalTxId = requireNotNull(transactionDto.externalTxId), externalTxUrl = requireNotNull(transactionDto.externalTxUrl), + txExtraIdName = transactionDto.txExtraIdName, + txExtraId = transactionDto.txExtraId, ) } } diff --git a/features/swap/domain/api/src/main/java/com/tangem/feature/swap/domain/api/SwapRepository.kt b/features/swap/domain/api/src/main/java/com/tangem/feature/swap/domain/api/SwapRepository.kt index 713cbeeb9e..c1310c961c 100644 --- a/features/swap/domain/api/src/main/java/com/tangem/feature/swap/domain/api/SwapRepository.kt +++ b/features/swap/domain/api/src/main/java/com/tangem/feature/swap/domain/api/SwapRepository.kt @@ -3,8 +3,8 @@ package com.tangem.feature.swap.domain.api import arrow.core.Either import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.feature.swap.domain.models.domain.* import com.tangem.feature.swap.domain.models.DataError +import com.tangem.feature.swap.domain.models.domain.* import java.math.BigDecimal interface SwapRepository { diff --git a/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/domain/ExpressTransactionModel.kt b/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/domain/ExpressTransactionModel.kt index 89ab7c6754..a1c0981569 100644 --- a/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/domain/ExpressTransactionModel.kt +++ b/features/swap/domain/models/src/main/java/com/tangem/feature/swap/domain/models/domain/ExpressTransactionModel.kt @@ -25,5 +25,7 @@ sealed class ExpressTransactionModel { override val txTo: String, val externalTxId: String, val externalTxUrl: String, + val txExtraIdName: String?, + val txExtraId: String?, ) : ExpressTransactionModel() } \ No newline at end of file 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 2de0ce5464..2fd8561359 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 @@ -499,13 +499,23 @@ internal class SwapInteractorImpl @Inject constructor( toAddress = currencyToGet.value.networkAddress?.defaultAddress?.value ?: "", ).getOrNull() + val exchangeDataCex = exchangeData?.transaction as? ExpressTransactionModel.CEX ?: return TxState.UnknownError + val txExtras = transactionManager.getMemoExtras( + currencyToSend.currency.network.backendId, + exchangeDataCex.txExtraId, + ) + if (txExtras == null && exchangeDataCex.txExtraId != null) { + return TxState.UnknownError + } val txData = walletManagersFacade.createTransaction( amount = amount.value.convertToAmount(currencyToSend.currency), fee = getFeeForTransaction(txFee), memo = null, - destination = (exchangeData?.transaction as ExpressTransactionModel.CEX).txTo, + destination = exchangeDataCex.txTo, userWalletId = userWalletId, network = currencyToSend.currency.network, + )?.copy( + extras = txExtras, ) val result = sendTransactionUseCase( diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt index 06039c3878..1e23353d4a 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt @@ -563,14 +563,14 @@ internal class TokenDetailsViewModel @Inject constructor( override fun onSwapPromoDismiss() { viewModelScope.launch(dispatchers.main) { - shouldShowSwapPromoTokenUseCase.neverToShow(userWalletId.stringValue, cryptoCurrency.id.value) + shouldShowSwapPromoTokenUseCase.neverToShow() analyticsEventsHandler.send(TokenSwapPromoAnalyticsEvent.Close) } } override fun onSwapPromoClick() { viewModelScope.launch(dispatchers.main) { - shouldShowSwapPromoTokenUseCase.neverToShow(userWalletId.stringValue, cryptoCurrency.id.value) + shouldShowSwapPromoTokenUseCase.neverToShow() analyticsEventsHandler.send(TokenSwapPromoAnalyticsEvent.Exchange(cryptoCurrency.symbol)) } onSwapClick() diff --git a/gradle/dependencies.toml b/gradle/dependencies.toml index 5557fb257d..6a3614624a 100644 --- a/gradle/dependencies.toml +++ b/gradle/dependencies.toml @@ -88,7 +88,7 @@ spr-client = "3.6.2" # endregion Other libraries # region Tangem -tangemBlockchainSdk = "release-app_5.4-417" +tangemBlockchainSdk = "release-app_5.4-419" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds tangemCardSdk = "release-app_5.4-315" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ diff --git a/libs/crypto/build.gradle.kts b/libs/crypto/build.gradle.kts index 248cc20bd1..60b1f6f10e 100644 --- a/libs/crypto/build.gradle.kts +++ b/libs/crypto/build.gradle.kts @@ -1,5 +1,8 @@ plugins { - alias(deps.plugins.kotlin.jvm) + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) + alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.kotlin.serialization) id("configuration") } @@ -7,4 +10,7 @@ dependencies { /** Coroutines */ implementation(deps.kotlin.coroutines) + + /** SDK */ + implementation(deps.tangem.blockchain) } \ No newline at end of file diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/TransactionManager.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/TransactionManager.kt index 3aa47352d5..ee8eb94937 100644 --- a/libs/crypto/src/main/java/com/tangem/lib/crypto/TransactionManager.kt +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/TransactionManager.kt @@ -1,5 +1,6 @@ package com.tangem.lib.crypto +import com.tangem.blockchain.common.TransactionExtras import com.tangem.lib.crypto.models.* import com.tangem.lib.crypto.models.transactions.SendTxResult import java.math.BigDecimal @@ -71,4 +72,7 @@ interface TransactionManager { @Throws(IllegalStateException::class) fun getExplorerTransactionLink(networkId: String, txAddress: String): String + + // TODO: move to another place to use as in Send feature + fun getMemoExtras(networkId: String, memo: String?): TransactionExtras? } \ No newline at end of file