Updated on 2026-08-14

This commit is contained in:
Tangem 2025-01-09 20:37:33 +03:00
commit 8e42589a00
456 changed files with 6580 additions and 3738 deletions

View file

@ -24,6 +24,7 @@ sealed class ApiConfig {
Express,
TangemTech,
StakeKit,
TangemVisaAuth,
}
private fun initializeId(): ID {
@ -31,6 +32,7 @@ sealed class ApiConfig {
is Express -> ID.Express
is TangemTech -> ID.TangemTech
is StakeKit -> ID.StakeKit
is TangemVisaAuth -> ID.TangemVisaAuth
}
}

View file

@ -0,0 +1,20 @@
package com.tangem.datasource.api.common.config
import com.tangem.utils.Provider
internal class TangemVisaAuth : ApiConfig() {
override val defaultEnvironment: ApiEnvironment = ApiEnvironment.STAGE
override val environmentConfigs = listOf(
createStageEnvironment(),
)
private fun createStageEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig(
environment = ApiEnvironment.STAGE,
baseUrl = "https://api-s.tangem.org/",
headers = createHeaders(),
)
private fun createHeaders() = mapOf<String, Provider<String>>()
}

View file

@ -1,44 +0,0 @@
package com.tangem.datasource.api.tangemTech
import com.tangem.datasource.api.common.MoshiConverter
import com.tangem.datasource.api.common.response.ApiResponseCallAdapterFactory
import com.tangem.datasource.utils.RequestHeader
import com.tangem.datasource.utils.RequestHeader.AuthenticationHeader
import com.tangem.datasource.utils.RequestHeader.CacheControlHeader
import com.tangem.datasource.utils.addHeaders
import com.tangem.datasource.utils.addLoggers
import okhttp3.OkHttpClient
import retrofit2.Retrofit
/**
[REDACTED_AUTHOR]
*/
// TODO("Remove after removing Redux")
@Deprecated("Use TangemTechApi")
object TangemTechService {
var api: TangemTechApi = createApi()
private set
private const val TANGEM_TECH_BASE_URL = "https://api.tangem-tech.com/v1/"
fun addAuthenticationHeader(header: AuthenticationHeader) {
api = createApi(header)
}
private fun createApi(header: RequestHeader? = null): TangemTechApi {
val headers = mutableListOf<RequestHeader>(CacheControlHeader).apply { header?.let(::add) }
return Retrofit.Builder()
.addConverterFactory(MoshiConverter.networkMoshiConverter)
.addCallAdapterFactory(ApiResponseCallAdapterFactory.create())
.baseUrl(TANGEM_TECH_BASE_URL)
.client(
OkHttpClient.Builder()
.addHeaders(*headers.toTypedArray())
.addLoggers()
.build(),
)
.build()
.create(TangemTechApi::class.java)
}
}

View file

@ -0,0 +1,5 @@
package com.tangem.datasource.api.visa
interface TangemVisaApi {
// TODO
}

View file

@ -0,0 +1,47 @@
package com.tangem.datasource.api.visa
import com.tangem.datasource.api.visa.models.response.GenerateNonceResponse
import com.tangem.datasource.api.visa.models.response.JWTResponse
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.Headers
import retrofit2.http.POST
interface TangemVisaAuthApi {
@FormUrlEncoded
@Headers("Content-Type: application/x-www-form-urlencoded")
@POST("auth/clients/mobile-app-android/nonce-challenge")
suspend fun generateNonceByWalletAddress(
@Field("customer_id") customerId: String? = null,
@Field("customer_wallet_address") customerWalletAddress: String,
): GenerateNonceResponse
@FormUrlEncoded
@Headers("Content-Type: application/x-www-form-urlencoded")
@POST("auth/clients/mobile-app-android/nonce-challenge")
suspend fun generateNonceByCard(
@Field("card_id") cardId: String,
@Field("card_public_key") cardPublicKey: String,
): GenerateNonceResponse
@FormUrlEncoded
@Headers("Content-Type: application/x-www-form-urlencoded")
@POST("auth/protocol/openid-connect/token")
suspend fun getAccessToken(
@Field("client_id") clientId: String = "mobile-app-android",
@Field("grant_type") grantType: String = "password",
@Field("session_id") sessionId: String,
@Field("signature") signature: String,
@Field("salt") salt: String?,
): JWTResponse
@FormUrlEncoded
@Headers("Content-Type: application/x-www-form-urlencoded")
@POST("auth/protocol/openid-connect/token")
suspend fun refreshAccessToken(
@Field("client_id") clientId: String = "mobile-app-android",
@Field("grant_type") grantType: String = "refresh_token",
@Field("refresh_token") refreshToken: String,
): JWTResponse
}

View file

@ -0,0 +1,10 @@
package com.tangem.datasource.api.visa.models.response
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class GenerateNonceResponse(
@Json(name = "nonce") val nonce: String,
@Json(name = "session_id") val sessionId: String,
)

View file

@ -0,0 +1,16 @@
package com.tangem.datasource.api.visa.models.response
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class JWTResponse(
@Json(name = "access_token") val accessToken: String,
@Json(name = "expires_in") val expiresIn: Int,
@Json(name = "refresh_expires_in") val refreshExpiresIn: Int,
@Json(name = "refresh_token") val refreshToken: String,
@Json(name = "token_type") val tokenType: String,
@Json(name = "not-before-policy") val notBeforePolicy: Int,
@Json(name = "session_state") val sessionState: String,
@Json(name = "scope") val scope: String,
)

