Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-25 16:39:35 +03:00
commit bfd903b43c
595 changed files with 12755 additions and 19837 deletions

View file

@ -1,11 +1,10 @@
package com.tangem.datasource.api.common.config
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.utils.ProviderSuspend
import kotlinx.coroutines.flow.first
internal class BlockAid(
private val configStorage: EnvironmentConfigStorage,
private val environmentConfig: EnvironmentConfig,
) : ApiConfig() {
override val defaultEnvironment: ApiEnvironment = ApiEnvironment.PROD
@ -21,9 +20,7 @@ internal class BlockAid(
put(
key = "X-API-KEY",
value = ProviderSuspend {
requireNotNull(
configStorage.getConfig().first { !it.blockAidApiKey.isNullOrEmpty() }.blockAidApiKey,
)
requireNotNull(environmentConfig.blockAidApiKey)
},
)
put("accept", ProviderSuspend { "application/json" })

View file

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

View file

@ -1,13 +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.datasource.local.config.environment.EnvironmentConfig
import com.tangem.utils.ProviderSuspend
import com.tangem.utils.version.AppVersionProvider
internal sealed class TangemPay(
private val environmentConfig: EnvironmentConfig,
private val appVersionProvider: AppVersionProvider,
private val environmentConfigStorage: EnvironmentConfigStorage,
) : ApiConfig() {
override val defaultEnvironment: ApiEnvironment = getInitialEnvironment()
@ -61,8 +61,8 @@ internal sealed class TangemPay(
return when (apiEnvironment) {
ApiEnvironment.MOCK,
ApiEnvironment.DEV,
-> environmentConfigStorage.getConfigSync().bffStaticTokenDev
ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().bffStaticToken
-> environmentConfig.bffStaticTokenDev
ApiEnvironment.PROD -> environmentConfig.bffStaticToken
ApiEnvironment.STAGE,
ApiEnvironment.STAGE_2,
ApiEnvironment.DEV_2,
@ -72,9 +72,9 @@ internal sealed class TangemPay(
}
class Bff(
environmentConfig: EnvironmentConfig,
appVersionProvider: AppVersionProvider,
environmentConfigStorage: EnvironmentConfigStorage,
) : TangemPay(appVersionProvider, environmentConfigStorage) {
) : TangemPay(environmentConfig, appVersionProvider) {
override fun getBaseUrl(apiEnvironment: ApiEnvironment): String {
return when (apiEnvironment) {
ApiEnvironment.DEV -> "https://api.dev.us.paera.com/bff-v2/"
@ -90,9 +90,9 @@ internal sealed class TangemPay(
}
class Auth(
environmentConfig: EnvironmentConfig,
appVersionProvider: AppVersionProvider,
environmentConfigStorage: EnvironmentConfigStorage,
) : TangemPay(appVersionProvider, environmentConfigStorage) {
) : TangemPay(environmentConfig, appVersionProvider) {
override fun getBaseUrl(apiEnvironment: ApiEnvironment): String {
return when (apiEnvironment) {
ApiEnvironment.DEV -> "https://api.dev.us.paera.com/"

View file

@ -2,7 +2,7 @@ package com.tangem.datasource.api.common.config
import com.tangem.datasource.BuildConfig
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.datasource.utils.RequestHeader
import com.tangem.utils.ProviderSuspend
import com.tangem.utils.info.AppInfoProvider
@ -10,7 +10,7 @@ import com.tangem.utils.version.AppVersionProvider
/** YieldSupply [ApiConfig] */
internal class YieldSupply(
private val environmentConfigStorage: EnvironmentConfigStorage,
private val environmentConfig: EnvironmentConfig,
private val appVersionProvider: AppVersionProvider,
private val authProvider: AuthProvider,
private val appInfoProvider: AppInfoProvider,
@ -78,8 +78,8 @@ internal class YieldSupply(
ApiEnvironment.DEV_3,
ApiEnvironment.STAGE,
ApiEnvironment.STAGE_2,
-> environmentConfigStorage.getConfigSync().yieldModuleApiKeyDev
ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().yieldModuleApiKey
-> environmentConfig.yieldModuleApiKeyDev
ApiEnvironment.PROD -> environmentConfig.yieldModuleApiKey
} ?: error("No tangem tech api config provided")
}
}

View file

@ -12,7 +12,7 @@ data class OrderResponse(
@Json(name = "id") val id: String,
@Json(name = "customer_id") val customerId: String?,
@Json(name = "type") val type: String?,
@Json(name = "status") val status: String,
@Json(name = "status") val status: Status,
@Json(name = "step") val step: String?,
@Json(name = "data") val data: Data,
@Json(name = "step_change_code") val stepChangeCode: Int?,
@ -29,5 +29,20 @@ data class OrderResponse(
@Json(name = "payment_account_id") val paymentAccountId: String?,
@Json(name = "transaction_hash") val transactionHash: String?,
)
@JsonClass(generateAdapter = false)
enum class Status {
@Json(name = "NEW")
NEW,
@Json(name = "PROCESSING")
PROCESSING,
@Json(name = "COMPLETED")
COMPLETED,
@Json(name = "CANCELED")
CANCELED,
}
}
}

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.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.EnvironmentConfig
internal class Sha256SignatureVerifier(
private val environmentConfigStorage: EnvironmentConfigStorage,
private val environmentConfig: EnvironmentConfig,
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 -> environmentConfigStorage.getConfigSync().express?.signVerifierPublicKey
else -> environmentConfigStorage.getConfigSync().devExpress?.signVerifierPublicKey
ApiEnvironment.PROD -> environmentConfig.express?.signVerifierPublicKey
else -> environmentConfig.devExpress?.signVerifierPublicKey
}
}
}

View file

@ -2,7 +2,7 @@ package com.tangem.datasource.di
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.api.common.config.*
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.lib.auth.ExpressAuthProvider
import com.tangem.lib.auth.P2PEthPoolAuthProvider
import com.tangem.lib.auth.StakeKitAuthProvider
@ -21,13 +21,13 @@ internal object ApiConfigsModule {
@Provides
@IntoSet
fun provideExpressConfig(
environmentConfigStorage: EnvironmentConfigStorage,
environmentConfig: EnvironmentConfig,
expressAuthProvider: ExpressAuthProvider,
appVersionProvider: AppVersionProvider,
appInfoProvider: AppInfoProvider,
): ApiConfig {
return Express(
environmentConfigStorage = environmentConfigStorage,
environmentConfig = environmentConfig,
expressAuthProvider = expressAuthProvider,
appVersionProvider = appVersionProvider,
appInfoProvider = appInfoProvider,
@ -73,12 +73,12 @@ internal object ApiConfigsModule {
@Provides
@IntoSet
fun provideYieldSupplyConfig(
environmentConfigStorage: EnvironmentConfigStorage,
environmentConfig: EnvironmentConfig,
appVersionProvider: AppVersionProvider,
authProvider: AuthProvider,
appInfoProvider: AppInfoProvider,
): ApiConfig = YieldSupply(
environmentConfigStorage = environmentConfigStorage,
environmentConfig = environmentConfig,
appVersionProvider = appVersionProvider,
authProvider = authProvider,
appInfoProvider = appInfoProvider,
@ -87,21 +87,21 @@ internal object ApiConfigsModule {
@Provides
@IntoSet
fun provideTangemPayBffConfig(
environmentConfig: EnvironmentConfig,
appVersionProvider: AppVersionProvider,
environmentConfigStorage: EnvironmentConfigStorage,
): ApiConfig = TangemPay.Bff(appVersionProvider, environmentConfigStorage)
): ApiConfig = TangemPay.Bff(environmentConfig, appVersionProvider)
@Provides
@IntoSet
fun provideTangemPayAuthConfig(
environmentConfig: EnvironmentConfig,
appVersionProvider: AppVersionProvider,
environmentConfigStorage: EnvironmentConfigStorage,
): ApiConfig = TangemPay.Auth(appVersionProvider, environmentConfigStorage)
): ApiConfig = TangemPay.Auth(environmentConfig, appVersionProvider)
@Provides
@IntoSet
fun provideBlockAidConfig(environmentConfigStorage: EnvironmentConfigStorage): ApiConfig {
return BlockAid(environmentConfigStorage)
fun provideBlockAidConfig(environmentConfig: EnvironmentConfig): ApiConfig {
return BlockAid(environmentConfig)
}
@Provides

View file

@ -9,6 +9,7 @@ import com.tangem.common.json.MoshiJsonConverter
import com.tangem.datasource.api.common.adapter.*
import com.tangem.datasource.local.config.providers.models.ProviderModel
import com.tangem.datasource.local.network.entity.NetworkStatusDM
import com.tangem.datasource.local.visa.entity.PaymentAccountStatusDM
import com.tangem.datasource.utils.SerializeNullsFactory
import com.tangem.domain.models.scan.serialization.*
import dagger.Module
@ -45,6 +46,15 @@ class MoshiModule {
.withSubtype(NetworkStatusDM.Verified::class.java, "amounts")
.withSubtype(NetworkStatusDM.NoAccount::class.java, "amount_to_create_account"),
)
.add(
NamePolymorphicAdapterFactory.of(PaymentAccountStatusDM::class.java)
.withSubtype(PaymentAccountStatusDM.NotCreated::class.java, "not_created")
.withSubtype(PaymentAccountStatusDM.UnderReview::class.java, "kyc_status")
.withSubtype(PaymentAccountStatusDM.IssuingCard::class.java, "issuing_card")
.withSubtype(PaymentAccountStatusDM.Locked::class.java, "locked")
.withSubtype(PaymentAccountStatusDM.Loaded::class.java, "balance")
.withSubtype(PaymentAccountStatusDM.CardIssueFailed::class.java, "card_issue_failed"),
)
.add(
PolymorphicJsonAdapterFactory.of(NFTCollection.Identifier::class.java, "bc")
.withSubtype(NFTCollection.Identifier.EVM::class.java, "evm")

View file

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

View file

@ -1,9 +1,8 @@
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.environment.converter.GeneratedEnvironmentConfigConverter
import com.tangem.datasource.local.config.issuers.DefaultIssuersConfigStorage
import com.tangem.datasource.local.config.issuers.IssuersConfigStorage
import com.tangem.datasource.local.config.providers.BlockchainProvidersStorage
@ -23,11 +22,8 @@ internal object ConfigModule {
@Provides
@Singleton
fun provideEnvironmentConfigStorage(assetLoader: AssetLoader): EnvironmentConfigStorage {
return DefaultEnvironmentConfigStorage(
assetLoader = assetLoader,
environmentConfigStore = RuntimeStateStore(defaultValue = EnvironmentConfig()),
)
fun provideEnvironmentConfig(): EnvironmentConfig {
return GeneratedEnvironmentConfigConverter.convert()
}
@Provides

View file

@ -1,41 +0,0 @@
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,20 +0,0 @@
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

@ -0,0 +1,181 @@
package com.tangem.datasource.local.config.environment.converter
import com.tangem.blockchain.common.*
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.datasource.local.config.environment.generated.GeneratedEnvironmentConfig
import com.tangem.datasource.local.config.environment.generated.GeneratedEnvironmentConfig.AppsFlyer
import com.tangem.datasource.local.config.environment.generated.GeneratedEnvironmentConfig.DevExpress
import com.tangem.datasource.local.config.environment.generated.GeneratedEnvironmentConfig.Express
import com.tangem.datasource.local.config.environment.generated.GeneratedEnvironmentConfig.GetBlockAccessTokens
import com.tangem.datasource.local.config.environment.generated.GeneratedEnvironmentConfig.P2pApiKey
import com.tangem.datasource.local.config.environment.generated.GeneratedEnvironmentConfig.TonCenterApiKey
import com.tangem.datasource.local.config.environment.models.ExpressModel
import com.tangem.datasource.local.config.environment.models.P2PKeys
/**
* Converts [GeneratedEnvironmentConfig] to [EnvironmentConfig]
*
* This converter maps the auto-generated config (from JSON) to the domain model.
* The generated config has nested objects that mirror the JSON structure.
*/
internal object GeneratedEnvironmentConfigConverter {
fun convert(): EnvironmentConfig {
return EnvironmentConfig(
moonPayApiKey = GeneratedEnvironmentConfig.moonPayApiKey,
moonPayApiSecretKey = GeneratedEnvironmentConfig.moonPayApiSecretKey,
mercuryoWidgetId = GeneratedEnvironmentConfig.mercuryoWidgetId,
mercuryoSecret = GeneratedEnvironmentConfig.mercuryoSecret,
blockchainSdkConfig = createBlockchainSdkConfig(),
amplitudeApiKey = GeneratedEnvironmentConfig.amplitudeApiKey,
appsFlyerApiKey = AppsFlyer.appsFlyerDevKey,
appsAppId = AppsFlyer.appsFlyerAppID,
walletConnectProjectId = GeneratedEnvironmentConfig.walletConnectProjectId,
express = createExpressModel(
apiKey = Express.apiKey,
signVerifierPublicKey = Express.signVerifierPublicKey,
),
devExpress = createExpressModel(
apiKey = DevExpress.apiKey,
signVerifierPublicKey = DevExpress.signVerifierPublicKey,
),
stakeKitApiKey = GeneratedEnvironmentConfig.stakeKitApiKey,
p2pApiKey = createP2PKeys(),
blockAidApiKey = GeneratedEnvironmentConfig.blockaidApiKey,
tangemApiKey = GeneratedEnvironmentConfig.tangemApiKey,
tangemApiKeyDev = GeneratedEnvironmentConfig.tangemApiKeyDev,
tangemApiKeyStage = GeneratedEnvironmentConfig.tangemApiKeyStage,
yieldModuleApiKey = GeneratedEnvironmentConfig.yieldModuleApiKey,
yieldModuleApiKeyDev = GeneratedEnvironmentConfig.yieldModuleApiKeyDev,
bffStaticToken = GeneratedEnvironmentConfig.bffStaticToken,
bffStaticTokenDev = GeneratedEnvironmentConfig.bffStaticTokenDev,
gaslessTxApiKeyDev = GeneratedEnvironmentConfig.gaslessTxApiKeyDev,
gaslessTxApiKey = GeneratedEnvironmentConfig.gaslessTxApiKey,
)
}
private fun createExpressModel(apiKey: String?, signVerifierPublicKey: String?): ExpressModel? {
return if (!apiKey.isNullOrEmpty() && !signVerifierPublicKey.isNullOrEmpty()) {
ExpressModel(apiKey = apiKey, signVerifierPublicKey = signVerifierPublicKey)
} else {
null
}
}
private fun createP2PKeys(): P2PKeys? {
val mainnet = P2pApiKey.mainnet
val hoodi = P2pApiKey.hoodi
return if (mainnet.isNotEmpty() && hoodi.isNotEmpty()) {
P2PKeys(mainnet = mainnet, hoodi = hoodi)
} else {
null
}
}
private fun createBlockchainSdkConfig(): BlockchainSdkConfig {
return BlockchainSdkConfig(
blockchairCredentials = BlockchairCredentials(
apiKey = GeneratedEnvironmentConfig.blockchairApiKeys,
authToken = GeneratedEnvironmentConfig.blockchairAuthorizationToken,
),
blockcypherTokens = GeneratedEnvironmentConfig.blockcypherTokens.toSet(),
quickNodeSolanaCredentials = QuickNodeCredentials(
apiKey = GeneratedEnvironmentConfig.quiknodeApiKey,
subdomain = GeneratedEnvironmentConfig.quiknodeSubdomain,
),
quickNodeBscCredentials = QuickNodeCredentials(
apiKey = GeneratedEnvironmentConfig.bscQuiknodeApiKey,
subdomain = GeneratedEnvironmentConfig.bscQuiknodeSubdomain,
),
quickNodePlasmaCredentials = QuickNodeCredentials(
apiKey = GeneratedEnvironmentConfig.quiknodePlasmaApiKey,
subdomain = GeneratedEnvironmentConfig.quiknodePlasmaSubdomain,
),
quickNodeMonadCredentials = QuickNodeCredentials(
apiKey = GeneratedEnvironmentConfig.quiknodeMonadApiKey,
subdomain = GeneratedEnvironmentConfig.quiknodeMonadSubdomain,
),
infuraProjectId = GeneratedEnvironmentConfig.infuraProjectId,
tronGridApiKey = GeneratedEnvironmentConfig.tronGridApiKey,
nowNodeCredentials = NowNodeCredentials(apiKey = GeneratedEnvironmentConfig.nowNodesApiKey),
getBlockCredentials = createGetBlockCredentials(),
kaspaSecondaryApiUrl = GeneratedEnvironmentConfig.kaspaSecondaryApiUrl,
tonCenterCredentials = TonCenterCredentials(
mainnetApiKey = TonCenterApiKey.mainnet,
testnetApiKey = TonCenterApiKey.testnet,
),
chiaFireAcademyApiKey = GeneratedEnvironmentConfig.chiaFireAcademyApiKey,
chiaTangemApiKey = GeneratedEnvironmentConfig.chiaTangemApiKey,
hederaArkhiaApiKey = GeneratedEnvironmentConfig.hederaArkhiaKey,
polygonScanApiKey = GeneratedEnvironmentConfig.polygonScanApiKey,
bittensorDwellirApiKey = GeneratedEnvironmentConfig.bittensorDwellirKey,
bittensorOnfinalityApiKey = GeneratedEnvironmentConfig.bittensorOnfinalityKey,
dwellirApiKey = GeneratedEnvironmentConfig.dwellirApiKey,
koinosProApiKey = GeneratedEnvironmentConfig.koinosProApiKey,
alephiumApiKey = GeneratedEnvironmentConfig.alephiumTangemApiKey,
moralisApiKey = GeneratedEnvironmentConfig.moralisApiKey,
etherscanApiKey = GeneratedEnvironmentConfig.etherscanApiKey,
blinkApiKey = GeneratedEnvironmentConfig.blinkApiKey,
tatumApiKey = GeneratedEnvironmentConfig.tatumApiKey,
)
}
private fun createGetBlockCredentials(): GetBlockCredentials {
return GetBlockCredentials(
xrp = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Xrp.jsonRpc),
cardano = GetBlockAccessToken(rosetta = GetBlockAccessTokens.Cardano.rosetta),
avalanche = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Avalanche.jsonRpc),
eth = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Ethereum.jsonRpc),
etc = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.EthereumClassic.jsonRpc),
fantom = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Fantom.jsonRpc),
rsk = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Rsk.jsonRpc),
bsc = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Bsc.jsonRpc),
polygon = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Polygon.jsonRpc),
gnosis = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Xdai.jsonRpc),
cronos = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Cronos.jsonRpc),
solana = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Solana.jsonRpc),
ton = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Ton.jsonRpc),
tron = GetBlockAccessToken(rest = GetBlockAccessTokens.Tron.rest),
cosmos = GetBlockAccessToken(rest = GetBlockAccessTokens.CosmosHub.rest),
near = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Near.jsonRpc),
aptos = GetBlockAccessToken(rest = GetBlockAccessTokens.Aptos.rest),
dogecoin = GetBlockAccessToken(
jsonRpc = GetBlockAccessTokens.Dogecoin.jsonRpc,
blockBookRest = GetBlockAccessTokens.Dogecoin.blockBookRest,
),
litecoin = GetBlockAccessToken(
jsonRpc = GetBlockAccessTokens.Litecoin.jsonRpc,
blockBookRest = GetBlockAccessTokens.Litecoin.blockBookRest,
),
dash = GetBlockAccessToken(
jsonRpc = GetBlockAccessTokens.Dash.jsonRpc,
blockBookRest = GetBlockAccessTokens.Dash.blockBookRest,
),
bitcoin = GetBlockAccessToken(
jsonRpc = GetBlockAccessTokens.Bitcoin.jsonRpc,
blockBookRest = GetBlockAccessTokens.Bitcoin.blockBookRest,
),
algorand = GetBlockAccessToken(rest = GetBlockAccessTokens.Algorand.rest),
zkSyncEra = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Zksync.jsonRpc),
polygonZkEvm = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.PolygonZkevm.jsonRpc),
base = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Base.jsonRpc),
blast = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Blast.jsonRpc),
filecoin = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Filecoin.jsonRpc),
arbitrum = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.ArbitrumOne.jsonRpc),
bitcoinCash = GetBlockAccessToken(
jsonRpc = GetBlockAccessTokens.BitcoinCash.jsonRpc,
blockBookRest = GetBlockAccessTokens.BitcoinCash.blockBookRest,
),
kusama = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Kusama.jsonRpc),
moonbeam = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Moonbeam.jsonRpc),
optimism = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Optimism.jsonRpc),
polkadot = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Polkadot.jsonRpc),
shibarium = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Shibarium.jsonRpc),
sui = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Sui.jsonRpc),
telos = GetBlockAccessToken(jsonRpc = GetBlockAccessTokens.Telos.jsonRpc),
tezos = GetBlockAccessToken(rest = GetBlockAccessTokens.Tezos.rest),
monad = GetBlockAccessToken(rest = GetBlockAccessTokens.Monad.rest),
stellar = GetBlockAccessToken(rest = GetBlockAccessTokens.Stellar.rest),
)
}
}

