From 0741b83490443d59f3f623d481a1f8a87a419da5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 19 Jan 2026 14:21:03 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../datasource/api/common/config/ApiConfig.kt | 4 +- .../datasource/api/common/config/TangemPay.kt | 71 ++++++++++++++++--- .../api/common/config/TangemPayAuth.kt | 53 -------------- .../tangem/datasource/api/pay/TangemPayApi.kt | 1 - .../tangem/datasource/di/ApiConfigsModule.kt | 12 ++-- .../config/environment/EnvironmentConfig.kt | 1 + .../converter/EnvironmentConfigConverter.kt | 1 + .../models/EnvironmentConfigModel.kt | 1 + .../api/common/config/ApiConfigTest.kt | 10 ++- .../managers/MockEnvironmentConfigStorage.kt | 4 ++ .../managers/ProdApiConfigsManagerTest.kt | 15 +++- .../repository/DefaultOnboardingRepository.kt | 9 +-- .../repository/TangemPayRequestPerformer.kt | 23 ++---- 13 files changed, 107 insertions(+), 98 deletions(-) delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPayAuth.kt diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/ApiConfig.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/ApiConfig.kt index 13b9af6b94..515a93b2f8 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/ApiConfig.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/ApiConfig.kt @@ -40,8 +40,8 @@ sealed class ApiConfig { is TangemTech -> ID.TangemTech is StakeKit -> ID.StakeKit is P2PEthPool -> ID.P2PEthPool - is TangemPay -> ID.TangemPay - is TangemPayAuth -> ID.TangemPayAuth + is TangemPay.Bff -> ID.TangemPay + is TangemPay.Auth -> ID.TangemPayAuth is BlockAid -> ID.BlockAid is YieldSupply -> ID.YieldSupply is MoonPay -> ID.MoonPay diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPay.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPay.kt index c0a5c07775..b494cbc70c 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPay.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPay.kt @@ -1,11 +1,13 @@ package com.tangem.datasource.api.common.config import com.tangem.datasource.BuildConfig +import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage import com.tangem.utils.ProviderSuspend import com.tangem.utils.version.AppVersionProvider -internal class TangemPay( +internal sealed class TangemPay( private val appVersionProvider: AppVersionProvider, + private val environmentConfigStorage: EnvironmentConfigStorage, ) : ApiConfig() { override val defaultEnvironment: ApiEnvironment = getInitialEnvironment() @@ -16,6 +18,8 @@ internal class TangemPay( createProdEnvironment(), ) + protected abstract fun getBaseUrl(apiEnvironment: ApiEnvironment): String + private fun getInitialEnvironment(): ApiEnvironment { return when (BuildConfig.BUILD_TYPE) { MOCKED_BUILD_TYPE -> ApiEnvironment.MOCK @@ -31,24 +35,75 @@ internal class TangemPay( private fun createDevEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( environment = ApiEnvironment.DEV, - baseUrl = "https://api.dev.us.paera.com/bff-v2/", - headers = createHeaders(), + baseUrl = getBaseUrl(ApiEnvironment.DEV), + headers = createHeaders(ApiEnvironment.DEV), ) private fun createMockedEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( environment = ApiEnvironment.MOCK, - baseUrl = "[REDACTED_ENV_URL]", - headers = createHeaders(), + baseUrl = getBaseUrl(ApiEnvironment.MOCK), + headers = createHeaders(ApiEnvironment.MOCK), ) private fun createProdEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( environment = ApiEnvironment.PROD, - baseUrl = "https://api.us.paera.com/bff-v2/", - headers = createHeaders(), + baseUrl = getBaseUrl(ApiEnvironment.PROD), + headers = createHeaders(ApiEnvironment.PROD), ) - private fun createHeaders() = mapOf( + private fun createHeaders(apiEnvironment: ApiEnvironment) = mapOf( "version" to ProviderSuspend { appVersionProvider.versionName }, "platform" to ProviderSuspend { "Android" }, + "X-API-KEY" to ProviderSuspend { getBffStaticToken(apiEnvironment) }, ) + + private fun getBffStaticToken(apiEnvironment: ApiEnvironment): String { + return when (apiEnvironment) { + ApiEnvironment.MOCK, + ApiEnvironment.DEV, + -> environmentConfigStorage.getConfigSync().bffStaticTokenDev + ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().bffStaticToken + ApiEnvironment.STAGE, + ApiEnvironment.STAGE_2, + ApiEnvironment.DEV_2, + ApiEnvironment.DEV_3, + -> null + } ?: error("BffStaticToken is not provided for $apiEnvironment") + } + + class Bff( + appVersionProvider: AppVersionProvider, + environmentConfigStorage: EnvironmentConfigStorage, + ) : TangemPay(appVersionProvider, environmentConfigStorage) { + override fun getBaseUrl(apiEnvironment: ApiEnvironment): String { + return when (apiEnvironment) { + ApiEnvironment.DEV -> "https://api.dev.us.paera.com/bff-v2/" + ApiEnvironment.MOCK -> "[REDACTED_ENV_URL]" + ApiEnvironment.PROD -> "https://api.us.paera.com/bff-v2/" + ApiEnvironment.DEV_2, + ApiEnvironment.DEV_3, + ApiEnvironment.STAGE, + ApiEnvironment.STAGE_2, + -> error("Unknown environment: $apiEnvironment") + } + } + } + + class Auth( + appVersionProvider: AppVersionProvider, + environmentConfigStorage: EnvironmentConfigStorage, + ) : TangemPay(appVersionProvider, environmentConfigStorage) { + override fun getBaseUrl(apiEnvironment: ApiEnvironment): String { + return when (apiEnvironment) { + ApiEnvironment.DEV -> "https://api.dev.us.paera.com/" + ApiEnvironment.MOCK -> "[REDACTED_ENV_URL]" + ApiEnvironment.PROD -> "https://api.us.paera.com/" + ApiEnvironment.DEV_2, + ApiEnvironment.DEV_3, + ApiEnvironment.STAGE, + ApiEnvironment.STAGE_2, + -> error("Unknown environment: $apiEnvironment") + } + } + } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPayAuth.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPayAuth.kt deleted file mode 100644 index cbbc29459d..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPayAuth.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.tangem.datasource.api.common.config - -import com.tangem.datasource.BuildConfig -import com.tangem.utils.ProviderSuspend -import com.tangem.utils.version.AppVersionProvider - -internal class TangemPayAuth( - private val appVersionProvider: AppVersionProvider, -) : ApiConfig() { - override val defaultEnvironment: ApiEnvironment = getInitialEnvironment() - - override val environmentConfigs = listOf( - createDevEnvironment(), - createMockedEnvironment(), - createProdEnvironment(), - ) - - private fun getInitialEnvironment(): ApiEnvironment { - return when (BuildConfig.BUILD_TYPE) { - MOCKED_BUILD_TYPE -> ApiEnvironment.MOCK - DEBUG_BUILD_TYPE, - INTERNAL_BUILD_TYPE, - -> ApiEnvironment.DEV - EXTERNAL_BUILD_TYPE, - RELEASE_BUILD_TYPE, - -> ApiEnvironment.PROD - else -> error("Unknown build type [${BuildConfig.BUILD_TYPE}]") - } - } - - private fun createDevEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( - environment = ApiEnvironment.DEV, - baseUrl = "https://api.dev.us.paera.com/", - headers = createHeaders(), - ) - - private fun createMockedEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( - environment = ApiEnvironment.MOCK, - baseUrl = "[REDACTED_ENV_URL]", - headers = createHeaders(), - ) - - private fun createProdEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( - environment = ApiEnvironment.PROD, - baseUrl = "https://api.us.paera.com/", - headers = createHeaders(), - ) - - private fun createHeaders() = mapOf( - "version" to ProviderSuspend { appVersionProvider.versionName }, - "platform" to ProviderSuspend { "Android" }, - ) -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/pay/TangemPayApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/pay/TangemPayApi.kt index 773dbb7b72..60484ac83b 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/pay/TangemPayApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/pay/TangemPayApi.kt @@ -25,7 +25,6 @@ interface TangemPayApi { @GET("v1/customer/wallets/{customer_wallet_id}") suspend fun checkCustomerWalletId( - @Header("X-API-KEY") authHeader: String, @Path("customer_wallet_id") customerWalletId: String, ): ApiResponse diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/ApiConfigsModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/ApiConfigsModule.kt index 2ae61bd722..20d4c632d5 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/ApiConfigsModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/ApiConfigsModule.kt @@ -86,13 +86,17 @@ internal object ApiConfigsModule { @Provides @IntoSet - fun provideTangemVisaConfig(appVersionProvider: AppVersionProvider): ApiConfig = TangemPay(appVersionProvider) + fun provideTangemPayBffConfig( + appVersionProvider: AppVersionProvider, + environmentConfigStorage: EnvironmentConfigStorage, + ): ApiConfig = TangemPay.Bff(appVersionProvider, environmentConfigStorage) @Provides @IntoSet - fun provideTangemPayAuthConfig(appVersionProvider: AppVersionProvider): ApiConfig = TangemPayAuth( - appVersionProvider, - ) + fun provideTangemPayAuthConfig( + appVersionProvider: AppVersionProvider, + environmentConfigStorage: EnvironmentConfigStorage, + ): ApiConfig = TangemPay.Auth(appVersionProvider, environmentConfigStorage) @Provides @IntoSet diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/config/environment/EnvironmentConfig.kt b/core/datasource/src/main/java/com/tangem/datasource/local/config/environment/EnvironmentConfig.kt index c77d5ede0c..22545b5329 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/config/environment/EnvironmentConfig.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/config/environment/EnvironmentConfig.kt @@ -25,6 +25,7 @@ data class EnvironmentConfig( val yieldModuleApiKey: String? = null, val yieldModuleApiKeyDev: String? = null, val bffStaticToken: String? = null, + val bffStaticTokenDev: String? = null, val gaslessTxApiKeyDev: String? = null, val gaslessTxApiKey: String? = null, ) \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/config/environment/converter/EnvironmentConfigConverter.kt b/core/datasource/src/main/java/com/tangem/datasource/local/config/environment/converter/EnvironmentConfigConverter.kt index 8e19d3682e..6d7733109a 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/config/environment/converter/EnvironmentConfigConverter.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/config/environment/converter/EnvironmentConfigConverter.kt @@ -33,6 +33,7 @@ internal object EnvironmentConfigConverter : Converter StakeKit(stakeKitAuthProvider = mockk()) - ApiConfig.ID.TangemPay -> TangemPay(appVersionProvider = mockk()) + ApiConfig.ID.TangemPay -> TangemPay.Bff( + appVersionProvider = mockk(), + environmentConfigStorage = mockk() + ) + ApiConfig.ID.TangemPayAuth -> TangemPay.Auth( + appVersionProvider = mockk(), + environmentConfigStorage = mockk() + ) ApiConfig.ID.BlockAid -> BlockAid(configStorage = mockk()) ApiConfig.ID.MoonPay -> MoonPay() ApiConfig.ID.P2PEthPool -> P2PEthPool(p2pAuthProvider = mockk()) @@ -78,7 +85,6 @@ class ApiConfigTest { authProvider = appAuthProvider, appInfoProvider = mockk(), ) - ApiConfig.ID.TangemPayAuth -> TangemPayAuth(appVersionProvider = mockk()) ApiConfig.ID.GaslessTxService -> GaslessTxService( authProvider = appAuthProvider, appVersionProvider = mockk(), diff --git a/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/managers/MockEnvironmentConfigStorage.kt b/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/managers/MockEnvironmentConfigStorage.kt index 7a7a84ca41..530d4de06e 100644 --- a/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/managers/MockEnvironmentConfigStorage.kt +++ b/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/managers/MockEnvironmentConfigStorage.kt @@ -18,6 +18,8 @@ internal class MockEnvironmentConfigStorage : EnvironmentConfigStorage { blockAidApiKey = BLOCK_AID_API_KEY, tangemApiKey = TANGEM_API_KEY, tangemApiKeyDev = TANGEM_API_KEY_DEV, + bffStaticToken = TANGEM_PAY_BFF_KEY, + bffStaticTokenDev = TANGEM_PAY_BFF_KEY_DEV, tangemApiKeyStage = TANGEM_API_KEY_STAGE, yieldModuleApiKey = YIELD_MODULE_KEY, yieldModuleApiKeyDev = YIELD_MODULE_KEY_DEV, @@ -33,6 +35,8 @@ internal class MockEnvironmentConfigStorage : EnvironmentConfigStorage { const val BLOCK_AID_API_KEY = "block_aid_api_key" const val TANGEM_API_KEY = "tangem_api_key" const val TANGEM_API_KEY_DEV = "tangem_api_key_dev" + const val TANGEM_PAY_BFF_KEY = "tangem_pay_bff_key" + const val TANGEM_PAY_BFF_KEY_DEV = "tangem_pay_bff_key_dev" const val TANGEM_GASLESS_API_KEY = "tangem_gasless_api_key" const val TANGEM_API_KEY_STAGE = "tangem_api_key_stage" const val YIELD_MODULE_KEY = "yield_module_api_key" 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 bb76d42aeb..76572d804f 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 @@ -13,6 +13,7 @@ import com.tangem.datasource.api.common.config.ApiConfig.Companion.RELEASE_BUILD import com.tangem.datasource.api.common.config.managers.MockEnvironmentConfigStorage.Companion.BLOCK_AID_API_KEY import com.tangem.datasource.api.common.config.managers.MockEnvironmentConfigStorage.Companion.TANGEM_API_KEY import com.tangem.datasource.api.common.config.managers.MockEnvironmentConfigStorage.Companion.TANGEM_GASLESS_API_KEY +import com.tangem.datasource.api.common.config.managers.MockEnvironmentConfigStorage.Companion.TANGEM_PAY_BFF_KEY_DEV import com.tangem.domain.staking.model.ethpool.P2PEthPoolStakingConfig import com.tangem.lib.auth.ExpressAuthProvider import com.tangem.lib.auth.P2PEthPoolAuthProvider @@ -115,7 +116,14 @@ internal class ProdApiConfigsManagerTest { ) } ApiConfig.ID.StakeKit -> StakeKit(stakeKitAuthProvider = stakeKitAuthProvider) - ApiConfig.ID.TangemPay -> TangemPay(appVersionProvider = appVersionProvider) + ApiConfig.ID.TangemPay -> TangemPay.Bff( + appVersionProvider = appVersionProvider, + environmentConfigStorage = environmentConfigStorage, + ) + ApiConfig.ID.TangemPayAuth -> TangemPay.Auth( + appVersionProvider = appVersionProvider, + environmentConfigStorage = environmentConfigStorage, + ) ApiConfig.ID.BlockAid -> BlockAid(configStorage = environmentConfigStorage) ApiConfig.ID.MoonPay -> MoonPay() ApiConfig.ID.P2PEthPool -> P2PEthPool(p2pAuthProvider = p2pEthPoolAuthProvider) @@ -124,7 +132,6 @@ internal class ProdApiConfigsManagerTest { authProvider = appAuthProvider, appInfoProvider = appInfoProvider, ) - ApiConfig.ID.TangemPayAuth -> TangemPayAuth(appVersionProvider = appVersionProvider) ApiConfig.ID.GaslessTxService -> GaslessTxService( authProvider = appAuthProvider, appVersionProvider = appVersionProvider, @@ -141,11 +148,11 @@ internal class ProdApiConfigsManagerTest { ApiConfig.ID.TangemTech -> createTangemTechModel() ApiConfig.ID.StakeKit -> createStakeKitModel() ApiConfig.ID.TangemPay -> createTangemPayModel() + ApiConfig.ID.TangemPayAuth -> createTangemPayAuthModel() ApiConfig.ID.BlockAid -> createBlockAidSdkModel() ApiConfig.ID.MoonPay -> createMoonPayModel() ApiConfig.ID.P2PEthPool -> createP2PModel() ApiConfig.ID.News -> createNewsModel() - ApiConfig.ID.TangemPayAuth -> createTangemPayAuthModel() ApiConfig.ID.GaslessTxService -> createGaslessTxServiceModel() } } @@ -269,6 +276,7 @@ internal class ProdApiConfigsManagerTest { headers = mapOf( "version" to ProviderSuspend { VERSION_NAME }, "platform" to ProviderSuspend { "Android" }, + "X-API-KEY" to ProviderSuspend { TANGEM_PAY_BFF_KEY_DEV }, ), ), ) @@ -283,6 +291,7 @@ internal class ProdApiConfigsManagerTest { headers = mapOf( "version" to ProviderSuspend { VERSION_NAME }, "platform" to ProviderSuspend { "Android" }, + "X-API-KEY" to ProviderSuspend { TANGEM_PAY_BFF_KEY_DEV }, ), ), ) diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt index aac0e1c218..0872260f70 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/DefaultOnboardingRepository.kt @@ -185,11 +185,8 @@ internal class DefaultOnboardingRepository @Inject constructor( return Either.Right(hasTangemPay) } - return requestHelper.performWithStaticToken { staticToken -> - tangemPayApi.checkCustomerWalletId( - authHeader = staticToken, - customerWalletId = userWalletId.stringValue, - ) + return requestHelper.performWithStaticToken { + tangemPayApi.checkCustomerWalletId(customerWalletId = userWalletId.stringValue) }.map { response -> val id = response.result?.id val isTangemPayEnabled = response.result?.isTangemPayEnabled == true @@ -205,7 +202,7 @@ internal class DefaultOnboardingRepository @Inject constructor( } override suspend fun checkCustomerEligibility(): Boolean { - val response = requestHelper.performWithoutToken { + val response = requestHelper.performWithStaticToken { tangemPayApi.checkCustomerEligibility() }.getOrNull() diff --git a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt index a788639680..e85c5c6f64 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/pay/repository/TangemPayRequestPerformer.kt @@ -11,7 +11,6 @@ import com.tangem.datasource.api.common.response.ApiResponse import com.tangem.datasource.api.pay.TangemPayAuthApi import com.tangem.datasource.api.pay.models.request.RefreshCustomerWalletAccessTokenRequest import com.tangem.datasource.api.pay.models.response.TangemPayGetTokensResponse -import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage import com.tangem.datasource.local.visa.TangemPayStorage import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.visa.error.VisaApiError @@ -31,7 +30,6 @@ private const val TAG = "TangemPayRequestPerformer" @Singleton internal class TangemPayRequestPerformer @Inject constructor( private val errorConverter: TangemPayErrorConverter, - private val environmentConfigStorage: EnvironmentConfigStorage, private val dispatchers: CoroutineDispatcherProvider, private val tangemPayAuthApi: TangemPayAuthApi, private val tangemPayStorage: TangemPayStorage, @@ -40,23 +38,10 @@ internal class TangemPayRequestPerformer @Inject constructor( private val customerWalletAddresses = ConcurrentHashMap() private val tokensMutex = Mutex() - suspend fun performWithStaticToken( - requestBlock: suspend (header: String) -> ApiResponse, - ): Either = withContext(dispatchers.io) { - catch( - block = { - val staticToken = - environmentConfigStorage.getConfigSync().bffStaticToken ?: error("BFF static token is null") - when (val apiResponse = requestBlock(staticToken)) { - is ApiResponse.Error -> errorConverter.convert(apiResponse.cause).left() - is ApiResponse.Success -> apiResponse.data.right() - } - }, - catch = { errorConverter.convert(it).left() }, - ) - } - - suspend fun performWithoutToken(requestBlock: suspend () -> ApiResponse): Either = + /** + * Static token added in headers [com.tangem.datasource.api.common.config.TangemPay] + */ + suspend fun performWithStaticToken(requestBlock: suspend () -> ApiResponse): Either = withContext(dispatchers.io) { catch( block = {