From a3a18854c8a37abb35115df5d7a462c65c05d705 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 23 Apr 2025 13:28:11 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../auth/DefaultExpressAuthProvider.kt | 56 +--- .../tangem/tap/network/auth/di/AuthModule.kt | 12 +- .../datasource/api/common/config/Express.kt | 2 - .../api/express/TangemExpressApi.kt | 38 ++- .../tangem/datasource/api/onramp/OnrampApi.kt | 43 ++- .../swap/DefaultExpressServiceLoader.kt | 16 +- .../swap/ExpressServiceLoader.kt | 5 +- .../exchangeservice/swap/ExpressUtils.kt | 46 +++ .../managers/ProdApiConfigsManagerTest.kt | 4 - .../data/onramp/DefaultOnrampRepository.kt | 265 +++++++++++------- .../repository/DefaultCurrenciesRepository.kt | 8 +- .../onramp/CheckOnrampAvailabilityUseCase.kt | 16 +- .../onramp/FetchOnrampCountriesUseCase.kt | 5 +- .../onramp/FetchOnrampCurrenciesUseCase.kt | 5 +- .../domain/onramp/GetOnrampCountryUseCase.kt | 5 +- .../onramp/GetOnrampRedirectUrlUseCase.kt | 6 +- .../domain/onramp/GetOnrampStatusUseCase.kt | 5 +- .../domain/onramp/OnrampFetchPairsUseCase.kt | 10 +- .../domain/onramp/OnrampFetchQuotesUseCase.kt | 4 +- .../onramp/repositories/OnrampRepository.kt | 24 +- .../ConfirmResidencyComponent.kt | 2 + .../DefaultConfirmResidencyComponent.kt | 1 + .../onramp/main/DefaultOnrampMainComponent.kt | 2 + .../main/model/OnrampMainComponentModel.kt | 11 +- .../redirect/model/OnrampRedirectModel.kt | 6 +- .../onramp/root/DefaultOnrampComponent.kt | 5 +- .../selectcountry/SelectCountryComponent.kt | 7 +- .../model/OnrampSelectCountryModel.kt | 9 +- .../selectcurrency/SelectCurrencyComponent.kt | 7 +- .../model/OnrampSelectCurrencyModel.kt | 2 +- .../DefaultOnrampSettingsComponent.kt | 3 +- .../settings/OnrampSettingsComponent.kt | 7 +- .../model/OnrampSuccessComponentModel.kt | 2 +- .../model/AvailableSwapPairsModel.kt | 4 + .../feature/swap/DefaultSwapRepository.kt | 62 +++- .../swap/DefaultSwapTransactionRepository.kt | 9 +- .../tangem/feature/swap/di/SwapDataModule.kt | 2 + .../feature/swap/domain/api/SwapRepository.kt | 19 +- .../swap/domain/GetAvailablePairsUseCase.kt | 8 +- .../feature/swap/domain/SwapInteractorImpl.kt | 16 +- .../swap/domain/SwapTransactionRepository.kt | 5 +- .../tokendetails/model/TokenDetailsModel.kt | 6 +- .../factory/express/ExchangeStatusFactory.kt | 22 +- .../factory/express/ExpressStatusFactory.kt | 12 +- .../factory/express/OnrampStatusFactory.kt | 10 +- .../wallet/child/wallet/model/WalletModel.kt | 44 +-- .../wallet/domain/OnrampStatusFactory.kt | 9 +- .../tangem/lib/auth/ExpressAuthProvider.kt | 5 - 48 files changed, 544 insertions(+), 328 deletions(-) create mode 100644 core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/ExpressUtils.kt diff --git a/app/src/main/java/com/tangem/tap/network/auth/DefaultExpressAuthProvider.kt b/app/src/main/java/com/tangem/tap/network/auth/DefaultExpressAuthProvider.kt index 5087ef7019..15e74c5498 100644 --- a/app/src/main/java/com/tangem/tap/network/auth/DefaultExpressAuthProvider.kt +++ b/app/src/main/java/com/tangem/tap/network/auth/DefaultExpressAuthProvider.kt @@ -1,68 +1,14 @@ package com.tangem.tap.network.auth -import com.tangem.common.CardIdRangeDec -import com.tangem.datasource.local.preferences.AppPreferencesStore -import com.tangem.datasource.local.preferences.PreferencesKeys -import com.tangem.datasource.local.preferences.utils.getSyncOrDefault -import com.tangem.datasource.local.userwallet.UserWalletsStore -import com.tangem.domain.wallets.models.UserWallet import com.tangem.lib.auth.ExpressAuthProvider -import kotlinx.coroutines.runBlocking import java.util.UUID import java.util.concurrent.atomic.AtomicReference -internal class DefaultExpressAuthProvider( - private val userWalletsStore: UserWalletsStore, - private val appPreferencesStore: AppPreferencesStore, -) : ExpressAuthProvider { +internal class DefaultExpressAuthProvider : ExpressAuthProvider { private var uuid = AtomicReference(UUID.randomUUID()) - override fun getUserId(): String { - return userWalletsStore.selectedUserWalletOrNull?.walletId?.stringValue ?: error("No user id provided") - } - override fun getSessionId(): String { return uuid.get().toString() } - - override fun getRefCode(): String { - val selectedUserWallet = userWalletsStore.selectedUserWalletOrNull ?: error("Can not get selected user wallet") - - return when { - isRing(selectedUserWallet) -> "ring" - isChangeNow(selectedUserWallet) -> "ChangeNow" - isPartner(selectedUserWallet) -> "partner" - else -> "" - } - } - - private fun isRing(selectedUserWallet: UserWallet): Boolean { - val addedWalletsWithRings = runBlocking { - appPreferencesStore.getSyncOrDefault( - key = PreferencesKeys.ADDED_WALLETS_WITH_RING_KEY, - default = emptySet(), - ) - } - - return addedWalletsWithRings.contains(selectedUserWallet.walletId.stringValue) - } - - private fun isChangeNow(selectedUserWallet: UserWallet): Boolean { - val changeNowRange = CardIdRangeDec( - start = "AF99001800554008", - end = "AF99001800559994", - ) - val card = selectedUserWallet.scanResponse.card - return card.batchId == BATCH_ID_CHANGENOW || changeNowRange?.contains(card.cardId) == true - } - - private fun isPartner(selectedUserWallet: UserWallet): Boolean { - return selectedUserWallet.scanResponse.card.batchId == BATCH_ID_PARTNER - } - - private companion object { - const val BATCH_ID_CHANGENOW = "BB000013" - const val BATCH_ID_PARTNER = "AF990015" - } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt b/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt index c72a9c145c..5f724624af 100644 --- a/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt +++ b/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt @@ -2,8 +2,6 @@ package com.tangem.tap.network.auth.di import com.tangem.datasource.api.common.AuthProvider import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage -import com.tangem.datasource.local.preferences.AppPreferencesStore -import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.lib.auth.ExpressAuthProvider import com.tangem.lib.auth.StakeKitAuthProvider @@ -30,14 +28,8 @@ internal class AuthModule { @Provides @Singleton - fun provideExpressAuthProvider( - userWalletsStore: UserWalletsStore, - appPreferencesStore: AppPreferencesStore, - ): ExpressAuthProvider { - return DefaultExpressAuthProvider( - userWalletsStore = userWalletsStore, - appPreferencesStore = appPreferencesStore, - ) + fun provideExpressAuthProvider(): ExpressAuthProvider { + return DefaultExpressAuthProvider() } @Provides diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/Express.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/Express.kt index 3babcef973..db32d40409 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/Express.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/Express.kt @@ -48,10 +48,8 @@ internal class Express( private fun createHeaders(isProd: Boolean) = buildMap { put(key = "api-key", value = ProviderSuspend { getApiKey(isProd) }) - put(key = "user-id", value = ProviderSuspend(expressAuthProvider::getUserId)) put(key = "session-id", value = ProviderSuspend(expressAuthProvider::getSessionId)) putAll(from = RequestHeader.AppVersionPlatformHeaders(appVersionProvider).values) - put(key = "refcode", value = ProviderSuspend(expressAuthProvider::getRefCode)) } private fun getApiKey(isProd: Boolean): String { diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/express/TangemExpressApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/express/TangemExpressApi.kt index 54a7935d66..469ab8a516 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/express/TangemExpressApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/express/TangemExpressApi.kt @@ -5,10 +5,7 @@ import com.tangem.datasource.api.express.models.request.AssetsRequestBody import com.tangem.datasource.api.express.models.request.ExchangeSentRequestBody import com.tangem.datasource.api.express.models.request.PairsRequestBody import com.tangem.datasource.api.express.models.response.* -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* /** * Interface of Tangem Express API (new swap mechanism) @@ -17,16 +14,29 @@ import retrofit2.http.Query interface TangemExpressApi { @POST("assets") - suspend fun getAssets(@Body body: AssetsRequestBody): ApiResponse> + suspend fun getAssets( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, + @Body body: AssetsRequestBody, + ): ApiResponse> @POST("pairs") - suspend fun getPairs(@Body body: PairsRequestBody): ApiResponse> + suspend fun getPairs( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, + @Body body: PairsRequestBody, + ): ApiResponse> @GET("providers") - suspend fun getProviders(): ApiResponse> + suspend fun getProviders( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, + ): ApiResponse> @GET("exchange-quote") suspend fun getExchangeQuote( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, @Query("fromContractAddress") fromContractAddress: String, @Query("fromNetwork") fromNetwork: String, @Query("toContractAddress") toContractAddress: String, @@ -40,6 +50,8 @@ interface TangemExpressApi { @GET("exchange-data") suspend fun getExchangeData( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, @Query("fromContractAddress") fromContractAddress: String, @Query("fromNetwork") fromNetwork: String, @Query("toContractAddress") toContractAddress: String, @@ -57,8 +69,16 @@ interface TangemExpressApi { ): ApiResponse @GET("exchange-status") - suspend fun getExchangeStatus(@Query("txId") txId: String): ApiResponse + suspend fun getExchangeStatus( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, + @Query("txId") txId: String, + ): ApiResponse @POST("exchange-sent") - suspend fun exchangeSent(@Body body: ExchangeSentRequestBody): ApiResponse + suspend fun exchangeSent( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, + @Body body: ExchangeSentRequestBody, + ): ApiResponse } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/onramp/OnrampApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/onramp/OnrampApi.kt index 2a8034b8b1..433cf8b3eb 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/onramp/OnrampApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/onramp/OnrampApi.kt @@ -3,37 +3,52 @@ package com.tangem.datasource.api.onramp import com.tangem.datasource.api.common.response.ApiResponse import com.tangem.datasource.api.onramp.models.request.OnrampPairsRequest import com.tangem.datasource.api.onramp.models.response.OnrampDataResponse -import com.tangem.datasource.api.onramp.models.response.model.OnrampPairDTO import com.tangem.datasource.api.onramp.models.response.OnrampQuoteResponse import com.tangem.datasource.api.onramp.models.response.OnrampStatusResponse import com.tangem.datasource.api.onramp.models.response.model.OnrampCountryDTO import com.tangem.datasource.api.onramp.models.response.model.OnrampCurrencyDTO +import com.tangem.datasource.api.onramp.models.response.model.OnrampPairDTO import com.tangem.datasource.api.onramp.models.response.model.PaymentMethodDTO -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* @Suppress("LongParameterList", "LargeClass", "TooManyFunctions") interface OnrampApi { @GET("currencies") - suspend fun getCurrencies(): ApiResponse> + suspend fun getCurrencies( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, + ): ApiResponse> @GET("countries") - suspend fun getCountries(): ApiResponse> + suspend fun getCountries( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, + ): ApiResponse> @GET("country-by-ip") - suspend fun getCountryByIp(): ApiResponse + suspend fun getCountryByIp( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, + ): ApiResponse @GET("payment-methods") - suspend fun getPaymentMethods(): ApiResponse> + suspend fun getPaymentMethods( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, + ): ApiResponse> @POST("onramp-pairs") - suspend fun getPairs(@Body body: OnrampPairsRequest): ApiResponse> + suspend fun getPairs( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, + @Body body: OnrampPairsRequest, + ): ApiResponse> @GET("onramp-quote") suspend fun getQuote( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, @Query("fromCurrencyCode") fromCurrencyCode: String, @Query("fromPrecision") fromPrecision: Int, @Query("toContractAddress") toContractAddress: String, @@ -47,6 +62,8 @@ interface OnrampApi { @GET("onramp-data") suspend fun getData( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, @Query("fromCurrencyCode") fromCurrencyCode: String, @Query("fromPrecision") fromPrecision: Int, @Query("toContractAddress") toContractAddress: String, @@ -64,5 +81,9 @@ interface OnrampApi { ): ApiResponse @GET("onramp-status") - suspend fun getStatus(@Query("txId") txId: String): ApiResponse + suspend fun getStatus( + @Header("user-id") userWalletId: String, + @Header("refcode") refCode: String, + @Query("txId") txId: String, + ): ApiResponse } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/DefaultExpressServiceLoader.kt b/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/DefaultExpressServiceLoader.kt index b966a12e0e..c89a7f0d1d 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/DefaultExpressServiceLoader.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/DefaultExpressServiceLoader.kt @@ -5,11 +5,14 @@ import com.tangem.datasource.api.express.TangemExpressApi import com.tangem.datasource.api.express.models.request.AssetsRequestBody import com.tangem.datasource.api.express.models.request.LeastTokenInfo import com.tangem.datasource.api.express.models.response.Asset +import com.tangem.datasource.exchangeservice.swap.ExpressUtils.getRefCode +import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.token.ExpressAssetsStore import com.tangem.domain.core.lce.Lce import com.tangem.domain.core.utils.lceContent import com.tangem.domain.core.utils.lceError import com.tangem.domain.core.utils.lceLoading +import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.Flow @@ -33,31 +36,34 @@ typealias InitializationStatusFlow = MutableStateFlow internal class DefaultExpressServiceLoader @Inject constructor( private val tangemExpressApi: TangemExpressApi, private val expressAssetsStore: ExpressAssetsStore, + private val appPreferencesStore: AppPreferencesStore, private val dispatchers: CoroutineDispatcherProvider, ) : ExpressServiceLoader { private val initializationStatuses = MutableStateFlow>(value = emptyMap()) - override suspend fun update(userWalletId: UserWalletId, userTokens: List) { + override suspend fun update(userWallet: UserWallet, userTokens: List) { withContext(dispatchers.io) { - val initializationStatus = getInitializationStatusInternal(userWalletId) + val initializationStatus = getInitializationStatusInternal(userWallet.walletId) try { if (userTokens.isNotEmpty()) { val response = tangemExpressApi.getAssets( + userWalletId = userWallet.walletId.stringValue, + refCode = getRefCode(userWallet, appPreferencesStore), body = AssetsRequestBody(tokensList = userTokens), ).getOrThrow() - expressAssetsStore.store(userWalletId, response) + expressAssetsStore.store(userWallet.walletId, response) initializationStatus.update { response.lceContent() } } } catch (e: Throwable) { - if (expressAssetsStore.getSyncOrNull(userWalletId) == null) { + if (expressAssetsStore.getSyncOrNull(userWallet.walletId) == null) { initializationStatus.update { e.lceError() } } - Timber.e(e, "Unable to fetch assets for: ${userWalletId.stringValue}") + Timber.e(e, "Unable to fetch assets for: ${userWallet.walletId.stringValue}") } } } diff --git a/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/ExpressServiceLoader.kt b/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/ExpressServiceLoader.kt index f73ee82700..38d07ae3f1 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/ExpressServiceLoader.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/ExpressServiceLoader.kt @@ -3,6 +3,7 @@ package com.tangem.datasource.exchangeservice.swap import com.tangem.datasource.api.express.models.request.LeastTokenInfo import com.tangem.datasource.api.express.models.response.Asset import com.tangem.domain.core.lce.Lce +import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import kotlinx.coroutines.flow.Flow @@ -13,8 +14,8 @@ import kotlinx.coroutines.flow.Flow */ interface ExpressServiceLoader { - /** Update service using [userWalletId] and [userTokens] */ - suspend fun update(userWalletId: UserWalletId, userTokens: List) + /** Update service using [userWallet] and [userTokens] */ + suspend fun update(userWallet: UserWallet, userTokens: List) /** Get initialization status by [userWalletId] */ fun getInitializationStatus(userWalletId: UserWalletId): Flow>> diff --git a/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/ExpressUtils.kt b/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/ExpressUtils.kt new file mode 100644 index 0000000000..50d0877467 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/exchangeservice/swap/ExpressUtils.kt @@ -0,0 +1,46 @@ +package com.tangem.datasource.exchangeservice.swap + +import com.tangem.common.CardIdRangeDec +import com.tangem.datasource.local.preferences.AppPreferencesStore +import com.tangem.datasource.local.preferences.PreferencesKeys +import com.tangem.datasource.local.preferences.utils.getSyncOrDefault +import com.tangem.domain.wallets.models.UserWallet +import kotlinx.coroutines.runBlocking + +object ExpressUtils { + private const val BATCH_ID_CHANGENOW = "BB000013" + private const val BATCH_ID_PARTNER = "AF990015" + + fun getRefCode(userWallet: UserWallet, appPreferencesStore: AppPreferencesStore): String { + return when { + isRing(userWallet, appPreferencesStore) -> "ring" + isChangeNow(userWallet) -> "ChangeNow" + isPartner(userWallet) -> "partner" + else -> "" + } + } + + private fun isRing(selectedUserWallet: UserWallet, appPreferencesStore: AppPreferencesStore): Boolean { + val addedWalletsWithRings = runBlocking { + appPreferencesStore.getSyncOrDefault( + key = PreferencesKeys.ADDED_WALLETS_WITH_RING_KEY, + default = emptySet(), + ) + } + + return addedWalletsWithRings.contains(selectedUserWallet.walletId.stringValue) + } + + private fun isChangeNow(selectedUserWallet: UserWallet): Boolean { + val changeNowRange = CardIdRangeDec( + start = "AF99001800554008", + end = "AF99001800559994", + ) + val card = selectedUserWallet.scanResponse.card + return card.batchId == BATCH_ID_CHANGENOW || changeNowRange?.contains(card.cardId) == true + } + + private fun isPartner(selectedUserWallet: UserWallet): Boolean { + return selectedUserWallet.scanResponse.card.batchId == BATCH_ID_PARTNER + } +} \ No newline at end of file diff --git a/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/managers/ProdApiConfigsManagerTest.kt b/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/managers/ProdApiConfigsManagerTest.kt index 6537f31453..2624ca1707 100644 --- a/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/managers/ProdApiConfigsManagerTest.kt +++ b/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/managers/ProdApiConfigsManagerTest.kt @@ -50,9 +50,7 @@ internal class ProdApiConfigsManagerTest(private val model: Model) { @Before fun setup() { every { appVersionProvider.versionName } returns VERSION_NAME - every { expressAuthProvider.getUserId() } returns EXPRESS_USER_ID every { expressAuthProvider.getSessionId() } returns EXPRESS_SESSION_ID - every { expressAuthProvider.getRefCode() } returns EXPRESS_REF_CODE every { stakeKitAuthProvider.getApiKey() } returns STAKE_KIT_API_KEY every { appAuthProvider.getCardId() } returns APP_CARD_ID every { appAuthProvider.getCardPublicKey() } returns APP_CARD_PUBLIC_KEY @@ -131,9 +129,7 @@ internal class ProdApiConfigsManagerTest(private val model: Model) { MockEnvironmentConfigStorage.EXPRESS_DEV_API_KEY } }, - "user-id" to ProviderSuspend { EXPRESS_USER_ID }, "session-id" to ProviderSuspend { EXPRESS_SESSION_ID }, - "refcode" to ProviderSuspend { EXPRESS_REF_CODE }, "version" to ProviderSuspend { VERSION_NAME }, "platform" to ProviderSuspend { "android" }, "language" to ProviderSuspend { Locale.getDefault().language.checkHeaderValueOrEmpty() }, diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt index 578611fb04..479cb8c590 100644 --- a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt +++ b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt @@ -24,6 +24,7 @@ import com.tangem.datasource.api.onramp.models.response.model.OnrampCountryDTO import com.tangem.datasource.api.onramp.models.response.model.OnrampPairDTO import com.tangem.datasource.api.onramp.models.response.model.PaymentMethodDTO import com.tangem.datasource.crypto.DataSignatureVerifier +import com.tangem.datasource.exchangeservice.swap.ExpressUtils import com.tangem.datasource.local.onramp.countries.OnrampCountriesStore import com.tangem.datasource.local.onramp.currencies.OnrampCurrenciesStore import com.tangem.datasource.local.onramp.pairs.OnrampPairsStore @@ -43,6 +44,7 @@ import com.tangem.domain.onramp.repositories.OnrampRepository import com.tangem.domain.tokens.model.Amount import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.walletmanager.WalletManagersFacade +import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.NonCancellable @@ -82,10 +84,16 @@ internal class DefaultOnrampRepository( override fun getCurrencies(): Flow> = currenciesStore.get(CURRENCIES_KEY) - override suspend fun fetchCurrencies() = withContext(dispatchers.io) { + override suspend fun fetchCurrencies(userWallet: UserWallet) = withContext(dispatchers.io) { if (!currenciesStore.getSyncOrNull(CURRENCIES_KEY).isNullOrEmpty()) return@withContext - val result = onrampApi.getCurrencies() + val result = onrampApi.getCurrencies( + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), + ) .getOrThrow() .map(currencyConverter::convert) @@ -98,10 +106,16 @@ internal class DefaultOnrampRepository( return countriesStore.getSyncOrNull(COUNTRIES_KEY) } - override suspend fun fetchCountries(): List = withContext(dispatchers.io) { + override suspend fun fetchCountries(userWallet: UserWallet): List = withContext(dispatchers.io) { if (!countriesStore.getSyncOrNull(COUNTRIES_KEY).isNullOrEmpty()) return@withContext emptyList() - val result = onrampApi.getCountries() + val result = onrampApi.getCountries( + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), + ) .getOrThrow() .map(countryConverter::convert) @@ -110,14 +124,27 @@ internal class DefaultOnrampRepository( result } - override suspend fun getCountryByIp(): OnrampCountry = withContext(dispatchers.io) { - onrampApi.getCountryByIp() + override suspend fun getCountryByIp(userWallet: UserWallet): OnrampCountry = withContext(dispatchers.io) { + onrampApi.getCountryByIp( + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), + ) .getOrThrow() .let(countryConverter::convert) } - override suspend fun getStatus(txId: String): OnrampStatus = withContext(dispatchers.io) { - onrampApi.getStatus(txId) + override suspend fun getStatus(userWallet: UserWallet, txId: String): OnrampStatus = withContext(dispatchers.io) { + onrampApi.getStatus( + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), + txId = txId, + ) .getOrThrow() .let(statusConverter::convert) } @@ -161,11 +188,19 @@ internal class DefaultOnrampRepository( .map { it?.let(countryConverter::convert) } } - override suspend fun fetchPaymentMethodsIfAbsent() = withContext(dispatchers.io) { + override suspend fun fetchPaymentMethodsIfAbsent(userWallet: UserWallet) = withContext(dispatchers.io) { if (paymentMethodsStore.contains(PAYMENT_METHODS_KEY)) return@withContext val response = safeApiCall( - call = { onrampApi.getPaymentMethods().bind() }, + call = { + onrampApi.getPaymentMethods( + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), + ).bind() + }, onError = { Timber.w(it, "Unable to fetch onramp payment methods") throw it @@ -174,100 +209,123 @@ internal class DefaultOnrampRepository( paymentMethodsStore.store(PAYMENT_METHODS_KEY, response.removeApplePay()) } - override suspend fun fetchPairs(currency: OnrampCurrency, country: OnrampCountry, cryptoCurrency: CryptoCurrency) = - withContext(dispatchers.io) { - val onrampPairs = async { - safeApiCall( - call = { - onrampApi.getPairs( - body = OnrampPairsRequest( - fromCurrencyCode = currency.code, - countryCode = country.code, - to = listOf( - OnrampDestinationDTO( - contractAddress = cryptoCurrency.getContractAddress(), - network = cryptoCurrency.network.backendId, - ), + override suspend fun fetchPairs( + userWallet: UserWallet, + currency: OnrampCurrency, + country: OnrampCountry, + cryptoCurrency: CryptoCurrency, + ) = withContext(dispatchers.io) { + val onrampPairs = async { + safeApiCall( + call = { + onrampApi.getPairs( + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), + body = OnrampPairsRequest( + fromCurrencyCode = currency.code, + countryCode = country.code, + to = listOf( + OnrampDestinationDTO( + contractAddress = cryptoCurrency.getContractAddress(), + network = cryptoCurrency.network.backendId, ), ), - ).bind() - }, - onError = { - Timber.w(it, "Unable to fetch onramp pairs") - throw it - }, - ) - } - val providers = async { - safeApiCall( - call = { expressApi.getProviders().bind() }, - onError = { - Timber.w(it, "Unable to fetch express providers") - throw it - }, - ) - } - storeOnrampPairs(pairs = onrampPairs.await(), providers = providers.await()) + ), + ).bind() + }, + onError = { + Timber.w(it, "Unable to fetch onramp pairs") + throw it + }, + ) } + val providers = async { + safeApiCall( + call = { + expressApi.getProviders( + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), + ).bind() + }, + onError = { + Timber.w(it, "Unable to fetch express providers") + throw it + }, + ) + } + storeOnrampPairs(pairs = onrampPairs.await(), providers = providers.await()) + } - override suspend fun fetchQuotes(cryptoCurrency: CryptoCurrency, amount: Amount) = withContext(dispatchers.io) { - val pairs = requireNotNull(pairsStore.getSyncOrNull(PAIRS_KEY)) { - "Unable to get pairs. At this point they must not be null." - } - val amountValue = requireNotNull(amount.value) { "Amount value must not be null" } - val fromAmount = amountValue.movePointRight(amount.decimals).toString() - val currency = requireNotNull(getDefaultCurrencySync()) { "Default currency must not be null" } - val country = requireNotNull(getDefaultCountrySync()) { "Default country must not be null" } - val fromOnrampAmount = OnrampAmount( - value = fromAmount - .toBigDecimalOrDefault() - .movePointLeft(currency.precision), - decimals = currency.precision, - symbol = amount.currencySymbol, - ) - val quotes: List = pairs.flatMap { pair -> - pair.providers.flatMap { provider -> - provider.paymentMethods.map { paymentMethod -> - async { - safeApiCall( - call = { - val response = onrampApi.getQuote( - fromCurrencyCode = currency.code, - fromPrecision = currency.precision, - toContractAddress = cryptoCurrency.getContractAddress(), - toNetwork = cryptoCurrency.network.backendId, - paymentMethod = paymentMethod.id, - countryCode = country.code, - fromAmount = fromAmount, - toDecimals = cryptoCurrency.decimals, - providerId = provider.id, - ).bind() - OnrampQuote.Data( - fromAmount = fromOnrampAmount, - toAmount = convertToAmount(response.toAmount, cryptoCurrency), - minFromAmount = convertToAmount(response.minFromAmount, cryptoCurrency), - maxFromAmount = convertToAmount(response.maxFromAmount, cryptoCurrency), - paymentMethod = paymentMethod, - provider = provider, - countryCode = response.countryCode, - ) - }, - onError = { error -> - convertQuoteError( - error = error, - paymentMethod = paymentMethod, - provider = provider, - fromOnrampAmount = fromOnrampAmount, - countryCode = country.code, - ) - }, - ) + override suspend fun fetchQuotes(userWallet: UserWallet, cryptoCurrency: CryptoCurrency, amount: Amount) = + withContext(dispatchers.io) { + val pairs = requireNotNull(pairsStore.getSyncOrNull(PAIRS_KEY)) { + "Unable to get pairs. At this point they must not be null." + } + val amountValue = requireNotNull(amount.value) { "Amount value must not be null" } + val fromAmount = amountValue.movePointRight(amount.decimals).toString() + val currency = requireNotNull(getDefaultCurrencySync()) { "Default currency must not be null" } + val country = requireNotNull(getDefaultCountrySync()) { "Default country must not be null" } + val fromOnrampAmount = OnrampAmount( + value = fromAmount + .toBigDecimalOrDefault() + .movePointLeft(currency.precision), + decimals = currency.precision, + symbol = amount.currencySymbol, + ) + val quotes: List = pairs.flatMap { pair -> + pair.providers.flatMap { provider -> + provider.paymentMethods.map { paymentMethod -> + async { + safeApiCall( + call = { + val response = onrampApi.getQuote( + fromCurrencyCode = currency.code, + fromPrecision = currency.precision, + toContractAddress = cryptoCurrency.getContractAddress(), + toNetwork = cryptoCurrency.network.backendId, + paymentMethod = paymentMethod.id, + countryCode = country.code, + fromAmount = fromAmount, + toDecimals = cryptoCurrency.decimals, + providerId = provider.id, + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), + ).bind() + OnrampQuote.Data( + fromAmount = fromOnrampAmount, + toAmount = convertToAmount(response.toAmount, cryptoCurrency), + minFromAmount = convertToAmount(response.minFromAmount, cryptoCurrency), + maxFromAmount = convertToAmount(response.maxFromAmount, cryptoCurrency), + paymentMethod = paymentMethod, + provider = provider, + countryCode = response.countryCode, + ) + }, + onError = { error -> + convertQuoteError( + error = error, + paymentMethod = paymentMethod, + provider = provider, + fromOnrampAmount = fromOnrampAmount, + countryCode = country.code, + ) + }, + ) + } } } - } - }.awaitAll().filterNotNull() - quotesStore.store(QUOTES_KEY, quotes) - } + }.awaitAll().filterNotNull() + quotesStore.store(QUOTES_KEY, quotes) + } override fun getQuotes(): Flow> { return quotesStore.get(QUOTES_KEY) @@ -278,14 +336,14 @@ internal class DefaultOnrampRepository( } override suspend fun getOnrampData( - userWalletId: UserWalletId, + userWallet: UserWallet, cryptoCurrency: CryptoCurrency, quote: OnrampProviderWithQuote.Data, isDarkTheme: Boolean, ): OnrampTransaction = withContext(dispatchers.io) { try { val address = requireNotNull( - value = walletManagersFacade.getDefaultAddress(userWalletId, cryptoCurrency.network), + value = walletManagersFacade.getDefaultAddress(userWallet.walletId, cryptoCurrency.network), lazyMessage = { "Address must not be null" }, ) val fromAmountString = quote.fromAmount.value.movePointRight(quote.fromAmount.decimals).toString() @@ -309,6 +367,11 @@ internal class DefaultOnrampRepository( language = null, theme = getTheme(isDarkTheme), requestId = requestId, + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), ).bind() }, onError = { e -> @@ -326,7 +389,7 @@ internal class DefaultOnrampRepository( txId = data.txId, quote = quote, onrampDataJson = dataJson, - userWalletId = userWalletId, + userWalletId = userWallet.walletId, currency = currency, cryptoCurrency = cryptoCurrency, residency = country.name, diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt index 6e893fe151..9454dd4a87 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/repository/DefaultCurrenciesRepository.kt @@ -618,7 +618,7 @@ internal class DefaultCurrenciesRepository( } coroutineScope { - launch { expressServiceLoader.update(userWalletId, tokens) } + launch { expressServiceLoader.update(getUserWallet(userWalletId), tokens) } } } @@ -639,7 +639,7 @@ internal class DefaultCurrenciesRepository( skipCache = refresh, block = { coroutineScope { - launch { expressServiceLoader.update(userWalletId, tokens) } + launch { expressServiceLoader.update(getUserWallet(userWalletId), tokens) } } }, ) @@ -677,13 +677,13 @@ internal class DefaultCurrenciesRepository( isSortedByBalance = false, ) - private suspend fun getUserWallet(userWalletId: UserWalletId): UserWallet { + private fun getUserWallet(userWalletId: UserWalletId): UserWallet { return requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) { "Unable to find a user wallet with provided ID: $userWalletId" } } - private suspend fun ensureIsCorrectUserWallet(userWalletId: UserWalletId, isMultiCurrencyWalletExpected: Boolean) { + private fun ensureIsCorrectUserWallet(userWalletId: UserWalletId, isMultiCurrencyWalletExpected: Boolean) { val userWallet = getUserWallet(userWalletId) ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected) diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/CheckOnrampAvailabilityUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/CheckOnrampAvailabilityUseCase.kt index 60cb522991..911ca71568 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/CheckOnrampAvailabilityUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/CheckOnrampAvailabilityUseCase.kt @@ -6,27 +6,31 @@ import com.tangem.domain.onramp.model.OnrampCountry import com.tangem.domain.onramp.model.error.OnrampError import com.tangem.domain.onramp.repositories.OnrampErrorResolver import com.tangem.domain.onramp.repositories.OnrampRepository +import com.tangem.domain.wallets.models.UserWallet class CheckOnrampAvailabilityUseCase( private val repository: OnrampRepository, private val errorResolver: OnrampErrorResolver, ) { - suspend operator fun invoke(): Either { + suspend operator fun invoke(userWallet: UserWallet): Either { return Either.catch { - repository.fetchPaymentMethodsIfAbsent() + repository.fetchPaymentMethodsIfAbsent(userWallet) val savedCountry = repository.getDefaultCountrySync() if (savedCountry != null) { - proceedWithSavedCountry(savedCountry = savedCountry) + proceedWithSavedCountry(userWallet = userWallet, savedCountry = savedCountry) } else { - val detectedCountry = repository.getCountryByIp() + val detectedCountry = repository.getCountryByIp(userWallet) OnrampAvailability.ConfirmResidency(detectedCountry) } }.mapLeft(errorResolver::resolve) } - private suspend fun proceedWithSavedCountry(savedCountry: OnrampCountry): OnrampAvailability { - val countries = repository.fetchCountries() + private suspend fun proceedWithSavedCountry( + userWallet: UserWallet, + savedCountry: OnrampCountry, + ): OnrampAvailability { + val countries = repository.fetchCountries(userWallet) val updatedCountry = countries.find { it.id == savedCountry.id } ?: savedCountry return if (updatedCountry.onrampAvailable) { val currency = repository.getDefaultCurrencySync() ?: run { diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/FetchOnrampCountriesUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/FetchOnrampCountriesUseCase.kt index 1920178751..5c9cd186d9 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/FetchOnrampCountriesUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/FetchOnrampCountriesUseCase.kt @@ -4,13 +4,14 @@ import arrow.core.Either import com.tangem.domain.onramp.model.error.OnrampError import com.tangem.domain.onramp.repositories.OnrampErrorResolver import com.tangem.domain.onramp.repositories.OnrampRepository +import com.tangem.domain.wallets.models.UserWallet class FetchOnrampCountriesUseCase( private val repository: OnrampRepository, private val errorResolver: OnrampErrorResolver, ) { - suspend operator fun invoke(): Either { - return Either.catch { repository.fetchCountries() }.mapLeft(errorResolver::resolve) + suspend operator fun invoke(userWallet: UserWallet): Either { + return Either.catch { repository.fetchCountries(userWallet) }.mapLeft(errorResolver::resolve) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/FetchOnrampCurrenciesUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/FetchOnrampCurrenciesUseCase.kt index d1a15ca673..facbee7dab 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/FetchOnrampCurrenciesUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/FetchOnrampCurrenciesUseCase.kt @@ -4,13 +4,14 @@ import arrow.core.Either import com.tangem.domain.onramp.model.error.OnrampError import com.tangem.domain.onramp.repositories.OnrampErrorResolver import com.tangem.domain.onramp.repositories.OnrampRepository +import com.tangem.domain.wallets.models.UserWallet class FetchOnrampCurrenciesUseCase( private val repository: OnrampRepository, private val errorResolver: OnrampErrorResolver, ) { - suspend operator fun invoke(): Either { - return Either.catch { repository.fetchCurrencies() }.mapLeft(errorResolver::resolve) + suspend operator fun invoke(userWallet: UserWallet): Either { + return Either.catch { repository.fetchCurrencies(userWallet) }.mapLeft(errorResolver::resolve) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountryUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountryUseCase.kt index 65c945e7b5..9802404640 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountryUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountryUseCase.kt @@ -7,6 +7,7 @@ import com.tangem.domain.onramp.model.OnrampCountry import com.tangem.domain.onramp.model.error.OnrampError import com.tangem.domain.onramp.repositories.OnrampErrorResolver import com.tangem.domain.onramp.repositories.OnrampRepository +import com.tangem.domain.wallets.models.UserWallet import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.map @@ -24,8 +25,8 @@ class GetOnrampCountryUseCase( } } - suspend fun invokeSync(): Either { - return Either.catch { repository.getDefaultCountrySync() ?: repository.getCountryByIp() } + suspend fun invokeSync(userWallet: UserWallet): Either { + return Either.catch { repository.getDefaultCountrySync() ?: repository.getCountryByIp(userWallet) } .mapLeft(errorResolver::resolve) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampRedirectUrlUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampRedirectUrlUseCase.kt index 55ba74a5bf..dae9cfdb2a 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampRedirectUrlUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampRedirectUrlUseCase.kt @@ -7,7 +7,7 @@ import com.tangem.domain.onramp.repositories.OnrampErrorResolver import com.tangem.domain.onramp.repositories.OnrampRepository import com.tangem.domain.onramp.repositories.OnrampTransactionRepository import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.domain.wallets.models.UserWallet class GetOnrampRedirectUrlUseCase( private val repository: OnrampRepository, @@ -16,14 +16,14 @@ class GetOnrampRedirectUrlUseCase( ) { suspend operator fun invoke( - userWalletId: UserWalletId, + userWallet: UserWallet, quote: OnrampProviderWithQuote.Data, cryptoCurrency: CryptoCurrency, isDarkTheme: Boolean, ): Either { return Either.catch { val transaction = repository.getOnrampData( - userWalletId = userWalletId, + userWallet = userWallet, cryptoCurrency = cryptoCurrency, quote = quote, isDarkTheme = isDarkTheme, diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampStatusUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampStatusUseCase.kt index 20effbbeeb..92afbf647c 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampStatusUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampStatusUseCase.kt @@ -5,15 +5,16 @@ import com.tangem.domain.onramp.model.OnrampStatus import com.tangem.domain.onramp.model.error.OnrampError import com.tangem.domain.onramp.repositories.OnrampErrorResolver import com.tangem.domain.onramp.repositories.OnrampRepository +import com.tangem.domain.wallets.models.UserWallet class GetOnrampStatusUseCase( private val onrampRepository: OnrampRepository, private val errorResolver: OnrampErrorResolver, ) { - suspend operator fun invoke(txId: String): Either { + suspend operator fun invoke(userWallet: UserWallet, txId: String): Either { return Either.catch { - onrampRepository.getStatus(txId) + onrampRepository.getStatus(userWallet = userWallet, txId = txId) }.mapLeft(errorResolver::resolve) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchPairsUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchPairsUseCase.kt index 1bbaf78853..2cc183e142 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchPairsUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchPairsUseCase.kt @@ -5,17 +5,23 @@ import com.tangem.domain.onramp.model.error.OnrampError import com.tangem.domain.onramp.repositories.OnrampErrorResolver import com.tangem.domain.onramp.repositories.OnrampRepository import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWallet class OnrampFetchPairsUseCase( private val repository: OnrampRepository, private val errorResolver: OnrampErrorResolver, ) { - suspend operator fun invoke(cryptoCurrency: CryptoCurrency): Either { + suspend operator fun invoke(userWallet: UserWallet, cryptoCurrency: CryptoCurrency): Either { return Either.catch { val country = requireNotNull(repository.getDefaultCountrySync()) { "Country must not be null" } val currency = requireNotNull(repository.getDefaultCurrencySync()) { "Currency must not be null" } - repository.fetchPairs(currency = currency, country = country, cryptoCurrency = cryptoCurrency) + repository.fetchPairs( + userWallet = userWallet, + currency = currency, + country = country, + cryptoCurrency = cryptoCurrency, + ) }.mapLeft(errorResolver::resolve) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchQuotesUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchQuotesUseCase.kt index 1842f2a819..7135dbddb0 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchQuotesUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchQuotesUseCase.kt @@ -5,14 +5,16 @@ import com.tangem.domain.onramp.repositories.OnrampErrorResolver import com.tangem.domain.onramp.repositories.OnrampRepository import com.tangem.domain.tokens.model.Amount import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWallet class OnrampFetchQuotesUseCase( private val repository: OnrampRepository, private val errorResolver: OnrampErrorResolver, ) { - suspend operator fun invoke(amount: Amount, cryptoCurrency: CryptoCurrency) = Either.catch { + suspend operator fun invoke(userWallet: UserWallet, amount: Amount, cryptoCurrency: CryptoCurrency) = Either.catch { repository.fetchQuotes( + userWallet = userWallet, cryptoCurrency = cryptoCurrency, amount = amount, ) diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/repositories/OnrampRepository.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/repositories/OnrampRepository.kt index 302a563b12..4e1dc066ae 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/repositories/OnrampRepository.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/repositories/OnrampRepository.kt @@ -4,7 +4,7 @@ import com.tangem.domain.onramp.model.* import com.tangem.domain.onramp.model.cache.OnrampTransaction import com.tangem.domain.tokens.model.Amount import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.domain.wallets.models.UserWallet import kotlinx.coroutines.flow.Flow @Suppress("TooManyFunctions") @@ -13,15 +13,21 @@ interface OnrampRepository { fun getCurrencies(): Flow> fun getCountries(): Flow> suspend fun getCountriesSync(): List? - suspend fun getCountryByIp(): OnrampCountry - suspend fun getStatus(txId: String): OnrampStatus - suspend fun fetchCurrencies() - suspend fun fetchCountries(): List - suspend fun fetchPaymentMethodsIfAbsent() - suspend fun fetchPairs(currency: OnrampCurrency, country: OnrampCountry, cryptoCurrency: CryptoCurrency) - suspend fun fetchQuotes(cryptoCurrency: CryptoCurrency, amount: Amount) + suspend fun getCountryByIp(userWallet: UserWallet): OnrampCountry + suspend fun getStatus(userWallet: UserWallet, txId: String): OnrampStatus + suspend fun fetchCurrencies(userWallet: UserWallet) + suspend fun fetchCountries(userWallet: UserWallet): List + suspend fun fetchPaymentMethodsIfAbsent(userWallet: UserWallet) + suspend fun fetchPairs( + userWallet: UserWallet, + currency: OnrampCurrency, + country: OnrampCountry, + cryptoCurrency: CryptoCurrency, + ) + + suspend fun fetchQuotes(userWallet: UserWallet, cryptoCurrency: CryptoCurrency, amount: Amount) suspend fun getOnrampData( - userWalletId: UserWalletId, + userWallet: UserWallet, cryptoCurrency: CryptoCurrency, quote: OnrampProviderWithQuote.Data, isDarkTheme: Boolean, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/ConfirmResidencyComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/ConfirmResidencyComponent.kt index 7dda243f37..f948424bfa 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/ConfirmResidencyComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/ConfirmResidencyComponent.kt @@ -4,10 +4,12 @@ import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableBottomSheetComponent import com.tangem.domain.onramp.model.OnrampCountry import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWalletId internal interface ConfirmResidencyComponent : ComposableBottomSheetComponent { data class Params( + val userWalletId: UserWalletId, val cryptoCurrency: CryptoCurrency, val country: OnrampCountry, val onDismiss: () -> Unit, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt index 2ff2e6a708..053fa306c7 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/DefaultConfirmResidencyComponent.kt @@ -69,6 +69,7 @@ internal class DefaultConfirmResidencyComponent @AssistedInject constructor( is ConfirmResidencyBottomSheetConfig.SelectCountry -> selectCountryComponentFactory.create( context = childByContext(componentContext), params = SelectCountryComponent.Params( + userWalletId = params.userWalletId, cryptoCurrency = params.cryptoCurrency, onDismiss = { isCountrySelected -> // Dismiss country select sheet diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt index f6c03525c1..0f959bb2c2 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/DefaultOnrampMainComponent.kt @@ -54,6 +54,7 @@ internal class DefaultOnrampMainComponent @AssistedInject constructor( is OnrampMainBottomSheetConfig.ConfirmResidency -> confirmResidencyComponentFactory.create( context = childByContext(componentContext), params = ConfirmResidencyComponent.Params( + userWalletId = params.userWalletId, cryptoCurrency = params.cryptoCurrency, country = config.country, onDismiss = { @@ -65,6 +66,7 @@ internal class DefaultOnrampMainComponent @AssistedInject constructor( is OnrampMainBottomSheetConfig.CurrenciesList -> selectCurrencyComponentFactory.create( context = childByContext(componentContext), params = SelectCurrencyComponent.Params( + userWallet = model.userWallet, cryptoCurrency = params.cryptoCurrency, onDismiss = model.bottomSheetNavigation::dismiss, ), diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt index a3afe0f26f..09feb75a0d 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt @@ -57,6 +57,9 @@ internal class OnrampMainComponentModel @Inject constructor( ) : Model(), OnrampIntents { private val params: OnrampMainComponent.Params = paramsContainer.require() + + val userWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId } + private val stateFactory = OnrampStateFactory( currentStateProvider = Provider { _state.value }, cryptoCurrency = params.cryptoCurrency, @@ -68,7 +71,6 @@ internal class OnrampMainComponentModel @Inject constructor( onrampIntents = this, cryptoCurrency = params.cryptoCurrency, ) - private val selectedUserWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId } private val _state: MutableStateFlow = MutableStateFlow( value = stateFactory.getInitialState( currency = params.cryptoCurrency.name, @@ -107,7 +109,7 @@ internal class OnrampMainComponentModel @Inject constructor( private fun checkResidenceCountry() { modelScope.launch { - checkOnrampAvailabilityUseCase() + checkOnrampAvailabilityUseCase(userWallet) .onRight(::handleOnrampAvailability) .onLeft(::handleOnrampError) } @@ -158,7 +160,7 @@ internal class OnrampMainComponentModel @Inject constructor( if (!state?.amountBlockState?.amountFieldModel?.fiatValue.isNullOrEmpty()) { _state.update { amountStateFactory.getAmountSecondaryLoadingState() } } - fetchPairsUseCase.invoke(params.cryptoCurrency).fold( + fetchPairsUseCase.invoke(userWallet, params.cryptoCurrency).fold( ifLeft = ::handleOnrampError, ifRight = { _state.update { amountStateFactory.getAmountSecondaryResetState() } }, ) @@ -184,6 +186,7 @@ internal class OnrampMainComponentModel @Inject constructor( val content = state.value as? OnrampMainComponentUM.Content ?: return@runCatching if (content.amountBlockState.amountFieldModel.fiatAmount.value.isNullOrZero()) return@runCatching fetchQuotesUseCase.invoke( + userWallet = userWallet, amount = content.amountBlockState.amountFieldModel.fiatAmount, cryptoCurrency = params.cryptoCurrency, ).onLeft(::handleOnrampError) @@ -216,7 +219,7 @@ internal class OnrampMainComponentModel @Inject constructor( } override fun onBuyClick(quote: OnrampProviderWithQuote.Data) { - if (isDemoCardUseCase.invoke(selectedUserWallet.cardId)) { + if (isDemoCardUseCase.invoke(userWallet.cardId)) { showDemoWarning() } else { val currentContentState = state.value as? OnrampMainComponentUM.Content ?: return diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt index cc6426d771..7d8207b969 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt @@ -14,6 +14,7 @@ import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.message.DialogMessage import com.tangem.domain.onramp.GetOnrampRedirectUrlUseCase import com.tangem.domain.onramp.model.error.OnrampError +import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.features.onramp.impl.R import com.tangem.features.onramp.redirect.OnrampRedirectComponent import com.tangem.features.onramp.redirect.entity.OnrampRedirectTopBarUM @@ -29,6 +30,7 @@ internal class OnrampRedirectModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val urlOpener: UrlOpener, private val getOnrampRedirectUrlUseCase: GetOnrampRedirectUrlUseCase, + private val getWalletsUseCase: GetWalletsUseCase, private val messageSender: UiMessageSender, private val analyticsEventHandler: AnalyticsEventHandler, router: Router, @@ -36,6 +38,8 @@ internal class OnrampRedirectModel @Inject constructor( ) : Model() { private val params: OnrampRedirectComponent.Params = paramsContainer.require() + private val selectedUserWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId } + val state = OnrampRedirectUM( topBarConfig = OnrampRedirectTopBarUM( title = combinedReference( @@ -62,7 +66,7 @@ internal class OnrampRedirectModel @Inject constructor( fun getRedirectUrl(isDarkTheme: Boolean) { modelScope.launch { getOnrampRedirectUrlUseCase.invoke( - userWalletId = params.userWalletId, + userWallet = selectedUserWallet, quote = params.onrampProviderWithQuote, cryptoCurrency = params.cryptoCurrency, isDarkTheme = isDarkTheme, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt index 48804d46be..e08b4a4477 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt @@ -61,8 +61,9 @@ internal class DefaultOnrampComponent @AssistedInject constructor( OnrampChild.Settings -> settingsComponentFactory.create( context = childByContext(componentContext), params = OnrampSettingsComponent.Params( - params.cryptoCurrency, - navigation::pop, + userWalletId = params.userWalletId, + cryptoCurrency = params.cryptoCurrency, + onBack = navigation::pop, ), ) OnrampChild.Main -> onrampMainComponentFactory.create( diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/SelectCountryComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/SelectCountryComponent.kt index 8abf849546..869dc95993 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/SelectCountryComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/SelectCountryComponent.kt @@ -3,10 +3,15 @@ package com.tangem.features.onramp.selectcountry import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableBottomSheetComponent import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWalletId internal interface SelectCountryComponent : ComposableBottomSheetComponent { - data class Params(val cryptoCurrency: CryptoCurrency, val onDismiss: (Boolean) -> Unit) + data class Params( + val userWalletId: UserWalletId, + val cryptoCurrency: CryptoCurrency, + val onDismiss: (Boolean) -> Unit, + ) interface Factory : ComponentFactory } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt index 8d0835efff..a30217c087 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt @@ -13,6 +13,7 @@ import com.tangem.domain.onramp.GetOnrampCountryUseCase import com.tangem.domain.onramp.OnrampSaveDefaultCountryUseCase import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent import com.tangem.domain.onramp.model.OnrampCountry +import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.features.onramp.impl.R import com.tangem.features.onramp.selectcountry.SelectCountryComponent import com.tangem.features.onramp.selectcountry.entity.CountryItemState @@ -44,11 +45,15 @@ internal class OnrampSelectCountryModel @Inject constructor( private val saveDefaultCountryUseCase: OnrampSaveDefaultCountryUseCase, private val getOnrampCountryUseCase: GetOnrampCountryUseCase, private val fetchOnrampCountriesUseCase: FetchOnrampCountriesUseCase, + getWalletsUseCase: GetWalletsUseCase, paramsContainer: ParamsContainer, ) : Model() { - val state: StateFlow get() = controller.state private val params: SelectCountryComponent.Params = paramsContainer.require() + private val userWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId } + + val state: StateFlow get() = controller.state + private val controller = CountryListUMController( searchBarUM = createSearchBarUM(), loadingItems = loadingItems, @@ -103,7 +108,7 @@ internal class OnrampSelectCountryModel @Inject constructor( private fun updateCountriesList() { modelScope.launch { - fetchOnrampCountriesUseCase().onLeft { + fetchOnrampCountriesUseCase(userWallet).onLeft { controller.update(UpdateCountryItemsErrorTransformer(onRetry = ::onRetry)) } } diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/SelectCurrencyComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/SelectCurrencyComponent.kt index f8283864dd..e06fdec8ac 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/SelectCurrencyComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/SelectCurrencyComponent.kt @@ -3,10 +3,15 @@ package com.tangem.features.onramp.selectcurrency import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableBottomSheetComponent import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWallet internal interface SelectCurrencyComponent : ComposableBottomSheetComponent { - data class Params(val cryptoCurrency: CryptoCurrency, val onDismiss: () -> Unit) + data class Params( + val userWallet: UserWallet, + val cryptoCurrency: CryptoCurrency, + val onDismiss: () -> Unit, + ) interface Factory : ComponentFactory } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt index 1162910ed0..c7899de0de 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt @@ -97,7 +97,7 @@ internal class OnrampSelectCurrencyModel @Inject constructor( private fun updateCurrenciesList() { modelScope.launch { - fetchOnrampCurrenciesUseCase().onLeft { + fetchOnrampCurrenciesUseCase(userWallet = params.userWallet).onLeft { controller.update(UpdateCurrencyItemsErrorTransformer(onRetry = ::onRetry)) } } diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt index 941d543d82..2d61aa6571 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt @@ -52,7 +52,8 @@ internal class DefaultOnrampSettingsComponent @AssistedInject constructor( OnrampSettingsConfig.SelectCountry -> selectCountryComponentFactory.create( context = childByContext(componentContext), params = SelectCountryComponent.Params( - params.cryptoCurrency, + userWalletId = params.userWalletId, + cryptoCurrency = params.cryptoCurrency, onDismiss = { model.bottomSheetNavigation.dismiss() }, ), ) diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/OnrampSettingsComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/OnrampSettingsComponent.kt index 4b3b8d1455..c6fca3fb80 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/OnrampSettingsComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/OnrampSettingsComponent.kt @@ -3,10 +3,15 @@ package com.tangem.features.onramp.settings import com.tangem.core.decompose.factory.ComponentFactory import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWalletId internal interface OnrampSettingsComponent : ComposableContentComponent { - data class Params(val cryptoCurrency: CryptoCurrency, val onBack: () -> Unit) + data class Params( + val userWalletId: UserWalletId, + val cryptoCurrency: CryptoCurrency, + val onBack: () -> Unit, + ) interface Factory : ComponentFactory } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/model/OnrampSuccessComponentModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/model/OnrampSuccessComponentModel.kt index 4803e7f98e..fa74f49da7 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/model/OnrampSuccessComponentModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/model/OnrampSuccessComponentModel.kt @@ -97,7 +97,7 @@ internal class OnrampSuccessComponentModel @Inject constructor( return } - getOnrampStatusUseCase(txId = transaction.txId) + getOnrampStatusUseCase(userWallet = userWallet, txId = transaction.txId) .fold( ifLeft = { error -> analyticsEventHandler.sendOnrampErrorEvent( diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/model/AvailableSwapPairsModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/model/AvailableSwapPairsModel.kt index 09f41bc29d..ca5940bfa9 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/model/AvailableSwapPairsModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/swap/availablepairs/model/AvailableSwapPairsModel.kt @@ -19,6 +19,7 @@ import com.tangem.domain.tokens.GetTokenListUseCase import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.TokenList +import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.feature.swap.domain.GetAvailablePairsUseCase import com.tangem.feature.swap.domain.models.domain.LeastTokenInfo import com.tangem.feature.swap.domain.models.domain.SwapPairLeast @@ -52,11 +53,13 @@ internal class AvailableSwapPairsModel @Inject constructor( private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase, private val getAvailablePairsUseCase: GetAvailablePairsUseCase, + private val getWalletsUseCase: GetWalletsUseCase, ) : Model() { val state: StateFlow = tokenListUMController.state private var params: AvailableSwapPairsComponent.Params = paramsContainer.require() + private val userWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId } private val tokenListFlow = getTokenListUseCaseFlow() @@ -212,6 +215,7 @@ internal class AvailableSwapPairsModel @Inject constructor( availablePairsByNetworkFlow.update(networkInfo = networkInfo, state = lceLoading()) getAvailablePairsUseCase( + userWallet = userWallet, initialCurrency = networkInfo, currencies = statuses.map(CryptoCurrencyStatus::currency), ) diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt index f872cd9c2c..ac037efc96 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt @@ -21,9 +21,12 @@ import com.tangem.datasource.api.express.models.response.SwapPair import com.tangem.datasource.api.express.models.response.SwapPairsWithProviders import com.tangem.datasource.api.express.models.response.TxDetails import com.tangem.datasource.crypto.DataSignatureVerifier +import com.tangem.datasource.exchangeservice.swap.ExpressUtils +import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.legacy.UserWalletsListManager +import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.swap.converters.* import com.tangem.feature.swap.domain.api.SwapRepository @@ -48,6 +51,7 @@ internal class DefaultSwapRepository( private val userWalletsListManager: UserWalletsListManager, private val errorsDataConverter: ErrorsDataConverter, private val dataSignatureVerifier: DataSignatureVerifier, + private val appPreferencesStore: AppPreferencesStore, moshi: Moshi, excludedBlockchains: ExcludedBlockchains, ) : SwapRepository { @@ -60,6 +64,7 @@ internal class DefaultSwapRepository( private val txDetailsMoshiAdapter = moshi.adapter(TxDetails::class.java) override suspend fun getPairs( + userWallet: UserWallet, initialCurrency: LeastTokenInfo, currencyList: List, ): PairsWithProviders { @@ -73,6 +78,7 @@ internal class DefaultSwapRepository( val pairsDeferred = async { getPairsInternal( + userWallet = userWallet, from = arrayListOf(initial), to = currenciesList, ) @@ -80,6 +86,7 @@ internal class DefaultSwapRepository( val reversedPairsDeferred = async { getPairsInternal( + userWallet = userWallet, from = currenciesList, to = arrayListOf(initial), ) @@ -90,7 +97,13 @@ internal class DefaultSwapRepository( val allPairs = pairs + reversedPairs - val providers = tangemExpressApi.getProviders().getOrThrow() + val providers = tangemExpressApi.getProviders( + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), + ).getOrThrow() return@withContext swapPairInfoConverter.convert( SwapPairsWithProviders( @@ -109,6 +122,7 @@ internal class DefaultSwapRepository( } override suspend fun getPairsOnly( + userWallet: UserWallet, initialCurrency: LeastTokenInfo, currencyList: List, ): PairsWithProviders { @@ -122,6 +136,7 @@ internal class DefaultSwapRepository( val pairsDeferred = async { getPairsInternal( + userWallet = userWallet, from = arrayListOf(initial), to = currenciesList, ) @@ -129,6 +144,7 @@ internal class DefaultSwapRepository( val reversedPairsDeferred = async { getPairsInternal( + userWallet = userWallet, from = currenciesList, to = arrayListOf(initial), ) @@ -156,25 +172,42 @@ internal class DefaultSwapRepository( } private suspend fun getPairsInternal( + userWallet: UserWallet, from: List, to: List, ): ApiResponse> { return tangemExpressApi.getPairs( - PairsRequestBody( + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), + body = PairsRequestBody( from = from, to = to, ), ) } - override suspend fun getExchangeStatus(txId: String): Either { + override suspend fun getExchangeStatus( + userWallet: UserWallet, + txId: String, + ): Either { return withContext(coroutineDispatcher.io) { either { catch( block = { exchangeStatusConverter.convert( tangemExpressApi - .getExchangeStatus(txId) + .getExchangeStatus( + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), + txId = txId, + ) .getOrThrow(), ) }, @@ -188,7 +221,7 @@ internal class DefaultSwapRepository( } override suspend fun findBestQuote( - userWalletId: UserWalletId, + userWallet: UserWallet, fromContractAddress: String, fromNetwork: String, toContractAddress: String, @@ -211,6 +244,11 @@ internal class DefaultSwapRepository( toDecimals = toDecimals, providerId = providerId, rateType = rateType.name.lowercase(), + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), ).getOrThrow() QuoteModel( toTokenAmount = createFromAmountWithOffset(response.toAmount, response.toDecimals), @@ -223,6 +261,7 @@ internal class DefaultSwapRepository( } override suspend fun getExchangeData( + userWallet: UserWallet, fromContractAddress: String, fromNetwork: String, toContractAddress: String, @@ -255,6 +294,11 @@ internal class DefaultSwapRepository( requestId = requestId, refundAddress = refundAddress, refundExtraId = refundExtraId, + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), ).getOrThrow() if (dataSignatureVerifier.verifySignature(response.signature, response.txDetailsJson)) { val txDetails = parseTxDetails(response.txDetailsJson) @@ -281,6 +325,7 @@ internal class DefaultSwapRepository( } override suspend fun exchangeSent( + userWallet: UserWallet, txId: String, fromNetwork: String, fromAddress: String, @@ -290,7 +335,12 @@ internal class DefaultSwapRepository( ): Either = withContext(coroutineDispatcher.io) { try { tangemExpressApi.exchangeSent( - ExchangeSentRequestBody( + userWalletId = userWallet.walletId.stringValue, + refCode = ExpressUtils.getRefCode( + userWallet = userWallet, + appPreferencesStore = appPreferencesStore, + ), + body = ExchangeSentRequestBody( txId = txId, fromNetwork = fromNetwork, fromAddress = fromAddress, diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt index 082f1b8ec9..87e009b03a 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt @@ -7,8 +7,8 @@ import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.utils.getObjectList import com.tangem.datasource.local.preferences.utils.getObjectListSync import com.tangem.datasource.local.preferences.utils.getObjectMapSync -import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.swap.converters.SavedSwapTransactionListConverter import com.tangem.feature.swap.domain.SwapTransactionRepository @@ -80,9 +80,8 @@ internal class DefaultSwapTransactionRepository( } override suspend fun getTransactions( - userWalletId: UserWalletId, + userWallet: UserWallet, cryptoCurrencyId: CryptoCurrency.ID, - scanResponse: ScanResponse, ): Flow?> { return withContext(dispatchers.io) { val txStatuses = appPreferencesStore.getObjectMapSync( @@ -93,7 +92,7 @@ internal class DefaultSwapTransactionRepository( ).map { savedTransactions -> val currencyTxs = savedTransactions ?.filter { - it.userWalletId == userWalletId.stringValue && + it.userWalletId == userWallet.walletId.stringValue && ( it.toCryptoCurrencyId == cryptoCurrencyId.value || it.fromCryptoCurrencyId == cryptoCurrencyId.value @@ -103,7 +102,7 @@ internal class DefaultSwapTransactionRepository( currencyTxs?.mapNotNull { converter.convertBack( value = it, - scanResponse = scanResponse, + scanResponse = userWallet.scanResponse, txStatuses = txStatuses, ) } diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/di/SwapDataModule.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/di/SwapDataModule.kt index 5a1b3dcf85..eb0e016c58 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/di/SwapDataModule.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/di/SwapDataModule.kt @@ -36,6 +36,7 @@ internal class SwapDataModule { errorsDataConverter: ErrorsDataConverter, @NetworkMoshi moshi: Moshi, excludedBlockchains: ExcludedBlockchains, + appPreferencesStore: AppPreferencesStore, ): SwapRepository { return DefaultSwapRepository( tangemExpressApi = tangemExpressApi, @@ -46,6 +47,7 @@ internal class SwapDataModule { dataSignatureVerifier = dataSignature, moshi = moshi, excludedBlockchains = excludedBlockchains, + appPreferencesStore = appPreferencesStore, ) } 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 bacf1b8df5..69b15ea0b7 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 @@ -2,6 +2,7 @@ package com.tangem.feature.swap.domain.api import arrow.core.Either import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.swap.domain.models.ExpressDataError import com.tangem.feature.swap.domain.models.domain.* @@ -9,16 +10,24 @@ import java.math.BigDecimal interface SwapRepository { - suspend fun getPairs(initialCurrency: LeastTokenInfo, currencyList: List): PairsWithProviders + suspend fun getPairs( + userWallet: UserWallet, + initialCurrency: LeastTokenInfo, + currencyList: List, + ): PairsWithProviders /** Express getPairs request variant without providers request */ - suspend fun getPairsOnly(initialCurrency: LeastTokenInfo, currencyList: List): PairsWithProviders + suspend fun getPairsOnly( + userWallet: UserWallet, + initialCurrency: LeastTokenInfo, + currencyList: List, + ): PairsWithProviders - suspend fun getExchangeStatus(txId: String): Either + suspend fun getExchangeStatus(userWallet: UserWallet, txId: String): Either @Suppress("LongParameterList") suspend fun findBestQuote( - userWalletId: UserWalletId, + userWallet: UserWallet, fromContractAddress: String, fromNetwork: String, toContractAddress: String, @@ -43,6 +52,7 @@ interface SwapRepository { @Suppress("LongParameterList") suspend fun getExchangeData( + userWallet: UserWallet, fromContractAddress: String, fromNetwork: String, toContractAddress: String, @@ -61,6 +71,7 @@ interface SwapRepository { // TODO: Add target error handling, remove either ([REDACTED_JIRA]) @Suppress("LongParameterList") suspend fun exchangeSent( + userWallet: UserWallet, txId: String, fromNetwork: String, fromAddress: String, diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/GetAvailablePairsUseCase.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/GetAvailablePairsUseCase.kt index 113c0ca915..28d0e06898 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/GetAvailablePairsUseCase.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/GetAvailablePairsUseCase.kt @@ -1,6 +1,7 @@ package com.tangem.feature.swap.domain import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.feature.swap.domain.models.domain.LeastTokenInfo import com.tangem.feature.swap.domain.models.domain.SwapPairLeast @@ -10,9 +11,14 @@ class GetAvailablePairsUseCase( ) { suspend operator fun invoke( + userWallet: UserWallet, initialCurrency: LeastTokenInfo, currencies: List, ): List { - return swapRepository.getPairsOnly(initialCurrency, currencies).pairs + return swapRepository.getPairsOnly( + userWallet = userWallet, + initialCurrency = initialCurrency, + currencyList = currencies, + ).pairs } } \ 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 d5b93c4276..34954d7dc3 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 @@ -114,6 +114,7 @@ internal class SwapInteractorImpl @AssistedInject constructor( } val pairsLeast = getPairs( + userWallet = userWallet, initialCurrency = LeastTokenInfo( contractAddress = (currency as? CryptoCurrency.Token)?.contractAddress ?: "0", network = currency.network.backendId, @@ -197,10 +198,15 @@ internal class SwapInteractorImpl @AssistedInject constructor( } private suspend fun getPairs( + userWallet: UserWallet, initialCurrency: LeastTokenInfo, currenciesList: List, ): PairsWithProviders { - return repository.getPairs(initialCurrency, currenciesList) + return repository.getPairs( + userWallet = userWallet, + initialCurrency = initialCurrency, + currencyList = currenciesList, + ) } override suspend fun givePermissionToSwap( @@ -308,7 +314,7 @@ internal class SwapInteractorImpl @AssistedInject constructor( isBalanceWithoutFeeEnough: Boolean, ): Pair { val maybeQuotes = repository.findBestQuote( - userWalletId = userWalletId, + userWallet = userWallet, fromContractAddress = fromToken.currency.getContractAddress(), fromNetwork = fromToken.currency.network.backendId, toContractAddress = toToken.currency.getContractAddress(), @@ -619,6 +625,7 @@ internal class SwapInteractorImpl @AssistedInject constructor( return result.fold( ifRight = { txHash -> repository.exchangeSent( + userWallet = userWallet, txId = swapData.transaction.txId, fromNetwork = currencyToSendStatus.currency.network.backendId, fromAddress = currencyToSendStatus.value.networkAddress?.defaultAddress?.value.orEmpty(), @@ -674,6 +681,7 @@ internal class SwapInteractorImpl @AssistedInject constructor( swapProvider: SwapProvider, ): SwapTransactionState { val exchangeData = repository.getExchangeData( + userWallet = userWallet, fromContractAddress = currencyToSend.currency.getContractAddress(), fromNetwork = currencyToSend.currency.network.backendId, toContractAddress = currencyToGet.currency.getContractAddress(), @@ -726,6 +734,7 @@ internal class SwapInteractorImpl @AssistedInject constructor( ifLeft = { SwapTransactionState.Error.TransactionError(it) }, ifRight = { txHash -> repository.exchangeSent( + userWallet = userWallet, txId = exchangeDataCex.txId, fromNetwork = currencyToSend.currency.network.backendId, fromAddress = currencyToSend.value.networkAddress?.defaultAddress?.value.orEmpty(), @@ -1132,7 +1141,7 @@ internal class SwapInteractorImpl @AssistedInject constructor( } val quotes = repository.findBestQuote( - userWalletId = userWalletId, + userWallet = userWallet, fromContractAddress = fromToken.getContractAddress(), fromNetwork = fromToken.network.backendId, toContractAddress = toToken.getContractAddress(), @@ -1388,6 +1397,7 @@ internal class SwapInteractorImpl @AssistedInject constructor( selectedFee: FeeType, ): SwapState { return repository.getExchangeData( + userWallet = userWallet, fromContractAddress = fromToken.currency.getContractAddress(), fromNetwork = fromToken.currency.network.backendId, toContractAddress = toToken.currency.getContractAddress(), diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt index 812499d47f..d0d49d2adf 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt @@ -1,7 +1,7 @@ package com.tangem.feature.swap.domain -import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.swap.domain.models.domain.ExchangeStatusModel import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModel @@ -18,9 +18,8 @@ interface SwapTransactionRepository { ) suspend fun getTransactions( - userWalletId: UserWalletId, + userWallet: UserWallet, cryptoCurrencyId: CryptoCurrency.ID, - scanResponse: ScanResponse, ): Flow?> suspend fun removeTransaction( diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt index d70de8f364..86c1687693 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt @@ -6,6 +6,8 @@ import arrow.core.getOrElse import com.tangem.blockchain.common.address.AddressType import com.tangem.common.routing.AppRoute import com.tangem.common.routing.AppRouter +import com.tangem.common.ui.bottomsheet.receive.AddressModel +import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM import com.tangem.core.analytics.api.AnalyticsEventHandler @@ -17,8 +19,6 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.navigation.share.ShareManager import com.tangem.core.ui.clipboard.ClipboardManager -import com.tangem.common.ui.bottomsheet.receive.AddressModel -import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference @@ -166,7 +166,7 @@ internal class TokenDetailsModel @Inject constructor( appCurrencyProvider = Provider { selectedAppCurrencyFlow.value }, currentStateProvider = Provider { uiState.value }, cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus }, - userWalletId = userWalletId, + userWallet = userWallet, cryptoCurrency = cryptoCurrency, ) } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt index 6890405a1d..1fbea94122 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt @@ -12,8 +12,7 @@ import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.Quote import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent import com.tangem.domain.tokens.repository.QuotesRepository -import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase +import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.swap.domain.SwapTransactionRepository import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.feature.swap.domain.models.domain.* @@ -29,7 +28,6 @@ import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.conflate -import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.map @Suppress("LongParameterList") @@ -39,14 +37,13 @@ internal class ExchangeStatusFactory @AssistedInject constructor( private val quotesRepository: QuotesRepository, private val quotesRepositoryV2: QuotesRepositoryV2, private val tokensFeatureToggles: TokensFeatureToggles, - private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase, private val swapTransactionStatusStore: SwapTransactionStatusStore, private val analyticsEventsHandler: AnalyticsEventHandler, @Assisted private val clickIntents: TokenDetailsClickIntents, @Assisted private val appCurrencyProvider: Provider, @Assisted private val currentStateProvider: Provider, - @Assisted private val userWalletId: UserWalletId, + @Assisted private val userWallet: UserWallet, @Assisted private val cryptoCurrency: CryptoCurrency, ) { @@ -60,14 +57,9 @@ internal class ExchangeStatusFactory @AssistedInject constructor( } suspend operator fun invoke(): Flow> { - val selectedWallet = getSelectedWalletSyncUseCase().fold( - ifLeft = { return emptyFlow() }, - ifRight = { it }, - ) return swapTransactionRepository.getTransactions( - userWalletId = userWalletId, + userWallet = userWallet, cryptoCurrencyId = cryptoCurrency.id, - scanResponse = selectedWallet.scanResponse, ).conflate() .map { savedTransactions -> val quotes = savedTransactions @@ -91,7 +83,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor( val shouldDispose = selectedTx.activeStatus?.isAutoDisposable == true || isForceDispose if (shouldDispose) { swapTransactionRepository.removeTransaction( - userWalletId = userWalletId, + userWalletId = userWallet.walletId, fromCryptoCurrency = selectedTx.fromCryptoCurrency, toCryptoCurrency = selectedTx.toCryptoCurrency, txId = selectedTx.info.txId, @@ -117,7 +109,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor( } private suspend fun getExchangeStatus(txId: String, provider: SwapProvider): ExchangeStatusModel? { - return swapRepository.getExchangeStatus(txId) + return swapRepository.getExchangeStatus(userWallet = userWallet, txId = txId) .fold( ifLeft = { null }, ifRight = { statusModel -> @@ -157,7 +149,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor( val refundContractAddress = status.refundContractAddress if (refundNetwork != null && refundContractAddress != null) { return addCryptoCurrenciesUseCase( - userWalletId = userWalletId, + userWalletId = userWallet.walletId, contractAddress = refundContractAddress, networkId = refundNetwork, ).getOrNull() @@ -219,7 +211,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor( clickIntents: TokenDetailsClickIntents, appCurrencyProvider: Provider, currentStateProvider: Provider, - userWalletId: UserWalletId, + userWallet: UserWallet, cryptoCurrency: CryptoCurrency, ): ExchangeStatusFactory } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt index 77c9dc1404..7d8902e653 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExpressStatusFactory.kt @@ -10,12 +10,12 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent -import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.swap.domain.models.domain.ExchangeStatus +import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotification import com.tangem.feature.tokendetails.presentation.tokendetails.state.express.ExchangeUM -import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents import com.tangem.utils.Provider import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.assisted.Assisted @@ -36,7 +36,7 @@ internal class ExpressStatusFactory @AssistedInject constructor( @Assisted private val clickIntents: TokenDetailsClickIntents, @Assisted private val cryptoCurrency: CryptoCurrency, @Assisted appCurrencyProvider: Provider, - @Assisted userWalletId: UserWalletId, + @Assisted userWallet: UserWallet, @Assisted cryptoCurrencyStatusProvider: Provider, private val dispatchers: CoroutineDispatcherProvider, private val analyticsEventsHandler: AnalyticsEventHandler, @@ -49,7 +49,7 @@ internal class ExpressStatusFactory @AssistedInject constructor( clickIntents = clickIntents, appCurrencyProvider = appCurrencyProvider, currentStateProvider = currentStateProvider, - userWalletId = userWalletId, + userWallet = userWallet, cryptoCurrency = cryptoCurrency, ) } @@ -61,7 +61,7 @@ internal class ExpressStatusFactory @AssistedInject constructor( appCurrencyProvider = appCurrencyProvider, clickIntents = clickIntents, cryptoCurrency = cryptoCurrency, - userWalletId = userWalletId, + userWallet = userWallet, ) } @@ -210,7 +210,7 @@ internal class ExpressStatusFactory @AssistedInject constructor( clickIntents: TokenDetailsClickIntents, appCurrencyProvider: Provider, currentStateProvider: Provider, - userWalletId: UserWalletId, + userWallet: UserWallet, cryptoCurrency: CryptoCurrency, cryptoCurrencyStatusProvider: Provider, ): ExpressStatusFactory diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/OnrampStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/OnrampStatusFactory.kt index bcf2f0b1b2..b790b61b5d 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/OnrampStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/OnrampStatusFactory.kt @@ -14,8 +14,8 @@ import com.tangem.domain.onramp.model.OnrampStatus.Status.* import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent -import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents +import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.TokenDetailsOnrampTransactionStateConverter import com.tangem.utils.Provider @@ -39,7 +39,7 @@ internal class OnrampStatusFactory @AssistedInject constructor( @Assisted private val appCurrencyProvider: Provider, @Assisted private val clickIntents: TokenDetailsClickIntents, @Assisted private val cryptoCurrency: CryptoCurrency, - @Assisted private val userWalletId: UserWalletId, + @Assisted private val userWallet: UserWallet, ) { private val onrampTransactionStateConverter by lazy(LazyThreadSafetyMode.NONE) { @@ -54,7 +54,7 @@ internal class OnrampStatusFactory @AssistedInject constructor( operator fun invoke(): Flow> { return getOnrampTransactionsUseCase( - userWalletId = userWalletId, + userWalletId = userWallet.walletId, cryptoCurrencyId = cryptoCurrency.id, ).map { maybeTransaction -> maybeTransaction.fold( @@ -82,7 +82,7 @@ internal class OnrampStatusFactory @AssistedInject constructor( return if (onrampTx.activeStatus.isTerminal) { onrampTx } else { - getOnrampStatusUseCase(onrampTx.info.txId).fold( + getOnrampStatusUseCase(userWallet = userWallet, onrampTx.info.txId).fold( ifLeft = { Timber.e("Couldn't update onramp status. $it") onrampTx @@ -150,7 +150,7 @@ internal class OnrampStatusFactory @AssistedInject constructor( appCurrencyProvider: Provider, clickIntents: TokenDetailsClickIntents, cryptoCurrency: CryptoCurrency, - userWalletId: UserWalletId, + userWallet: UserWallet, ): OnrampStatusFactory } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt index 5359f89098..270806b3a2 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt @@ -15,6 +15,7 @@ import com.tangem.domain.nft.FetchNFTCollectionsUseCase import com.tangem.domain.settings.* import com.tangem.domain.tokens.FetchCurrencyStatusUseCase import com.tangem.domain.tokens.RefreshMultiCurrencyWalletQuotesUseCase +import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.repository.WalletsRepository import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase @@ -107,9 +108,7 @@ internal class WalletModel @Inject constructor( subscribeToUserWalletsUpdates() subscribeOnBalanceHiding() subscribeOnSelectedWalletFlow() - subscribeToScreenBackgroundState() subscribeOnPushNotificationsPermission() - subscribeOnExpressTransactionsUpdates() subscribeOnNFTUpdates() clickIntents.initialize(innerWalletRouter, modelScope) @@ -223,6 +222,8 @@ internal class WalletModel @Inject constructor( } walletDeepLinksHandler.registerForWallet(scope = modelScope, userWallet = selectedWallet) + subscribeOnExpressTransactionsUpdates(selectedWallet) + subscribeToScreenBackgroundState(selectedWallet) } .flowOn(dispatchers.main) .launchIn(modelScope) @@ -231,7 +232,7 @@ internal class WalletModel @Inject constructor( // We need to update the current wallet quotes if the application was in the background for more than 10 seconds // and then returned to the foreground - private fun subscribeToScreenBackgroundState() { + private fun subscribeToScreenBackgroundState(userWallet: UserWallet) { screenLifecycleProvider.isBackgroundState .onEach { isBackground -> expressTxStatusTaskScheduler.cancelTask() @@ -241,30 +242,31 @@ internal class WalletModel @Inject constructor( isBackground -> needToRefreshTimer() needToRefreshWallet && !isBackground -> { triggerRefreshWalletQuotes() - subscribeOnExpressTransactionsUpdates() + subscribeOnExpressTransactionsUpdates(userWallet) } - !isBackground -> subscribeOnExpressTransactionsUpdates() + !isBackground -> subscribeOnExpressTransactionsUpdates(userWallet) } } .launchIn(modelScope) + .saveIn(expressStatusJobHolder) } - private fun subscribeOnExpressTransactionsUpdates() { - modelScope.launch(dispatchers.main) { - expressTxStatusTaskScheduler.cancelTask() - expressTxStatusTaskScheduler.scheduleTask( - modelScope, - PeriodicTask( - isDelayFirst = false, - delay = EXPRESS_STATUS_UPDATE_DELAY, - task = { - runCatching { onrampStatusFactory.updateOnrmapTransactionStatuses() } - }, - onSuccess = { /* no-op */ }, - onError = { /* no-op */ }, - ), - ) - }.saveIn(expressStatusJobHolder) + private fun subscribeOnExpressTransactionsUpdates(userWallet: UserWallet) { + expressTxStatusTaskScheduler.cancelTask() + expressTxStatusTaskScheduler.scheduleTask( + modelScope, + PeriodicTask( + isDelayFirst = false, + delay = EXPRESS_STATUS_UPDATE_DELAY, + task = { + runCatching { + onrampStatusFactory.updateOnrmapTransactionStatuses(userWallet) + } + }, + onSuccess = { /* no-op */ }, + onError = { /* no-op */ }, + ), + ) } @OptIn(ExperimentalCoroutinesApi::class) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/OnrampStatusFactory.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/OnrampStatusFactory.kt index aeb4c7ad66..e60f42ad67 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/OnrampStatusFactory.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/domain/OnrampStatusFactory.kt @@ -11,6 +11,7 @@ import com.tangem.domain.onramp.OnrampUpdateTransactionStatusUseCase import com.tangem.domain.onramp.model.OnrampStatus import com.tangem.domain.onramp.model.OnrampStatus.Status.* import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent +import com.tangem.domain.wallets.models.UserWallet import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -40,22 +41,22 @@ internal class OnrampStatusFactory @Inject constructor( } } - suspend fun updateOnrmapTransactionStatuses() = withContext(dispatchers.io) { + suspend fun updateOnrmapTransactionStatuses(userWallet: UserWallet) = withContext(dispatchers.io) { val singleWalletState = stateHolder.getSelectedWallet() as? WalletState.SingleCurrency.Content ?: return@withContext singleWalletState.expressTxs.map { tx -> async { if (tx is ExpressTransactionStateUM.OnrampUM) { - updateOnrampTxStatus(tx) + updateOnrampTxStatus(userWallet, tx) } } }.awaitAll() } - private suspend fun updateOnrampTxStatus(onrampTx: ExpressTransactionStateUM.OnrampUM) { + private suspend fun updateOnrampTxStatus(userWallet: UserWallet, onrampTx: ExpressTransactionStateUM.OnrampUM) { if (!onrampTx.activeStatus.isTerminal) { - getOnrampStatusUseCase(onrampTx.info.txId).fold( + getOnrampStatusUseCase(userWallet = userWallet, onrampTx.info.txId).fold( ifLeft = { Timber.e("Couldn't update onramp status. $it") }, diff --git a/libs/auth/src/main/java/com/tangem/lib/auth/ExpressAuthProvider.kt b/libs/auth/src/main/java/com/tangem/lib/auth/ExpressAuthProvider.kt index ebca655e53..fa5fc99d83 100644 --- a/libs/auth/src/main/java/com/tangem/lib/auth/ExpressAuthProvider.kt +++ b/libs/auth/src/main/java/com/tangem/lib/auth/ExpressAuthProvider.kt @@ -1,10 +1,5 @@ package com.tangem.lib.auth interface ExpressAuthProvider { - - fun getUserId(): String - fun getSessionId(): String - - fun getRefCode(): String } \ No newline at end of file