Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-03 14:13:39 +03:00
commit e963790304
437 changed files with 4080 additions and 12228 deletions

View file

@ -1,17 +1,13 @@
package com.tangem.blockchainsdk
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.BlockchainSdkConfig
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.blockchain.common.network.providers.ProviderType
import com.tangem.blockchainsdk.converters.BlockchainProviderTypesConverter
import com.tangem.blockchainsdk.converters.BlockchainSDKConfigConverter
import com.tangem.blockchainsdk.loader.BlockchainProvidersResponseLoader
import com.tangem.blockchainsdk.store.RuntimeStore
import com.tangem.datasource.asset.loader.AssetLoader
import com.tangem.datasource.config.models.ConfigValueModel
import com.tangem.datasource.config.models.ProviderModel
import com.tangem.libs.blockchain_sdk.BuildConfig
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.providers.models.ProviderModel
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
@ -25,18 +21,16 @@ internal typealias BlockchainProviderTypes = Map<Blockchain, List<ProviderType>>
/**
* Implementation of Blockchain SDK components factory
*
* @property assetLoader asset loader
* @property blockchainProvidersResponseLoader blockchain providers response loader
* @property configStore blockchain sdk config store
* @property environmentConfigStorage environment config storage
* @property blockchainProviderTypesStore blockchain provider types store
* @property walletManagerFactoryCreator wallet manager factory creator
*
[REDACTED_AUTHOR]
*/
internal class DefaultBlockchainSDKFactory(
private val assetLoader: AssetLoader,
private val blockchainProvidersResponseLoader: BlockchainProvidersResponseLoader,
private val configStore: RuntimeStore<BlockchainSdkConfig>,
private val environmentConfigStorage: EnvironmentConfigStorage,
private val blockchainProviderTypesStore: RuntimeStore<BlockchainProviderTypes>,
private val walletManagerFactoryCreator: WalletManagerFactoryCreator,
dispatchers: CoroutineDispatcherProvider,
@ -52,7 +46,6 @@ internal class DefaultBlockchainSDKFactory(
override suspend fun init() {
coroutineScope {
updateBlockchainSDKConfig()
updateBlockchainProviderTypes()
}
}
@ -61,7 +54,7 @@ internal class DefaultBlockchainSDKFactory(
private fun createWalletManagerFactory(): Flow<WalletManagerFactory?> {
return combine(
flow = configStore.get(),
flow = environmentConfigStorage.getConfig().map { it.blockchainSdkConfig },
flow2 = blockchainProviderTypesStore.get(),
// flow3 = subscribe on feature toggles changes, TODO: [REDACTED_JIRA]
transform = walletManagerFactoryCreator::create,
@ -69,23 +62,6 @@ internal class DefaultBlockchainSDKFactory(
.stateIn(scope = mainScope, started = SharingStarted.Eagerly, initialValue = null)
}
private fun CoroutineScope.updateBlockchainSDKConfig() {
launch {
val config = assetLoader.load<ConfigValueModel>(fileName = CONFIG_FILE_NAME)
if (config == null) {
Timber.e("Error loading BlockchainSDKConfig")
return@launch
}
Timber.i("Update BlockchainSDKConfig")
configStore.store(
value = BlockchainSDKConfigConverter.convert(value = config),
)
}
}
private fun CoroutineScope.updateBlockchainProviderTypes() {
launch {
val response = blockchainProvidersResponseLoader.load()
@ -102,8 +78,4 @@ internal class DefaultBlockchainSDKFactory(
)
}
}
private companion object {
const val CONFIG_FILE_NAME = "tangem-app-config/config_${BuildConfig.ENVIRONMENT}"
}
}

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.providers.models.ProviderModel
import com.tangem.utils.converter.Converter
import timber.log.Timber

View file

@ -1,93 +0,0 @@
package com.tangem.blockchainsdk.converters
import com.tangem.blockchain.common.*
import com.tangem.datasource.config.models.ConfigValueModel
import com.tangem.utils.converter.Converter
/**
* Converts [ConfigValueModel] to [BlockchainSdkConfig]
*
[REDACTED_AUTHOR]
*/
internal object BlockchainSDKConfigConverter : Converter<ConfigValueModel, BlockchainSdkConfig> {
override fun convert(value: ConfigValueModel): BlockchainSdkConfig {
return BlockchainSdkConfig(
blockchairCredentials = BlockchairCredentials(
apiKey = value.blockchairApiKeys,
authToken = value.blockchairAuthorizationToken,
),
blockcypherTokens = value.blockcypherTokens,
quickNodeSolanaCredentials = QuickNodeCredentials(
apiKey = value.quiknodeApiKey,
subdomain = value.quiknodeSubdomain,
),
quickNodeBscCredentials = QuickNodeCredentials(
apiKey = value.bscQuiknodeApiKey,
subdomain = value.bscQuiknodeSubdomain,
),
infuraProjectId = value.infuraProjectId,
tronGridApiKey = value.tronGridApiKey,
nowNodeCredentials = NowNodeCredentials(value.nowNodesApiKey),
getBlockCredentials = createGetBlockCredentials(value),
kaspaSecondaryApiUrl = value.kaspaSecondaryApiUrl,
tonCenterCredentials = TonCenterCredentials(
mainnetApiKey = value.tonCenterKeys.mainnet,
testnetApiKey = value.tonCenterKeys.testnet,
),
chiaFireAcademyApiKey = value.chiaFireAcademyApiKey,
chiaTangemApiKey = value.chiaTangemApiKey,
hederaArkhiaApiKey = value.hederaArkhiaKey,
polygonScanApiKey = value.polygonScanApiKey,
bittensorDwellirApiKey = value.bittensorDwellirApiKey,
bittensorOnfinalityApiKey = value.bittensorOnfinalityKey,
koinosProApiKey = value.koinosProApiKey,
)
}
private fun createGetBlockCredentials(configValues: ConfigValueModel): GetBlockCredentials? {
return configValues.getBlockAccessTokens?.let { accessTokens ->
GetBlockCredentials(
xrp = GetBlockAccessToken(jsonRpc = accessTokens.xrp?.jsonRPC),
cardano = GetBlockAccessToken(rosetta = accessTokens.cardano?.rosetta),
avalanche = GetBlockAccessToken(jsonRpc = accessTokens.avalanche?.jsonRPC),
eth = GetBlockAccessToken(jsonRpc = accessTokens.eth?.jsonRPC),
etc = GetBlockAccessToken(jsonRpc = accessTokens.etc?.jsonRPC),
fantom = GetBlockAccessToken(jsonRpc = accessTokens.fantom?.jsonRPC),
rsk = GetBlockAccessToken(jsonRpc = accessTokens.rsk?.jsonRPC),
bsc = GetBlockAccessToken(jsonRpc = accessTokens.bsc?.jsonRPC),
polygon = GetBlockAccessToken(jsonRpc = accessTokens.polygon?.jsonRPC),
gnosis = GetBlockAccessToken(jsonRpc = accessTokens.gnosis?.jsonRPC),
cronos = GetBlockAccessToken(jsonRpc = accessTokens.cronos?.jsonRPC),
solana = GetBlockAccessToken(jsonRpc = accessTokens.solana?.jsonRPC),
ton = GetBlockAccessToken(jsonRpc = accessTokens.ton?.jsonRPC),
tron = GetBlockAccessToken(rest = accessTokens.tron?.rest),
cosmos = GetBlockAccessToken(rest = accessTokens.cosmos?.rest),
near = GetBlockAccessToken(jsonRpc = accessTokens.near?.jsonRPC),
aptos = GetBlockAccessToken(rest = accessTokens.aptos?.rest),
dogecoin = GetBlockAccessToken(
jsonRpc = accessTokens.dogecoin?.jsonRPC,
blockBookRest = accessTokens.dogecoin?.blockBookRest,
),
litecoin = GetBlockAccessToken(
jsonRpc = accessTokens.litecoin?.jsonRPC,
blockBookRest = accessTokens.litecoin?.blockBookRest,
),
dash = GetBlockAccessToken(
jsonRpc = accessTokens.dash?.jsonRPC,
blockBookRest = accessTokens.dash?.blockBookRest,
),
bitcoin = GetBlockAccessToken(
jsonRpc = accessTokens.bitcoin?.jsonRPC,
blockBookRest = accessTokens.bitcoin?.blockBookRest,
),
algorand = GetBlockAccessToken(rest = accessTokens.algorand?.rest),
zkSyncEra = GetBlockAccessToken(jsonRpc = accessTokens.zksync?.jsonRPC),
polygonZkEvm = GetBlockAccessToken(jsonRpc = accessTokens.polygonZkevm?.jsonRPC),
base = GetBlockAccessToken(jsonRpc = accessTokens.base?.jsonRPC),
blast = GetBlockAccessToken(jsonRpc = accessTokens.blast?.jsonRPC),
filecoin = GetBlockAccessToken(jsonRpc = accessTokens.filecoin?.jsonRPC),
)
}
}
}

View file

@ -1,6 +1,5 @@
package com.tangem.blockchainsdk.di
import com.tangem.blockchain.common.BlockchainSdkConfig
import com.tangem.blockchain.common.logging.BlockchainSDKLogger
import com.tangem.blockchainsdk.BlockchainSDKFactory
import com.tangem.blockchainsdk.DefaultBlockchainSDKFactory
@ -13,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.asset.loader.AssetLoader
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,15 +28,14 @@ internal object BlockchainSDKFactoryModule {
@Provides
@Singleton
fun provideBlockchainSDKFactory(
assetLoader: AssetLoader,
blockchainProvidersResponseLoader: BlockchainProvidersResponseLoader,
environmentConfigStorage: EnvironmentConfigStorage,
walletManagerFactoryCreator: WalletManagerFactoryCreator,
dispatchers: CoroutineDispatcherProvider,
): BlockchainSDKFactory {
return DefaultBlockchainSDKFactory(
assetLoader = assetLoader,
blockchainProvidersResponseLoader = blockchainProvidersResponseLoader,
configStore = DefaultRuntimeStore(defaultValue = BlockchainSdkConfig()),
environmentConfigStorage = environmentConfigStorage,
blockchainProviderTypesStore = DefaultRuntimeStore(defaultValue = emptyMap()),
walletManagerFactoryCreator = walletManagerFactoryCreator,
dispatchers = dispatchers,

View file

@ -5,8 +5,8 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
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.providers.BlockchainProvidersStorage
import com.tangem.datasource.local.config.providers.models.ProviderModel
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.runCatching
import timber.log.Timber
@ -16,16 +16,16 @@ import javax.inject.Singleton
/**
* Loader of [BlockchainProvidersResponse]
*
* @property tangemTechServiceApi tangem tech api
* @property assetLoader asset loader for local config loading
* @property dispatchers dispatchers
* @property tangemTechServiceApi tangem tech api
* @property blockchainProvidersStorage blockchain providers storage
* @property dispatchers dispatchers
*
[REDACTED_AUTHOR]
*/
@Singleton
internal class BlockchainProvidersResponseLoader @Inject constructor(
private val tangemTechServiceApi: TangemTechApi,
private val assetLoader: AssetLoader,
private val blockchainProvidersStorage: BlockchainProvidersStorage,
private val dispatchers: CoroutineDispatcherProvider,
) {
@ -33,7 +33,7 @@ internal class BlockchainProvidersResponseLoader @Inject constructor(
/** Load [BlockchainProvidersResponse] */
suspend fun load(): BlockchainProvidersResponse? {
val localResponse = loadLocal() ?: return null
val localResponse = loadLocal().ifEmpty { return null }
return runCatching(dispatcher = dispatchers.io, block = ::loadRemote)
.fold(
@ -45,9 +45,7 @@ internal class BlockchainProvidersResponseLoader @Inject constructor(
)
}
private suspend fun loadLocal(): BlockchainProvidersResponse? {
return assetLoader.load<BlockchainProvidersResponse>(fileName = PROVIDER_TYPES_FILE_NAME)
}
private suspend fun loadLocal(): BlockchainProvidersResponse = blockchainProvidersStorage.getConfigSync()
private suspend fun loadRemote() = tangemTechServiceApi.getBlockchainProviders()
@ -140,8 +138,6 @@ internal class BlockchainProvidersResponseLoader @Inject constructor(
}
private companion object {
const val PROVIDER_TYPES_FILE_NAME = "tangem-app-config/providers_order"
val forbiddenSchemes = listOf("wss://")
}
}

View file

@ -128,6 +128,12 @@ fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain? {
"internet-computer" -> Blockchain.InternetComputer
"sui" -> Blockchain.Sui
"sui/test" -> Blockchain.SuiTestnet
"energy-web-chain" -> Blockchain.EnergyWebChain
"energy-web-chain/test" -> Blockchain.EnergyWebChainTestnet
"energy-web-x" -> Blockchain.EnergyWebX
"energy-web-x/test" -> Blockchain.EnergyWebXTestnet
"add_later" -> Blockchain.Casper
"add_later_test" -> Blockchain.CasperTestnet
else -> null
}
}
@ -257,6 +263,12 @@ fun Blockchain.toNetworkId(): String {
Blockchain.InternetComputer -> "internet-computer"
Blockchain.Sui -> "sui"
Blockchain.SuiTestnet -> "sui/test"
Blockchain.EnergyWebChain -> "energy-web-chain"
Blockchain.EnergyWebChainTestnet -> "energy-web-chain/test"
Blockchain.EnergyWebX -> "energy-web-x"
Blockchain.EnergyWebXTestnet -> "energy-web-x/test"
Blockchain.Casper -> "add_later"
Blockchain.CasperTestnet -> "add_later_test"
}
}
@ -342,6 +354,10 @@ fun Blockchain.toCoinId(): String {
Blockchain.Sei, Blockchain.SeiTestnet -> "sei-network"
Blockchain.InternetComputer -> "internet-computer"
Blockchain.Sui, Blockchain.SuiTestnet -> "sui"
Blockchain.EnergyWebChain, Blockchain.EnergyWebChainTestnet -> "energy-web-token"
Blockchain.EnergyWebX, Blockchain.EnergyWebXTestnet -> "energy-web-token"
Blockchain.Casper -> "add_later"
Blockchain.CasperTestnet -> "add_later_test"
}
}
@ -368,6 +384,7 @@ fun Blockchain.minimalAmount(): BigDecimal {
private const val NODL = "NODL"
private const val NODL_AMOUNT_TO_CREATE_ACCOUNT = 1.5
// no need to add testnets
private val excludedBlockchains = listOf(
Blockchain.Unknown,
Blockchain.Nexa,