Updated on 2026-08-14

This commit is contained in:
Tangem 2024-09-28 14:33:53 +04:00
parent 18af16b795
commit cd0b30eaec
40 changed files with 235 additions and 258 deletions

View file

@ -8,8 +8,8 @@ import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
import com.tangem.domain.apptheme.GetAppThemeModeUseCase
@ -45,7 +45,7 @@ import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository
@Suppress("TooManyFunctions")
interface ApplicationEntryPoint {
fun getConfigManager(): ConfigManager
fun getEnvironmentConfigStorage(): EnvironmentConfigStorage
fun getAppStateHolder(): AppStateHolder

View file

@ -15,9 +15,9 @@ import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.datasource.api.common.createNetworkLoggingInterceptor
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.config.models.Config
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
import com.tangem.domain.apptheme.GetAppThemeModeUseCase
@ -76,8 +76,8 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
private val appStateHolder: AppStateHolder
get() = entryPoint.getAppStateHolder()
private val configManager: ConfigManager
get() = entryPoint.getConfigManager()
private val environmentConfigStorage: EnvironmentConfigStorage
get() = entryPoint.getEnvironmentConfigStorage()
private val assetLoader: AssetLoader
get() = entryPoint.getAssetLoader()
@ -202,10 +202,10 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
runBlocking {
featureTogglesManager.init()
val config = configManager.initialize()
store.dispatch(GlobalAction.SetConfigManager(configManager))
val config = environmentConfigStorage.initialize()
store.dispatch(GlobalAction.SetConfigManager(environmentConfigStorage))
initWithConfigDependency(config = config)
initWithConfigDependency(environmentConfig = config)
}
loadNativeLibraries()
@ -223,7 +223,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
)
appStateHolder.mainStore = store
walletConnect2Repository.init(projectId = configManager.getConfigSync().walletConnectProjectId)
walletConnect2Repository.init(projectId = environmentConfigStorage.getConfigSync().walletConnectProjectId)
}
private fun createReduxStore(): Store<AppState> {
@ -278,12 +278,12 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
System.loadLibrary("TrustWalletCore")
}
private fun initWithConfigDependency(config: Config) {
initAnalytics(this, config)
private fun initWithConfigDependency(environmentConfig: EnvironmentConfig) {
initAnalytics(this, environmentConfig)
Log.addLogger(logger = tangemSdkLogger)
}
private fun initAnalytics(application: Application, config: Config) {
private fun initAnalytics(application: Application, environmentConfig: EnvironmentConfig) {
val factory = AnalyticsFactory()
factory.addHandlerBuilder(AmplitudeAnalyticsHandler.Builder())
factory.addHandlerBuilder(FirebaseAnalyticsHandler.Builder())
@ -292,7 +292,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
val buildData = AnalyticsHandlerBuilder.Data(
application = application,
config = config,
config = environmentConfig,
isDebug = BuildConfig.DEBUG,
logConfig = LogConfig.analyticsHandlers,
jsonConverter = MoshiConverter.sdkMoshiConverter,

View file

@ -3,15 +3,15 @@ package com.tangem.tap.common.analytics.api
import android.app.Application
import com.tangem.common.json.MoshiJsonConverter
import com.tangem.core.analytics.api.AnalyticsHandler
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.domain.common.AnalyticsHandlersLogConfig
import com.tangem.datasource.config.models.Config
interface AnalyticsHandlerBuilder {
fun build(data: Data): AnalyticsHandler?
data class Data(
val application: Application,
val config: Config,
val config: EnvironmentConfig,
val isDebug: Boolean,
val logConfig: AnalyticsHandlersLogConfig,
val jsonConverter: MoshiJsonConverter,

View file

@ -2,7 +2,7 @@ package com.tangem.tap.common.redux.global
import com.tangem.common.CompletionResult
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.redux.StateDialog
@ -67,7 +67,7 @@ sealed class GlobalAction : Action {
val walletPublicKey: ByteArray,
) : GlobalAction()
data class SetConfigManager(val configManager: ConfigManager) : GlobalAction()
data class SetConfigManager(val environmentConfigStorage: EnvironmentConfigStorage) : GlobalAction()
object ExchangeManager : GlobalAction() {
object Init : GlobalAction() {

View file

@ -4,7 +4,7 @@ import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.datasource.config.models.Config
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.common.LogConfig
import com.tangem.domain.models.scan.CardDTO
@ -57,7 +57,7 @@ private fun handleAction(action: Action, appState: () -> AppState?) {
}
is GlobalAction.ExchangeManager.Init -> {
val appStateSafe = appState() ?: return
val config = appStateSafe.globalState.configManager?.getConfigSync() ?: return
val config = appStateSafe.globalState.environmentConfigStorage?.getConfigSync() ?: return
scope.launch {
val scanResponseProvider: () -> ScanResponse? = {
@ -140,21 +140,24 @@ private fun restoreAppCurrency() {
}
}
private fun makeSellExchangeService(config: Config): ExchangeService {
private fun makeSellExchangeService(environmentConfig: EnvironmentConfig): ExchangeService {
return MoonPayService(
apiKey = config.moonPayApiKey,
secretKey = config.moonPayApiSecretKey,
apiKey = environmentConfig.moonPayApiKey,
secretKey = environmentConfig.moonPayApiSecretKey,
logEnabled = LogConfig.network.moonPayService,
)
}
private fun makeBuyExchangeService(config: Config): ExchangeService {
private fun makeBuyExchangeService(environmentConfig: EnvironmentConfig): ExchangeService {
return BuyExchangeService(
mercuryoService = makeMercuryoExchangeService(config),
mercuryoService = makeMercuryoExchangeService(environmentConfig),
)
}
private fun makeMercuryoExchangeService(config: Config): MercuryoService {
val mercuryoEnvironment = MercuryoEnvironment.prod(config.mercuryoWidgetId, config.mercuryoSecret)
private fun makeMercuryoExchangeService(environmentConfig: EnvironmentConfig): MercuryoService {
val mercuryoEnvironment = MercuryoEnvironment.prod(
environmentConfig.mercuryoWidgetId,
environmentConfig.mercuryoSecret,
)
return MercuryoService(mercuryoEnvironment)
}

View file

@ -48,7 +48,7 @@ fun globalReducer(action: Action, state: AppState, appStateHolder: AppStateHolde
globalState.copy(appCurrency = action.appCurrency)
}
is GlobalAction.SetConfigManager -> {
globalState.copy(configManager = action.configManager)
globalState.copy(environmentConfigStorage = action.environmentConfigStorage)
}
is GlobalAction.UpdateWalletSignedHashes -> {
val card = globalState.scanResponse?.card ?: return globalState

View file

@ -1,6 +1,6 @@
package com.tangem.tap.common.redux.global
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.apptheme.model.AppThemeMode
import com.tangem.domain.models.scan.ScanResponse
@ -16,7 +16,7 @@ data class GlobalState(
val onboardingState: OnboardingState = OnboardingState(),
val cardVerifiedOnline: Boolean = false,
val tapWalletManager: TapWalletManager = TapWalletManager(),
val configManager: ConfigManager? = null,
val environmentConfigStorage: EnvironmentConfigStorage? = null,
val appCurrency: AppCurrency = AppCurrency.Default,
val scanCardFailsCounter: Int = 0,
val dialog: StateDialog? = null,

View file

@ -1,13 +1,13 @@
package com.tangem.tap.network.auth
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.lib.auth.StakeKitAuthProvider
internal class DefaultStakeKitAuthProvider(
private val configManager: ConfigManager,
private val environmentConfigStorage: EnvironmentConfigStorage,
) : StakeKitAuthProvider {
override fun getApiKey(): String {
return configManager.getConfigSync().stakeKitApiKey ?: error("No StakeKit api key provided")
return environmentConfigStorage.getConfigSync().stakeKitApiKey ?: error("No StakeKit api key provided")
}
}

View file

@ -1,7 +1,7 @@
package com.tangem.tap.network.auth.di
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.lib.auth.ExpressAuthProvider
import com.tangem.lib.auth.StakeKitAuthProvider
@ -35,8 +35,8 @@ class AuthModule {
@Provides
@Singleton
fun provideStakeKitAuthProvider(configManager: ConfigManager): StakeKitAuthProvider {
return DefaultStakeKitAuthProvider(configManager)
fun provideStakeKitAuthProvider(environmentConfigStorage: EnvironmentConfigStorage): StakeKitAuthProvider {
return DefaultStakeKitAuthProvider(environmentConfigStorage)
}
@Provides

View file

@ -1,7 +1,7 @@
package com.tangem.datasource.api.common.config
import com.tangem.datasource.BuildConfig
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.utils.RequestHeader
import com.tangem.lib.auth.ExpressAuthProvider
import com.tangem.utils.Provider
@ -10,12 +10,12 @@ import com.tangem.utils.version.AppVersionProvider
/**
* Express [ApiConfig]
*
* @property configManager config manager
* @property expressAuthProvider express auth provider
* @property appVersionProvider app version provider
* @property environmentConfigStorage environment config storage
* @property expressAuthProvider express auth provider
* @property appVersionProvider app version provider
*/
internal class Express(
private val configManager: ConfigManager,
private val environmentConfigStorage: EnvironmentConfigStorage,
private val expressAuthProvider: ExpressAuthProvider,
private val appVersionProvider: AppVersionProvider,
) : ApiConfig() {
@ -55,9 +55,9 @@ internal class Express(
private fun getApiKey(isProd: Boolean): String {
return if (isProd) {
configManager.getConfigSync().express
environmentConfigStorage.getConfigSync().express
} else {
configManager.getConfigSync().devExpress
environmentConfigStorage.getConfigSync().devExpress
}
?.apiKey
?: error("No express config provided")

View file

@ -4,7 +4,7 @@ import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.promotion.models.PromotionInfoResponse
import com.tangem.datasource.api.tangemTech.models.*
import com.tangem.datasource.api.utils.ReadTimeout
import com.tangem.datasource.config.models.ProviderModel
import com.tangem.datasource.local.config.environment.models.ProviderModel
import retrofit2.http.*
import java.util.concurrent.TimeUnit

View file

@ -1,21 +0,0 @@
package com.tangem.datasource.config
import com.tangem.datasource.config.models.Config
import kotlinx.coroutines.flow.Flow
/**
* Config manager
*
[REDACTED_AUTHOR]
*/
interface ConfigManager {
/** Initialize and return [Config] */
suspend fun initialize(): Config
/** Get [Config] as [Flow] */
fun getConfig(): Flow<Config>
/** Get [Config] synchronously */
fun getConfigSync(): Config
}

View file

@ -1,42 +0,0 @@
package com.tangem.datasource.config
import com.tangem.datasource.BuildConfig
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.config.converter.EnvironmentConfigConverter
import com.tangem.datasource.config.models.Config
import com.tangem.datasource.config.models.ConfigValueModel
import com.tangem.datasource.local.datastore.RuntimeStateStore
import kotlinx.coroutines.flow.Flow
import timber.log.Timber
/**
* Default config manager
*
* @property assetLoader asset loader
* @property configStore config store
*/
internal class DefaultConfigManager(
private val assetLoader: AssetLoader,
private val configStore: RuntimeStateStore<Config>,
) : ConfigManager {
override suspend fun initialize(): Config {
val configValueModel = assetLoader.load<ConfigValueModel>(fileName = CONFIG_FILE_NAME)
?: return configStore.get().value
val config = EnvironmentConfigConverter.convert(value = configValueModel)
configStore.store(value = config)
Timber.i("Config [$CONFIG_FILE_NAME] loaded successfully")
return config
}
override fun getConfig(): Flow<Config> = configStore.get()
override fun getConfigSync(): Config = configStore.get().value
private companion object {
const val CONFIG_FILE_NAME = "tangem-app-config/config_${BuildConfig.ENVIRONMENT}"
}
}

View file

@ -1,12 +0,0 @@
package com.tangem.datasource.config.models
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class ExpressModel(
@Json(name = "apiKey")
val apiKey: String,
@Json(name = "signVerifierPublicKey")
val signVerifierPublicKey: String,
)

View file

@ -1,12 +0,0 @@
package com.tangem.datasource.config.models
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class TonCenterKeys(
@Json(name = "mainnet")
val mainnet: String,
@Json(name = "testnet")
val testnet: String,
)

View file

@ -5,10 +5,10 @@ import com.tangem.crypto.CryptoUtils
import com.tangem.datasource.api.common.config.ApiConfig
import com.tangem.datasource.api.common.config.ApiEnvironment
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
internal class Sha256SignatureVerifier(
private val configManager: ConfigManager,
private val environmentConfigStorage: EnvironmentConfigStorage,
private val apiConfigsManager: ApiConfigsManager,
) : DataSignatureVerifier {
@ -24,8 +24,8 @@ internal class Sha256SignatureVerifier(
private fun getPubKey(): String? {
val expressConfig = apiConfigsManager.getEnvironmentConfig(ApiConfig.ID.Express)
return when (expressConfig.environment) {
ApiEnvironment.PROD -> configManager.getConfigSync().express?.signVerifierPublicKey
else -> configManager.getConfigSync().devExpress?.signVerifierPublicKey
ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().express?.signVerifierPublicKey
else -> environmentConfigStorage.getConfigSync().devExpress?.signVerifierPublicKey
}
}
}

View file

@ -4,7 +4,7 @@ import com.tangem.datasource.api.common.config.ApiConfig
import com.tangem.datasource.api.common.config.Express
import com.tangem.datasource.api.common.config.StakeKit
import com.tangem.datasource.api.common.config.TangemTech
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.lib.auth.ExpressAuthProvider
import com.tangem.lib.auth.StakeKitAuthProvider
import com.tangem.utils.version.AppVersionProvider
@ -21,11 +21,11 @@ internal object ApiConfigsModule {
@Provides
@IntoSet
fun provideExpressConfig(
configManager: ConfigManager,
environmentConfigStorage: EnvironmentConfigStorage,
expressAuthProvider: ExpressAuthProvider,
appVersionProvider: AppVersionProvider,
): ApiConfig {
return Express(configManager, expressAuthProvider, appVersionProvider)
return Express(environmentConfigStorage, expressAuthProvider, appVersionProvider)
}
@Provides

View file

@ -1,26 +0,0 @@
package com.tangem.datasource.di
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.config.DefaultConfigManager
import com.tangem.datasource.config.models.Config
import com.tangem.datasource.local.datastore.RuntimeStateStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object ConfigModule {
@Provides
@Singleton
fun providesConfigManager(assetLoader: AssetLoader): ConfigManager {
return DefaultConfigManager(
assetLoader = assetLoader,
configStore = RuntimeStateStore(defaultValue = Config()),
)
}
}

View file

@ -4,11 +4,11 @@ import com.squareup.moshi.Moshi
import com.squareup.moshi.adapters.PolymorphicJsonAdapterFactory
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import com.tangem.common.json.MoshiJsonConverter
import com.tangem.datasource.api.common.adapter.*
import com.tangem.datasource.api.common.adapter.BigDecimalAdapter
import com.tangem.datasource.api.common.adapter.DateTimeAdapter
import com.tangem.datasource.api.common.adapter.LocalDateAdapter
import com.tangem.datasource.config.models.ProviderModel
import com.tangem.datasource.api.common.adapter.addStakeKitEnumFallbackAdapters
import com.tangem.datasource.local.config.environment.models.ProviderModel
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn

View file

@ -1,9 +1,9 @@
package com.tangem.datasource.di
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.crypto.DataSignatureVerifier
import com.tangem.datasource.crypto.Sha256SignatureVerifier
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -17,9 +17,9 @@ internal object SecurityModule {
@Provides
@Singleton
fun provideDataSignatureVerifier(
configManager: ConfigManager,
environmentConfigStorage: EnvironmentConfigStorage,
apiConfigsManager: ApiConfigsManager,
): DataSignatureVerifier {
return Sha256SignatureVerifier(configManager, apiConfigsManager)
return Sha256SignatureVerifier(environmentConfigStorage, apiConfigsManager)
}
}

View file

@ -1,24 +0,0 @@
package com.tangem.datasource.di
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.local.testnet.DefaultTestnetTokensStorage
import com.tangem.datasource.local.testnet.TestnetTokensStorage
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
/**
[REDACTED_AUTHOR]
*/
@Module
@InstallIn(SingletonComponent::class)
internal object TestnetTokensStorageModule {
@Provides
@Singleton
fun providesTestnetTokensStorage(assetLoader: AssetLoader): TestnetTokensStorage {
return DefaultTestnetTokensStorage(assetLoader)
}
}

View file

@ -0,0 +1,34 @@
package com.tangem.datasource.di.local.config
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.local.config.environment.DefaultEnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.testnet.DefaultTestnetTokensStorage
import com.tangem.datasource.local.config.testnet.TestnetTokensStorage
import com.tangem.datasource.local.datastore.RuntimeStateStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object ConfigModule {
@Provides
@Singleton
fun provideEnvironmentConfigStorage(assetLoader: AssetLoader): EnvironmentConfigStorage {
return DefaultEnvironmentConfigStorage(
assetLoader = assetLoader,
environmentConfigStore = RuntimeStateStore(defaultValue = EnvironmentConfig()),
)
}
@Provides
@Singleton
fun providesTestnetTokensStorage(assetLoader: AssetLoader): TestnetTokensStorage {
return DefaultTestnetTokensStorage(assetLoader)
}
}

View file

@ -0,0 +1,41 @@
package com.tangem.datasource.local.config.environment
import com.tangem.datasource.BuildConfig
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.local.config.environment.converter.EnvironmentConfigConverter
import com.tangem.datasource.local.config.environment.models.EnvironmentConfigModel
import com.tangem.datasource.local.datastore.RuntimeStateStore
import kotlinx.coroutines.flow.Flow
import timber.log.Timber
/**
* Default implementation for storing [EnvironmentConfig]
*
* @property assetLoader asset loader
* @property environmentConfigStore config store
*/
internal class DefaultEnvironmentConfigStorage(
private val assetLoader: AssetLoader,
private val environmentConfigStore: RuntimeStateStore<EnvironmentConfig>,
) : EnvironmentConfigStorage {
override suspend fun initialize(): EnvironmentConfig {
val environmentConfigModel = assetLoader.load<EnvironmentConfigModel>(fileName = CONFIG_FILE_NAME)
?: return environmentConfigStore.get().value
val config = EnvironmentConfigConverter.convert(value = environmentConfigModel)
environmentConfigStore.store(value = config)
Timber.i("Config [$CONFIG_FILE_NAME] loaded successfully")
return config
}
override fun getConfig(): Flow<EnvironmentConfig> = environmentConfigStore.get()
override fun getConfigSync(): EnvironmentConfig = environmentConfigStore.get().value
private companion object {
const val CONFIG_FILE_NAME = "tangem-app-config/config_${BuildConfig.ENVIRONMENT}"
}
}

View file

@ -1,8 +1,9 @@
package com.tangem.datasource.config.models
package com.tangem.datasource.local.config.environment
import com.tangem.blockchain.common.BlockchainSdkConfig
import com.tangem.datasource.local.config.environment.models.ExpressModel
data class Config(
data class EnvironmentConfig(
val moonPayApiKey: String = "pk_test_kc90oYTANy7UQdBavDKGfL4K9l6VEPE",
val moonPayApiSecretKey: String = "sk_test_V8w4M19LbDjjYOt170s0tGuvXAgyEb1C",
val mercuryoWidgetId: String = "",

View file

@ -0,0 +1,20 @@
package com.tangem.datasource.local.config.environment
import kotlinx.coroutines.flow.Flow
/**
* Storage for [EnvironmentConfig]
*
[REDACTED_AUTHOR]
*/
interface EnvironmentConfigStorage {
/** Initialize and return [EnvironmentConfig] */
suspend fun initialize(): EnvironmentConfig
/** Get [EnvironmentConfig] as [Flow] */
fun getConfig(): Flow<EnvironmentConfig>
/** Get [EnvironmentConfig] synchronously */
fun getConfigSync(): EnvironmentConfig
}

View file

@ -1,17 +1,17 @@
package com.tangem.datasource.config.converter
package com.tangem.datasource.local.config.environment.converter
import com.tangem.blockchain.common.*
import com.tangem.datasource.config.models.ConfigValueModel
import com.tangem.datasource.local.config.environment.models.EnvironmentConfigModel
import com.tangem.utils.converter.Converter
/**
* Converts [ConfigValueModel] to [BlockchainSdkConfig]
* Converts [EnvironmentConfigModel] to [BlockchainSdkConfig]
*
[REDACTED_AUTHOR]
*/
internal object BlockchainSDKConfigConverter : Converter<ConfigValueModel, BlockchainSdkConfig> {
internal object BlockchainSDKConfigConverter : Converter<EnvironmentConfigModel, BlockchainSdkConfig> {
override fun convert(value: ConfigValueModel): BlockchainSdkConfig {
override fun convert(value: EnvironmentConfigModel): BlockchainSdkConfig {
return BlockchainSdkConfig(
blockchairCredentials = BlockchairCredentials(
apiKey = value.blockchairApiKeys,
@ -45,7 +45,7 @@ internal object BlockchainSDKConfigConverter : Converter<ConfigValueModel, Block
)
}
private fun createGetBlockCredentials(configValues: ConfigValueModel): GetBlockCredentials? {
private fun createGetBlockCredentials(configValues: EnvironmentConfigModel): GetBlockCredentials? {
return configValues.getBlockAccessTokens?.let { accessTokens ->
GetBlockCredentials(
xrp = GetBlockAccessToken(jsonRpc = accessTokens.xrp?.jsonRPC),

View file

@ -1,18 +1,18 @@
package com.tangem.datasource.config.converter
package com.tangem.datasource.local.config.environment.converter
import com.tangem.datasource.config.models.Config
import com.tangem.datasource.config.models.ConfigValueModel
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.datasource.local.config.environment.models.EnvironmentConfigModel
import com.tangem.utils.converter.Converter
/**
* Converter from [ConfigValueModel] to [Config]
* Converter from [EnvironmentConfigModel] to [EnvironmentConfig]
*
[REDACTED_AUTHOR]
*/
internal object EnvironmentConfigConverter : Converter<ConfigValueModel, Config> {
internal object EnvironmentConfigConverter : Converter<EnvironmentConfigModel, EnvironmentConfig> {
override fun convert(value: ConfigValueModel): Config {
return Config(
override fun convert(value: EnvironmentConfigModel): EnvironmentConfig {
return EnvironmentConfig(
moonPayApiKey = value.moonPayApiKey,
moonPayApiSecretKey = value.moonPayApiSecretKey,
mercuryoWidgetId = value.mercuryoWidgetId,

View file

@ -1,11 +1,11 @@
package com.tangem.datasource.config.models
package com.tangem.datasource.local.config.environment.models
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@Suppress("LongParameterList")
@JsonClass(generateAdapter = true)
class ConfigValueModel(
class EnvironmentConfigModel(
@Json(name = "mercuryoWidgetId") val mercuryoWidgetId: String,
@Json(name = "mercuryoSecret") val mercuryoSecret: String,
@Json(name = "moonPayApiKey") val moonPayApiKey: String,
@ -68,10 +68,24 @@ data class GetBlockAccessTokens(
@Json(name = "filecoin") val filecoin: GetBlockToken?,
)
@JsonClass(generateAdapter = true)
data class TonCenterKeys(
@Json(name = "mainnet") val mainnet: String,
@Json(name = "testnet") val testnet: String,
)
@JsonClass(generateAdapter = true)
data class GetBlockToken(
@Json(name = "jsonRpc") val jsonRPC: String?,
@Json(name = "blockBookRest") val blockBookRest: String?,
@Json(name = "rest") val rest: String?,
@Json(name = "rosetta") val rosetta: String?,
)
@JsonClass(generateAdapter = true)
data class ExpressModel(
@Json(name = "apiKey")
val apiKey: String,
@Json(name = "signVerifierPublicKey")
val signVerifierPublicKey: String,
)

View file

@ -1,4 +1,4 @@
package com.tangem.datasource.config.models
package com.tangem.datasource.local.config.environment.models
import com.squareup.moshi.Json

View file

@ -1,7 +1,7 @@
package com.tangem.datasource.local.testnet
package com.tangem.datasource.local.config.testnet
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.local.testnet.models.TestnetTokensConfig
import com.tangem.datasource.local.config.testnet.models.TestnetTokensConfig
/**
* Default implementation for storing testnet tokens data

View file

@ -1,6 +1,6 @@
package com.tangem.datasource.local.testnet
package com.tangem.datasource.local.config.testnet
import com.tangem.datasource.local.testnet.models.TestnetTokensConfig
import com.tangem.datasource.local.config.testnet.models.TestnetTokensConfig
/**
* Storage of testnet tokens data

View file

@ -1,4 +1,4 @@
package com.tangem.datasource.local.testnet.models
package com.tangem.datasource.local.config.testnet.models
import com.squareup.moshi.Json
@ -7,6 +7,7 @@ import com.squareup.moshi.Json
*
* @property tokens testnet tokens list
*/
// TODO: use CoinsResponse
data class TestnetTokensConfig(
@Json(name = "coins") val tokens: List<Token>,
) {

View file

@ -1,28 +0,0 @@
package com.tangem.datasource.api.common.config.managers
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.config.models.Config
import com.tangem.datasource.config.models.ExpressModel
import kotlinx.coroutines.flow.flowOf
/**
* Mock [ConfigManager] implementation for [ProdApiConfigsManagerTest]
*
[REDACTED_AUTHOR]
*/
internal class MockConfigManager : ConfigManager {
private val config = Config(
express = ExpressModel(apiKey = EXPRESS_API_KEY, signVerifierPublicKey = "vocibus"),
devExpress = ExpressModel(apiKey = EXPRESS_DEV_API_KEY, signVerifierPublicKey = "pellentesque"),
)
override suspend fun initialize() = config
override fun getConfig() = flowOf(config)
override fun getConfigSync() = config
companion object {
const val EXPRESS_API_KEY = "express_api_key"
const val EXPRESS_DEV_API_KEY = "express_dev_api_key"
}
}

View file

@ -0,0 +1,28 @@
package com.tangem.datasource.api.common.config.managers
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.models.ExpressModel
import kotlinx.coroutines.flow.flowOf
/**
* Mock [EnvironmentConfigStorage] implementation for [ProdApiConfigsManagerTest]
*
[REDACTED_AUTHOR]
*/
internal class MockEnvironmentConfigStorage : EnvironmentConfigStorage {
private val environmentConfig = EnvironmentConfig(
express = ExpressModel(apiKey = EXPRESS_API_KEY, signVerifierPublicKey = "vocibus"),
devExpress = ExpressModel(apiKey = EXPRESS_DEV_API_KEY, signVerifierPublicKey = "pellentesque"),
)
override suspend fun initialize() = environmentConfig
override fun getConfig() = flowOf(environmentConfig)
override fun getConfigSync() = environmentConfig
companion object {
const val EXPRESS_API_KEY = "express_api_key"
const val EXPRESS_DEV_API_KEY = "express_dev_api_key"
}
}

View file

@ -19,7 +19,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
private val configManager = MockConfigManager()
private val configManager = MockEnvironmentConfigStorage()
private val appVersionProvider = mockk<AppVersionProvider>()
private val expressAuthProvider = mockk<ExpressAuthProvider>()
private val stakeKitAuthProvider = mockk<StakeKitAuthProvider>()
@ -106,9 +106,9 @@ internal class ProdApiConfigsManagerTest(private val model: Model) {
headers = mapOf(
"api-key" to Provider {
if (environment == ApiEnvironment.PROD) {
MockConfigManager.EXPRESS_API_KEY
MockEnvironmentConfigStorage.EXPRESS_API_KEY
} else {
MockConfigManager.EXPRESS_DEV_API_KEY
MockEnvironmentConfigStorage.EXPRESS_DEV_API_KEY
}
},
"user-id" to Provider { EXPRESS_USER_ID },

View file

@ -6,8 +6,8 @@ import com.tangem.blockchain.common.network.providers.ProviderType
import com.tangem.blockchainsdk.converters.BlockchainProviderTypesConverter
import com.tangem.blockchainsdk.loader.BlockchainProvidersResponseLoader
import com.tangem.blockchainsdk.store.RuntimeStore
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.config.models.ProviderModel
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.models.ProviderModel
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
@ -22,7 +22,7 @@ internal typealias BlockchainProviderTypes = Map<Blockchain, List<ProviderType>>
* Implementation of Blockchain SDK components factory
*
* @property blockchainProvidersResponseLoader blockchain providers response loader
* @property configManager config manager
* @property environmentConfigStorage environment config storage
* @property blockchainProviderTypesStore blockchain provider types store
* @property walletManagerFactoryCreator wallet manager factory creator
*
@ -30,7 +30,7 @@ internal typealias BlockchainProviderTypes = Map<Blockchain, List<ProviderType>>
*/
internal class DefaultBlockchainSDKFactory(
private val blockchainProvidersResponseLoader: BlockchainProvidersResponseLoader,
private val configManager: ConfigManager,
private val environmentConfigStorage: EnvironmentConfigStorage,
private val blockchainProviderTypesStore: RuntimeStore<BlockchainProviderTypes>,
private val walletManagerFactoryCreator: WalletManagerFactoryCreator,
dispatchers: CoroutineDispatcherProvider,
@ -54,7 +54,7 @@ internal class DefaultBlockchainSDKFactory(
private fun createWalletManagerFactory(): Flow<WalletManagerFactory?> {
return combine(
flow = configManager.getConfig().map { it.blockchainSdkConfig },
flow = environmentConfigStorage.getConfig().map { it.blockchainSdkConfig },
flow2 = blockchainProviderTypesStore.get(),
// flow3 = subscribe on feature toggles changes, TODO: [REDACTED_JIRA]
transform = walletManagerFactoryCreator::create,

View file

@ -6,7 +6,7 @@ import com.tangem.blockchainsdk.BlockchainProviderTypes
import com.tangem.blockchainsdk.BlockchainProvidersResponse
import com.tangem.blockchainsdk.utils.createPrivateProviderType
import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.datasource.config.models.ProviderModel
import com.tangem.datasource.local.config.environment.models.ProviderModel
import com.tangem.utils.converter.Converter
import timber.log.Timber

View file

@ -12,7 +12,7 @@ import com.tangem.blockchainsdk.store.DefaultRuntimeStore
import com.tangem.core.featuretoggle.manager.FeatureTogglesManager
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.config.ConfigManager
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
@ -29,13 +29,13 @@ internal object BlockchainSDKFactoryModule {
@Singleton
fun provideBlockchainSDKFactory(
blockchainProvidersResponseLoader: BlockchainProvidersResponseLoader,
configManager: ConfigManager,
environmentConfigStorage: EnvironmentConfigStorage,
walletManagerFactoryCreator: WalletManagerFactoryCreator,
dispatchers: CoroutineDispatcherProvider,
): BlockchainSDKFactory {
return DefaultBlockchainSDKFactory(
blockchainProvidersResponseLoader = blockchainProvidersResponseLoader,
configManager = configManager,
environmentConfigStorage = environmentConfigStorage,
blockchainProviderTypesStore = DefaultRuntimeStore(defaultValue = emptyMap()),
walletManagerFactoryCreator = walletManagerFactoryCreator,
dispatchers = dispatchers,

View file

@ -6,7 +6,7 @@ import com.tangem.blockchainsdk.BlockchainProvidersResponse
import com.tangem.blockchainsdk.utils.createPrivateProviderType
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.config.models.ProviderModel
import com.tangem.datasource.local.config.environment.models.ProviderModel
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.runCatching
import timber.log.Timber

View file

@ -10,7 +10,7 @@ import com.tangem.blockchainsdk.BlockchainProvidersResponse
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.asset.reader.AssetReader
import com.tangem.datasource.config.models.ProviderModel
import com.tangem.datasource.local.config.environment.models.ProviderModel
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
import io.mockk.*
import kotlinx.coroutines.test.runTest