View file

@ -1,7 +1,7 @@
package com.tangem.datasource.di
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.api.common.config.ApiConfig
import com.tangem.datasource.api.common.config.*
import com.tangem.datasource.api.common.config.Express
import com.tangem.datasource.api.common.config.StakeKit
import com.tangem.datasource.api.common.config.TangemTech
@ -39,4 +39,8 @@ internal object ApiConfigsModule {
@IntoSet
fun provideTangemTechConfig(appVersionProvider: AppVersionProvider, authProvider: AuthProvider): ApiConfig =
TangemTech(appVersionProvider, authProvider)
@Provides
@IntoSet
fun provideTangemVisaConfig(): ApiConfig = TangemVisaAuth()
}

View file

@ -15,6 +15,7 @@ import com.tangem.datasource.api.onramp.OnrampApi
import com.tangem.datasource.api.stakekit.StakeKitApi
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.TangemTechApiV2
import com.tangem.datasource.api.visa.TangemVisaAuthApi
import com.tangem.datasource.local.logs.AppLogsStore
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.utils.*
@ -169,6 +170,21 @@ internal object NetworkModule {
)
}
@Provides
@Singleton
fun provideTangemVisaApi(
@NetworkMoshi moshi: Moshi,
@ApplicationContext context: Context,
apiConfigsManager: ApiConfigsManager,
): TangemVisaAuthApi {
return createApi<TangemVisaAuthApi>(
id = ApiConfig.ID.TangemVisaAuth,
moshi = moshi,
context = context,
apiConfigsManager = apiConfigsManager,
)
}
@Deprecated("use createApi instead")
private inline fun <reified T> provideTangemTechApiInternal(
moshi: Moshi,

View file

@ -87,6 +87,19 @@ internal object BlockchainSDKConfigConverter : Converter<EnvironmentConfigModel,
base = GetBlockAccessToken(jsonRpc = accessTokens.base?.jsonRPC),
blast = GetBlockAccessToken(jsonRpc = accessTokens.blast?.jsonRPC),
filecoin = GetBlockAccessToken(jsonRpc = accessTokens.filecoin?.jsonRPC),
arbitrum = GetBlockAccessToken(jsonRpc = accessTokens.arbitrum?.jsonRPC),
bitcoinCash = GetBlockAccessToken(
jsonRpc = accessTokens.bitcoinCash?.jsonRPC,
blockBookRest = accessTokens.bitcoinCash?.blockBookRest,
),
kusama = GetBlockAccessToken(jsonRpc = accessTokens.kusama?.jsonRPC),
moonbeam = GetBlockAccessToken(jsonRpc = accessTokens.moonbeam?.jsonRPC),
optimism = GetBlockAccessToken(jsonRpc = accessTokens.optimism?.jsonRPC),
polkadot = GetBlockAccessToken(jsonRpc = accessTokens.polkadot?.jsonRPC),
shibarium = GetBlockAccessToken(jsonRpc = accessTokens.shibarium?.jsonRPC),
sui = GetBlockAccessToken(jsonRpc = accessTokens.sui?.jsonRPC),
telos = GetBlockAccessToken(jsonRpc = accessTokens.telos?.jsonRPC),
tezos = GetBlockAccessToken(rest = accessTokens.tezos?.rest),
)
}
}

View file

@ -66,6 +66,16 @@ data class GetBlockAccessTokens(
@Json(name = "base") val base: GetBlockToken?,
@Json(name = "blast") val blast: GetBlockToken?,
@Json(name = "filecoin") val filecoin: GetBlockToken?,
@Json(name = "arbitrum") val arbitrum: GetBlockToken?,
@Json(name = "bitcoinCash") val bitcoinCash: GetBlockToken?,
@Json(name = "kusama") val kusama: GetBlockToken?,
@Json(name = "moonbeam") val moonbeam: GetBlockToken?,
@Json(name = "optimism") val optimism: GetBlockToken?,
@Json(name = "polkadot") val polkadot: GetBlockToken?,
@Json(name = "shibarium") val shibarium: GetBlockToken?,
@Json(name = "sui") val sui: GetBlockToken?,
@Json(name = "telos") val telos: GetBlockToken?,
@Json(name = "tezos") val tezos: GetBlockToken?,
)
@JsonClass(generateAdapter = true)

View file

@ -85,6 +85,7 @@ internal class ProdApiConfigsManagerTest(private val model: Model) {
is Express -> createExpressModel()
is TangemTech -> createTangemTechModel()
is StakeKit -> createStakeKitModel()
is TangemVisaAuth -> createVisaAuthModel()
}
}
@ -172,6 +173,16 @@ internal class ProdApiConfigsManagerTest(private val model: Model) {
)
}
private fun createVisaAuthModel(): Model {
return Model(
id = ApiConfig.ID.TangemVisaAuth,
expected = ApiEnvironmentConfig(
environment = ApiEnvironment.STAGE,
baseUrl = "https://api-s.tangem.org/",
),
)
}
private fun String.checkHeaderValueOrEmpty(): String {
for (i in this.indices) {
val c = this[i]