View file

@ -0,0 +1,53 @@
@file:Suppress("BooleanPropertyNaming")
package com.tangem.datasource.local.visa.entity
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.tangem.domain.models.kyc.KycStatus
import dev.onenowy.moshipolymorphicadapter.PolymorphicAdapterType
import dev.onenowy.moshipolymorphicadapter.annotations.NameLabel
import java.math.BigDecimal
/**
* Payment account status for storage in the local cache.
*
* @see [com.tangem.domain.pay.PaymentAccountStatus]
*/
@JsonClass(generateAdapter = true, generator = PolymorphicAdapterType.NAME_POLYMORPHIC_ADAPTER)
sealed interface PaymentAccountStatusDM {
@NameLabel("not_created")
data class NotCreated(
@Json(name = "not_created") val marker: Boolean = true,
) : PaymentAccountStatusDM
@NameLabel("kyc_status")
data class UnderReview(
@Json(name = "kyc_status") val kycStatus: KycStatus,
) : PaymentAccountStatusDM
@NameLabel("issuing_card")
data class IssuingCard(
@Json(name = "issuing_card") val marker: Boolean = true,
) : PaymentAccountStatusDM
@NameLabel("locked")
data class Locked(
@Json(name = "locked") val marker: Boolean = true,
) : PaymentAccountStatusDM
@NameLabel("balance")
data class Loaded(
@Json(name = "card_id") val cardId: String,
@Json(name = "last_four_digits") val lastFourDigits: String,
@Json(name = "balance") val balance: BigDecimal,
@Json(name = "currency_code") val currencyCode: String,
@Json(name = "deposit_address") val depositAddress: String?,
@Json(name = "is_pin_set") val isPinSet: Boolean,
) : PaymentAccountStatusDM
@NameLabel("card_issue_failed")
data class CardIssueFailed(
@Json(name = "card_issue_failed") val marker: Boolean = true,
) : PaymentAccountStatusDM
}

