diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index a837db2797..35af912b96 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit a837db27973dca80e51cf9590eb34e060bed1236 +Subproject commit 35af912b96ce0f871906061bd483d9cf3af7451d diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechServiceApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechServiceApi.kt index f5a24561f8..7bd52cc1e2 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechServiceApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/tangemTech/TangemTechServiceApi.kt @@ -2,7 +2,6 @@ package com.tangem.datasource.api.tangemTech import com.tangem.datasource.config.models.ProviderModel import retrofit2.http.GET -import retrofit2.http.Header /** * Tangem Tech API for app services @@ -12,8 +11,5 @@ import retrofit2.http.Header interface TangemTechServiceApi { @GET("networks/providers") - suspend fun getBlockchainProviders( - @Header("card_public_key") cardPublicKey: String, - @Header("card_id") cardId: String, - ): Map> + suspend fun getBlockchainProviders(): Map> } \ No newline at end of file diff --git a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/loader/BlockchainProvidersResponseLoader.kt b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/loader/BlockchainProvidersResponseLoader.kt index b56ad1dd18..bb0a9800a6 100644 --- a/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/loader/BlockchainProvidersResponseLoader.kt +++ b/libs/blockchain-sdk/src/main/java/com/tangem/blockchainsdk/loader/BlockchainProvidersResponseLoader.kt @@ -3,7 +3,6 @@ package com.tangem.blockchainsdk.loader import androidx.core.util.PatternsCompat import com.google.firebase.crashlytics.FirebaseCrashlytics import com.tangem.blockchainsdk.BlockchainProvidersResponse -import com.tangem.datasource.api.common.AuthProvider import com.tangem.datasource.api.tangemTech.TangemTechServiceApi import com.tangem.datasource.asset.loader.AssetLoader import com.tangem.datasource.config.models.ProviderModel @@ -17,7 +16,6 @@ import javax.inject.Singleton * Loader of [BlockchainProvidersResponse] * * @property tangemTechServiceApi tangem tech api - * @property authProvider auth provider * @property assetLoader asset loader for local config loading * @property dispatchers dispatchers * @@ -26,7 +24,6 @@ import javax.inject.Singleton @Singleton internal class BlockchainProvidersResponseLoader @Inject constructor( private val tangemTechServiceApi: TangemTechServiceApi, - private val authProvider: AuthProvider, private val assetLoader: AssetLoader, private val dispatchers: CoroutineDispatcherProvider, ) { @@ -51,12 +48,7 @@ internal class BlockchainProvidersResponseLoader @Inject constructor( return assetLoader.load(fileName = PROVIDER_TYPES_FILE_NAME) } - private suspend fun loadRemote(): BlockchainProvidersResponse { - return tangemTechServiceApi.getBlockchainProviders( - cardPublicKey = authProvider.getCardPublicKey(), - cardId = authProvider.getCardId(), - ) - } + private suspend fun loadRemote() = tangemTechServiceApi.getBlockchainProviders() /** Merge blockchains with non-empty providers [remote] from remote with blockchains from local [local] */ private fun mergeResponses( @@ -87,7 +79,7 @@ internal class BlockchainProvidersResponseLoader @Inject constructor( recordException(missingBlockchains = missingBlockchains + blockchainsWithoutProviders) } - return result + return result.guaranteeUrlsEndWithSlash() } private fun List.filterUnsupportedProviders() = filter { it !is ProviderModel.UnsupportedType } @@ -118,6 +110,24 @@ internal class BlockchainProvidersResponseLoader @Inject constructor( firebaseCrashlytics.recordException(exception) } + /* + * Example: + * https://qwe.com --> https://qwe.com/ + */ + private fun BlockchainProvidersResponse.guaranteeUrlsEndWithSlash(): BlockchainProvidersResponse { + return mapValues { + it.value.map { provider -> provider.addSlashIfAbsent() } + } + } + + private fun ProviderModel.addSlashIfAbsent(): ProviderModel { + return if (this is ProviderModel.Public && url.last() != '/') { + copy(url = "$url/") + } else { + this + } + } + private companion object { const val PROVIDER_TYPES_FILE_NAME = "tangem-app-config/providers_order" diff --git a/libs/blockchain-sdk/src/test/java/com/tangem/blockchainsdk/loader/BlockchainProvidersResponseLoaderTest.kt b/libs/blockchain-sdk/src/test/java/com/tangem/blockchainsdk/loader/BlockchainProvidersResponseLoaderTest.kt index ed55c6cfed..5f1f5fb283 100644 --- a/libs/blockchain-sdk/src/test/java/com/tangem/blockchainsdk/loader/BlockchainProvidersResponseLoaderTest.kt +++ b/libs/blockchain-sdk/src/test/java/com/tangem/blockchainsdk/loader/BlockchainProvidersResponseLoaderTest.kt @@ -7,7 +7,6 @@ import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi import com.squareup.moshi.adapter import com.tangem.blockchainsdk.BlockchainProvidersResponse -import com.tangem.datasource.api.common.AuthProvider import com.tangem.datasource.api.tangemTech.TangemTechServiceApi import com.tangem.datasource.asset.loader.AssetLoader import com.tangem.datasource.asset.reader.AssetReader @@ -26,7 +25,6 @@ import org.junit.Test internal class BlockchainProvidersResponseLoaderTest { private val tangemTechServiceApi = mockk() - private val authProvider = mockk() private val assetReader = mockk() private val moshi = mockk() private val jsonAdapter = mockk>() @@ -36,7 +34,6 @@ internal class BlockchainProvidersResponseLoaderTest { private val loader = BlockchainProvidersResponseLoader( tangemTechServiceApi = tangemTechServiceApi, - authProvider = authProvider, assetLoader = assetLoader, dispatchers = TestingCoroutineDispatcherProvider(), ) @@ -62,32 +59,23 @@ internal class BlockchainProvidersResponseLoaderTest { jsonAdapter.fromJson(emptyJson) } - coVerify(inverse = true) { - authProvider.getCardPublicKey() - authProvider.getCardId() - tangemTechServiceApi.getBlockchainProviders(any(), any()) - } + coVerify(inverse = true) { tangemTechServiceApi.getBlockchainProviders() } Truth.assertThat(actual).isEqualTo(null) } @Test fun test_load_if_remote_config_loading_is_loaded_failure() = runTest { - everyGettingLocalConfig(json = localProvidersJson) returns localProviders - everyGettingRemoteConfig() throws IllegalStateException("Test exception") + everyGettingLocalConfig(json = LOCAL_PROVIDERS_JSON) returns localProviders + coEvery { tangemTechServiceApi.getBlockchainProviders() } throws IllegalStateException("Test exception") val actual = loader.load() coVerifyOrder { assetReader.read(LOCAL_CONFIG_FILE_NAME) moshi.adapter() - jsonAdapter.fromJson(localProvidersJson) - authProvider.getCardPublicKey() - authProvider.getCardId() - tangemTechServiceApi.getBlockchainProviders( - cardPublicKey = DEFAULT_CARD_PUBLIC_KEY, - cardId = DEFAULT_CARD_ID, - ) + jsonAdapter.fromJson(LOCAL_PROVIDERS_JSON) + tangemTechServiceApi.getBlockchainProviders() } Truth.assertThat(actual).isEqualTo(localProviders) @@ -95,21 +83,16 @@ internal class BlockchainProvidersResponseLoaderTest { @Test fun test_load_if_remote_config_loading_is_loaded_successful() = runTest { - everyGettingLocalConfig(json = localProvidersJson) returns localProviders - everyGettingRemoteConfig() returns remoteProviders + everyGettingLocalConfig(json = LOCAL_PROVIDERS_JSON) returns localProviders + coEvery { tangemTechServiceApi.getBlockchainProviders() } returns remoteProviders val actual = loader.load() coVerifyOrder { assetReader.read(LOCAL_CONFIG_FILE_NAME) moshi.adapter() - jsonAdapter.fromJson(localProvidersJson) - authProvider.getCardPublicKey() - authProvider.getCardId() - tangemTechServiceApi.getBlockchainProviders( - cardPublicKey = DEFAULT_CARD_PUBLIC_KEY, - cardId = DEFAULT_CARD_ID, - ) + jsonAdapter.fromJson(LOCAL_PROVIDERS_JSON) + tangemTechServiceApi.getBlockchainProviders() } Truth.assertThat(actual).isEqualTo(remoteProviders) @@ -119,21 +102,16 @@ internal class BlockchainProvidersResponseLoaderTest { fun test_load_if_remote_config_is_the_same_as_local() = runTest { val remoteProviders = localProviders - everyGettingLocalConfig(json = localProvidersJson) returns localProviders - everyGettingRemoteConfig() returns remoteProviders + everyGettingLocalConfig(json = LOCAL_PROVIDERS_JSON) returns localProviders + coEvery { tangemTechServiceApi.getBlockchainProviders() } returns remoteProviders val actual = loader.load() coVerifyOrder { assetReader.read(LOCAL_CONFIG_FILE_NAME) moshi.adapter() - jsonAdapter.fromJson(localProvidersJson) - authProvider.getCardPublicKey() - authProvider.getCardId() - tangemTechServiceApi.getBlockchainProviders( - cardPublicKey = DEFAULT_CARD_PUBLIC_KEY, - cardId = DEFAULT_CARD_ID, - ) + jsonAdapter.fromJson(LOCAL_PROVIDERS_JSON) + tangemTechServiceApi.getBlockchainProviders() } Truth.assertThat(actual).isEqualTo(remoteProviders) @@ -144,8 +122,8 @@ internal class BlockchainProvidersResponseLoaderTest { val ethProvider = "ethereum" to emptyList() val remoteProvidersWithEth = remoteProviders + ethProvider - everyGettingLocalConfig(json = localProvidersJson) returns localProviders - everyGettingRemoteConfig() returns remoteProvidersWithEth + everyGettingLocalConfig(json = LOCAL_PROVIDERS_JSON) returns localProviders + coEvery { tangemTechServiceApi.getBlockchainProviders() } returns remoteProvidersWithEth everyCrashlyticsRecording() just Runs val actual = loader.load() @@ -153,13 +131,8 @@ internal class BlockchainProvidersResponseLoaderTest { coVerifyOrder { assetReader.read(LOCAL_CONFIG_FILE_NAME) moshi.adapter() - jsonAdapter.fromJson(localProvidersJson) - authProvider.getCardPublicKey() - authProvider.getCardId() - tangemTechServiceApi.getBlockchainProviders( - cardPublicKey = DEFAULT_CARD_PUBLIC_KEY, - cardId = DEFAULT_CARD_ID, - ) + jsonAdapter.fromJson(LOCAL_PROVIDERS_JSON) + tangemTechServiceApi.getBlockchainProviders() firebaseCrashlytics.recordException(any()) } @@ -170,21 +143,16 @@ internal class BlockchainProvidersResponseLoaderTest { fun test_load_if_local_config_has_empty_providers() = runTest { val localProvidersWithEmptyApt = localProviders.mapValues { if (it.key == "aptos") emptyList() else it.value } - everyGettingLocalConfig(json = localProvidersJson) returns localProvidersWithEmptyApt - everyGettingRemoteConfig() returns remoteProviders + everyGettingLocalConfig(json = LOCAL_PROVIDERS_JSON) returns localProvidersWithEmptyApt + coEvery { tangemTechServiceApi.getBlockchainProviders() } returns remoteProviders val actual = loader.load() coVerifyOrder { assetReader.read(LOCAL_CONFIG_FILE_NAME) moshi.adapter() - jsonAdapter.fromJson(localProvidersJson) - authProvider.getCardPublicKey() - authProvider.getCardId() - tangemTechServiceApi.getBlockchainProviders( - cardPublicKey = DEFAULT_CARD_PUBLIC_KEY, - cardId = DEFAULT_CARD_ID, - ) + jsonAdapter.fromJson(LOCAL_PROVIDERS_JSON) + tangemTechServiceApi.getBlockchainProviders() } val expected = localProvidersWithEmptyApt + remoteProviders @@ -196,8 +164,8 @@ internal class BlockchainProvidersResponseLoaderTest { fun test_load_if_remote_config_doesnt_contain_local_providers() = runTest { val remoteProvidersWithoutLocal: BlockchainProvidersResponse = remoteProviders - localProviders.keys - everyGettingLocalConfig(json = localProvidersJson) returns localProviders - everyGettingRemoteConfig() returns remoteProvidersWithoutLocal + everyGettingLocalConfig(json = LOCAL_PROVIDERS_JSON) returns localProviders + coEvery { tangemTechServiceApi.getBlockchainProviders() } returns remoteProvidersWithoutLocal everyCrashlyticsRecording() just Runs val actual = loader.load() @@ -205,13 +173,8 @@ internal class BlockchainProvidersResponseLoaderTest { coVerifyOrder { assetReader.read(LOCAL_CONFIG_FILE_NAME) moshi.adapter() - jsonAdapter.fromJson(localProvidersJson) - authProvider.getCardPublicKey() - authProvider.getCardId() - tangemTechServiceApi.getBlockchainProviders( - cardPublicKey = DEFAULT_CARD_PUBLIC_KEY, - cardId = DEFAULT_CARD_ID, - ) + jsonAdapter.fromJson(LOCAL_PROVIDERS_JSON) + tangemTechServiceApi.getBlockchainProviders() firebaseCrashlytics.recordException(any()) } @@ -223,8 +186,8 @@ internal class BlockchainProvidersResponseLoaderTest { val ethProvider = "ethereum" to listOf(ProviderModel.UnsupportedType, ProviderModel.Private(name = "nownodes")) val remoteProvidersWithEth = remoteProviders + ethProvider - everyGettingLocalConfig(json = localProvidersJson) returns localProviders - everyGettingRemoteConfig() returns remoteProvidersWithEth + everyGettingLocalConfig(json = LOCAL_PROVIDERS_JSON) returns localProviders + coEvery { tangemTechServiceApi.getBlockchainProviders() } returns remoteProvidersWithEth everyCrashlyticsRecording() just Runs val actual = loader.load() @@ -232,13 +195,8 @@ internal class BlockchainProvidersResponseLoaderTest { coVerifyOrder { assetReader.read(LOCAL_CONFIG_FILE_NAME) moshi.adapter() - jsonAdapter.fromJson(localProvidersJson) - authProvider.getCardPublicKey() - authProvider.getCardId() - tangemTechServiceApi.getBlockchainProviders( - cardPublicKey = DEFAULT_CARD_PUBLIC_KEY, - cardId = DEFAULT_CARD_ID, - ) + jsonAdapter.fromJson(LOCAL_PROVIDERS_JSON) + tangemTechServiceApi.getBlockchainProviders() firebaseCrashlytics.recordException(any()) } @@ -255,8 +213,8 @@ internal class BlockchainProvidersResponseLoaderTest { val remoteEthProvider = "ethereum" to listOf(ProviderModel.UnsupportedType, ProviderModel.Public("adbw2138")) val remoteProvidersWithEth = remoteProviders + remoteEthProvider - everyGettingLocalConfig(json = localProvidersJson) returns localProvidersWithEth - everyGettingRemoteConfig() returns remoteProvidersWithEth + everyGettingLocalConfig(json = LOCAL_PROVIDERS_JSON) returns localProvidersWithEth + coEvery { tangemTechServiceApi.getBlockchainProviders() } returns remoteProvidersWithEth everyCrashlyticsRecording() just Runs val actual = loader.load() @@ -264,13 +222,8 @@ internal class BlockchainProvidersResponseLoaderTest { coVerifyOrder { assetReader.read(LOCAL_CONFIG_FILE_NAME) moshi.adapter() - jsonAdapter.fromJson(localProvidersJson) - authProvider.getCardPublicKey() - authProvider.getCardId() - tangemTechServiceApi.getBlockchainProviders( - cardPublicKey = DEFAULT_CARD_PUBLIC_KEY, - cardId = DEFAULT_CARD_ID, - ) + jsonAdapter.fromJson(LOCAL_PROVIDERS_JSON) + tangemTechServiceApi.getBlockchainProviders() firebaseCrashlytics.recordException(any()) } @@ -279,6 +232,37 @@ internal class BlockchainProvidersResponseLoaderTest { Truth.assertThat(actual).isEqualTo(expected) } + @Test + fun test_load_if_configs_contain_public_providers_without_slash_in_the_end() = runTest { + val localPublicProviderUrl = "https://qwe.com" + val localEthProvider = "ethereum" to listOf(ProviderModel.Public(url = localPublicProviderUrl)) + val localProvidersWithEth = localProviders + localEthProvider + + val remotePublicProviderUrl = "https://rty.com" + val remoteDogeProvider = "dogecoin" to listOf(ProviderModel.Public(url = remotePublicProviderUrl)) + val remoteProvidersWithDoge = remoteProviders + remoteDogeProvider + + everyGettingLocalConfig(json = LOCAL_PROVIDERS_JSON) returns localProvidersWithEth + coEvery { tangemTechServiceApi.getBlockchainProviders() } returns remoteProvidersWithDoge + everyCrashlyticsRecording() just Runs + + val actual = loader.load() + + coVerifyOrder { + assetReader.read(LOCAL_CONFIG_FILE_NAME) + moshi.adapter() + jsonAdapter.fromJson(LOCAL_PROVIDERS_JSON) + tangemTechServiceApi.getBlockchainProviders() + firebaseCrashlytics.recordException(any()) + } + + val expected = remoteProviders + + localEthProvider.copy(second = listOf(ProviderModel.Public(url = "$localPublicProviderUrl/"))) + + remoteDogeProvider.copy(second = listOf(ProviderModel.Public(url = "$remotePublicProviderUrl/"))) + + Truth.assertThat(actual).isEqualTo(expected) + } + private fun everyGettingLocalConfig( json: String, ): MockKStubScope { @@ -287,51 +271,18 @@ internal class BlockchainProvidersResponseLoaderTest { return coEvery { jsonAdapter.fromJson(json) } } - private fun everyGettingRemoteConfig(): MockKStubScope { - every { authProvider.getCardPublicKey() } returns DEFAULT_CARD_PUBLIC_KEY - every { authProvider.getCardId() } returns DEFAULT_CARD_ID - - return coEvery { - tangemTechServiceApi.getBlockchainProviders( - cardPublicKey = DEFAULT_CARD_PUBLIC_KEY, - cardId = DEFAULT_CARD_ID, - ) - } - } - private fun everyCrashlyticsRecording() = every { firebaseCrashlytics.recordException(any()) } private companion object { const val LOCAL_CONFIG_FILE_NAME = "tangem-app-config/providers_order.json" - const val DEFAULT_CARD_PUBLIC_KEY = "card_public_key" - const val DEFAULT_CARD_ID = "card_id" - val localProvidersJson = """ - { - "aptos": [ - { - "type": "private", - "name": "private_apt" - } - ], - "algorand": [ - { - "type": "private", - "name": "private_alg" - }, - { - "type": "public", - "name": "https://public_alg.com" - } - ] - } - """.trimIndent() + const val LOCAL_PROVIDERS_JSON = "doesn't matter" val localProviders: BlockchainProvidersResponse = mapOf( "aptos" to listOf(ProviderModel.Private(name = "private_apt")), "algorand" to listOf( ProviderModel.Private(name = "private_alg"), - ProviderModel.Public(url = "https://public_alg.com"), + ProviderModel.Public(url = "https://public_alg.com/"), ), )