View file

@ -2,6 +2,7 @@ package com.tangem.datasource.api.common.config
import com.google.common.truth.Truth
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.utils.ProviderSuspend
import io.mockk.clearMocks
import io.mockk.every
@ -19,6 +20,7 @@ class ApiConfigTest {
private val appAuthProvider = mockk<AuthProvider>()
private val apiKeyProvider = mockk<ProviderSuspend<String>>()
private val environmentConfig = mockk<EnvironmentConfig>()
@BeforeEach
fun setup() {
@ -47,7 +49,7 @@ class ApiConfigTest {
when (it) {
ApiConfig.ID.Express -> {
Express(
environmentConfigStorage = mockk(),
environmentConfig = environmentConfig,
expressAuthProvider = mockk(),
appVersionProvider = mockk(),
appInfoProvider = mockk(),
@ -55,7 +57,7 @@ class ApiConfigTest {
}
ApiConfig.ID.YieldSupply -> {
YieldSupply(
environmentConfigStorage = mockk(),
environmentConfig = environmentConfig,
appVersionProvider = mockk(),
authProvider = appAuthProvider,
appInfoProvider = mockk(),
@ -70,14 +72,14 @@ class ApiConfigTest {
}
ApiConfig.ID.StakeKit -> StakeKit(stakeKitAuthProvider = mockk())
ApiConfig.ID.TangemPay -> TangemPay.Bff(
environmentConfig = environmentConfig,
appVersionProvider = mockk(),
environmentConfigStorage = mockk()
)
ApiConfig.ID.TangemPayAuth -> TangemPay.Auth(
environmentConfig = environmentConfig,
appVersionProvider = mockk(),
environmentConfigStorage = mockk()
)
ApiConfig.ID.BlockAid -> BlockAid(configStorage = mockk())
ApiConfig.ID.BlockAid -> BlockAid(environmentConfig = environmentConfig)
ApiConfig.ID.MoonPay -> MoonPay()
ApiConfig.ID.P2PEthPool -> P2PEthPool(p2pAuthProvider = mockk())
ApiConfig.ID.News -> News(

View file

@ -1,45 +0,0 @@
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"),
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,
)
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"
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"
const val YIELD_MODULE_KEY_DEV = "yield_module_api_key_dev"
}
}

View file

@ -10,10 +10,8 @@ import com.tangem.datasource.api.common.config.ApiConfig.Companion.EXTERNAL_BUIL
import com.tangem.datasource.api.common.config.ApiConfig.Companion.INTERNAL_BUILD_TYPE
import com.tangem.datasource.api.common.config.ApiConfig.Companion.MOCKED_BUILD_TYPE
import com.tangem.datasource.api.common.config.ApiConfig.Companion.RELEASE_BUILD_TYPE
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.datasource.local.config.environment.EnvironmentConfig
import com.tangem.datasource.local.config.environment.models.ExpressModel
import com.tangem.domain.staking.model.ethpool.P2PEthPoolStakingConfig
import com.tangem.lib.auth.ExpressAuthProvider
import com.tangem.lib.auth.P2PEthPoolAuthProvider
@ -39,7 +37,7 @@ import java.util.TimeZone
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
internal class ProdApiConfigsManagerTest {
private val environmentConfigStorage = MockEnvironmentConfigStorage()
private val environmentConfig = createMockEnvironmentConfig()
private val appVersionProvider = mockk<AppVersionProvider>()
private val expressAuthProvider = mockk<ExpressAuthProvider>()
private val stakeKitAuthProvider = mockk<StakeKitAuthProvider>()
@ -94,7 +92,7 @@ internal class ProdApiConfigsManagerTest {
when (it) {
ApiConfig.ID.Express -> {
Express(
environmentConfigStorage = environmentConfigStorage,
environmentConfig = environmentConfig,
expressAuthProvider = expressAuthProvider,
appVersionProvider = appVersionProvider,
appInfoProvider = appInfoProvider,
@ -102,7 +100,7 @@ internal class ProdApiConfigsManagerTest {
}
ApiConfig.ID.YieldSupply -> {
YieldSupply(
environmentConfigStorage = environmentConfigStorage,
environmentConfig = environmentConfig,
appVersionProvider = appVersionProvider,
authProvider = appAuthProvider,
appInfoProvider = appInfoProvider,
@ -117,14 +115,14 @@ internal class ProdApiConfigsManagerTest {
}
ApiConfig.ID.StakeKit -> StakeKit(stakeKitAuthProvider = stakeKitAuthProvider)
ApiConfig.ID.TangemPay -> TangemPay.Bff(
environmentConfig = environmentConfig,
appVersionProvider = appVersionProvider,
environmentConfigStorage = environmentConfigStorage,
)
ApiConfig.ID.TangemPayAuth -> TangemPay.Auth(
environmentConfig = environmentConfig,
appVersionProvider = appVersionProvider,
environmentConfigStorage = environmentConfigStorage,
)
ApiConfig.ID.BlockAid -> BlockAid(configStorage = environmentConfigStorage)
ApiConfig.ID.BlockAid -> BlockAid(environmentConfig = environmentConfig)
ApiConfig.ID.MoonPay -> MoonPay()
ApiConfig.ID.P2PEthPool -> P2PEthPool(p2pAuthProvider = p2pEthPoolAuthProvider)
ApiConfig.ID.News -> News(
@ -188,9 +186,9 @@ internal class ProdApiConfigsManagerTest {
headers = mapOf(
"api-key" to ProviderSuspend {
if (environment == ApiEnvironment.PROD) {
MockEnvironmentConfigStorage.EXPRESS_API_KEY
EXPRESS_API_KEY
} else {
MockEnvironmentConfigStorage.EXPRESS_DEV_API_KEY
EXPRESS_DEV_API_KEY
}
},
"session-id" to ProviderSuspend { EXPRESS_SESSION_ID },
@ -237,7 +235,7 @@ internal class ProdApiConfigsManagerTest {
environment = ApiEnvironment.PROD,
baseUrl = "https://yield.tangem.org/",
headers = mapOf(
"api-key" to ProviderSuspend { MockEnvironmentConfigStorage.YIELD_MODULE_KEY },
"api-key" to ProviderSuspend { YIELD_MODULE_KEY },
"card_id" to ProviderSuspend { APP_CARD_ID },
"card_public_key" to ProviderSuspend { APP_CARD_PUBLIC_KEY },
"version" to ProviderSuspend { VERSION_NAME },
@ -426,5 +424,48 @@ internal class ProdApiConfigsManagerTest {
const val P2P_API_KEY = "p2p_api_key"
const val APP_CARD_ID = "app_card_id"
const val APP_CARD_PUBLIC_KEY = "Bearer app_public_key"
// Mock config values
const val TANGEM_API_KEY = "tangem_api_key"
const val TANGEM_GASLESS_API_KEY = "tangem_gasless_api_key"
const val TANGEM_PAY_BFF_KEY_DEV = "tangem_pay_bff_key_dev"
const val BLOCK_AID_API_KEY = "block_aid_api_key"
const val EXPRESS_API_KEY = "express_api_key"
const val EXPRESS_DEV_API_KEY = "express_dev_api_key"
const val YIELD_MODULE_KEY = "yield_module_key"
fun createMockEnvironmentConfig(): EnvironmentConfig {
return EnvironmentConfig(
moonPayApiKey = "moon_pay_api_key",
moonPayApiSecretKey = "moon_pay_secret_key",
mercuryoWidgetId = "mercuryo_widget_id",
mercuryoSecret = "mercuryo_secret",
blockchainSdkConfig = mockk(relaxed = true),
amplitudeApiKey = "amplitude_api_key",
appsFlyerApiKey = "appsflyer_api_key",
appsAppId = "apps_app_id",
walletConnectProjectId = "wallet_connect_project_id",
express = ExpressModel(
apiKey = EXPRESS_API_KEY,
signVerifierPublicKey = "express_public_key",
),
devExpress = ExpressModel(
apiKey = EXPRESS_DEV_API_KEY,
signVerifierPublicKey = "express_dev_public_key",
),
stakeKitApiKey = STAKE_KIT_API_KEY,
p2pApiKey = null,
blockAidApiKey = BLOCK_AID_API_KEY,
tangemApiKey = TANGEM_API_KEY,
tangemApiKeyDev = TANGEM_API_KEY,
tangemApiKeyStage = TANGEM_API_KEY,
yieldModuleApiKey = YIELD_MODULE_KEY,
yieldModuleApiKeyDev = YIELD_MODULE_KEY,
bffStaticToken = TANGEM_PAY_BFF_KEY_DEV,
bffStaticTokenDev = TANGEM_PAY_BFF_KEY_DEV,
gaslessTxApiKeyDev = TANGEM_GASLESS_API_KEY,
gaslessTxApiKey = TANGEM_GASLESS_API_KEY,
)
}
}
}