Updated on 2026-08-14
This commit is contained in:
parent
d9a539b64d
commit
d68ad52a45
16 changed files with 278 additions and 2 deletions
|
|
@ -18,6 +18,8 @@ interface AuthProvider {
|
|||
|
||||
fun getApiKey(apiEnvironment: Provider<ApiEnvironment>): ProviderSuspend<String>
|
||||
|
||||
fun getGaslessServiceApiKey(apiEnvironment: Provider<ApiEnvironment>): ProviderSuspend<String>
|
||||
|
||||
/**
|
||||
* Returns map where keys(cardId) associated with cardPublicKey
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ sealed class ApiConfig {
|
|||
YieldSupply,
|
||||
MoonPay,
|
||||
News,
|
||||
GaslessTxService,
|
||||
}
|
||||
|
||||
private fun initializeId(): ID {
|
||||
|
|
@ -45,6 +46,7 @@ sealed class ApiConfig {
|
|||
is YieldSupply -> ID.YieldSupply
|
||||
is MoonPay -> ID.MoonPay
|
||||
is News -> ID.News
|
||||
is GaslessTxService -> ID.GaslessTxService
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
package com.tangem.datasource.api.common.config
|
||||
|
||||
import com.tangem.datasource.BuildConfig
|
||||
import com.tangem.datasource.api.common.AuthProvider
|
||||
import com.tangem.datasource.utils.RequestHeader
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.ProviderSuspend
|
||||
import com.tangem.utils.info.AppInfoProvider
|
||||
import com.tangem.utils.version.AppVersionProvider
|
||||
|
||||
/**
|
||||
* Gasless transactions [ApiConfig]
|
||||
*/
|
||||
internal class GaslessTxService(
|
||||
private val authProvider: AuthProvider,
|
||||
private val appVersionProvider: AppVersionProvider,
|
||||
private val appInfoProvider: AppInfoProvider,
|
||||
) : ApiConfig() {
|
||||
|
||||
override val defaultEnvironment: ApiEnvironment = getInitialEnvironment()
|
||||
|
||||
override val environmentConfigs: List<ApiEnvironmentConfig> = listOf(
|
||||
createProdEnvironment(),
|
||||
createDevEnvironment(),
|
||||
)
|
||||
|
||||
private fun getInitialEnvironment(): ApiEnvironment {
|
||||
return when (BuildConfig.BUILD_TYPE) {
|
||||
MOCKED_BUILD_TYPE,
|
||||
DEBUG_BUILD_TYPE,
|
||||
-> ApiEnvironment.DEV
|
||||
INTERNAL_BUILD_TYPE,
|
||||
EXTERNAL_BUILD_TYPE,
|
||||
RELEASE_BUILD_TYPE,
|
||||
-> ApiEnvironment.PROD
|
||||
else -> error("Unknown build type [${BuildConfig.BUILD_TYPE}]")
|
||||
}
|
||||
}
|
||||
|
||||
private fun createProdEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig(
|
||||
environment = ApiEnvironment.PROD,
|
||||
baseUrl = PROD_BASE_URL,
|
||||
headers = createHeaders(ApiEnvironment.PROD),
|
||||
)
|
||||
|
||||
private fun createDevEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig(
|
||||
environment = ApiEnvironment.DEV,
|
||||
baseUrl = DEV_BASE_URL,
|
||||
headers = createHeaders(ApiEnvironment.DEV),
|
||||
)
|
||||
|
||||
private fun createHeaders(environment: ApiEnvironment) = buildMap {
|
||||
putAll(RequestHeader.AppVersionPlatformHeaders(appVersionProvider, appInfoProvider).values)
|
||||
put(
|
||||
key = "Authorization",
|
||||
value = ProviderSuspend {
|
||||
"Bearer ${authProvider.getGaslessServiceApiKey(Provider { environment }).invoke()}"
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val PROD_BASE_URL = "https://api.tangem.org/"
|
||||
private const val DEV_BASE_URL = "[REDACTED_ENV_URL]"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.datasource.api.gasless
|
||||
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.datasource.api.gasless.models.GaslessServiceResponse
|
||||
import com.tangem.datasource.api.gasless.models.GaslessSupportedTokens
|
||||
import retrofit2.http.GET
|
||||
|
||||
interface GaslessTxServiceApi {
|
||||
|
||||
@GET("api/v1/tokens")
|
||||
suspend fun getSupportedTokens(): ApiResponse<GaslessServiceResponse<GaslessSupportedTokens>>
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.datasource.api.gasless.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GaslessServiceResponse<T>(
|
||||
@Json(name = "result") val result: T,
|
||||
@Json(name = "success") val isSuccess: Boolean,
|
||||
@Json(name = "timestamp") val timestamp: String,
|
||||
)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.datasource.api.gasless.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GaslessSupportedTokens(
|
||||
@Json(name = "tokens") val tokens: List<GaslessTokenDTO>,
|
||||
)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.datasource.api.gasless.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GaslessTokenDTO(
|
||||
@Json(name = "tokenAddress") val tokenAddress: String,
|
||||
@Json(name = "tokenSymbol") val tokenSymbol: String,
|
||||
@Json(name = "tokenName") val tokenName: String,
|
||||
@Json(name = "decimals") val decimals: Int,
|
||||
@Json(name = "chainId") val chainId: Int,
|
||||
@Json(name = "chain") val chain: String,
|
||||
)
|
||||
|
|
@ -15,6 +15,7 @@ import com.tangem.datasource.api.moonpay.MoonPayApi
|
|||
import com.tangem.datasource.api.news.NewsApi
|
||||
import com.tangem.datasource.api.onramp.OnrampApi
|
||||
import com.tangem.datasource.api.ethpool.P2PEthPoolApi
|
||||
import com.tangem.datasource.api.gasless.GaslessTxServiceApi
|
||||
import com.tangem.datasource.api.pay.TangemPayApi
|
||||
import com.tangem.datasource.api.pay.TangemPayAuthApi
|
||||
import com.tangem.datasource.api.stakekit.StakeKitApi
|
||||
|
|
@ -188,4 +189,13 @@ internal object NetworkModule {
|
|||
applyTimeoutAnnotations = false,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGaslessTxServiceApi(retrofitApiBuilder: RetrofitApiBuilder): GaslessTxServiceApi {
|
||||
return retrofitApiBuilder.build(
|
||||
apiConfigId = ApiConfig.ID.GaslessTxService,
|
||||
applyTimeoutAnnotations = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -75,6 +75,11 @@ class ApiConfigTest {
|
|||
ApiConfig.ID.P2PEthPool -> P2PEthPool(p2pAuthProvider = mockk())
|
||||
ApiConfig.ID.News -> News(authProvider = appAuthProvider)
|
||||
ApiConfig.ID.TangemPayAuth -> TangemPayAuth(appVersionProvider = mockk())
|
||||
ApiConfig.ID.GaslessTxService -> GaslessTxService(
|
||||
authProvider = appAuthProvider,
|
||||
appVersionProvider = mockk(),
|
||||
appInfoProvider = mockk(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ internal class MockEnvironmentConfigStorage : EnvironmentConfigStorage {
|
|||
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_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"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.datasource.api.common.config.ApiConfig.Companion.MOCKED_BUILD_
|
|||
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.domain.staking.model.ethpool.P2PEthPoolStakingConfig
|
||||
import com.tangem.lib.auth.ExpressAuthProvider
|
||||
import com.tangem.lib.auth.P2PEthPoolAuthProvider
|
||||
|
|
@ -45,6 +46,7 @@ internal class ProdApiConfigsManagerTest {
|
|||
private val appAuthProvider = mockk<AuthProvider>()
|
||||
private val appInfoProvider = mockk<AppInfoProvider>()
|
||||
private val tangemApiKeyProvider = mockk<ProviderSuspend<String>>()
|
||||
private val tangemGaslessApiKeyProvider = mockk<ProviderSuspend<String>>()
|
||||
|
||||
private lateinit var manager: ProdApiConfigsManager
|
||||
|
||||
|
|
@ -63,6 +65,8 @@ internal class ProdApiConfigsManagerTest {
|
|||
every { stakeKitAuthProvider.getApiKey() } returns STAKE_KIT_API_KEY
|
||||
every { p2pEthPoolAuthProvider.getApiKey() } returns P2P_API_KEY
|
||||
every { appAuthProvider.getApiKey(any()) } returns tangemApiKeyProvider
|
||||
every { appAuthProvider.getGaslessServiceApiKey(any()) } returns tangemGaslessApiKeyProvider
|
||||
coEvery { tangemGaslessApiKeyProvider.invoke() } returns TANGEM_GASLESS_API_KEY
|
||||
coEvery { tangemApiKeyProvider.invoke() } returns TANGEM_API_KEY
|
||||
coEvery { appAuthProvider.getCardId() } returns APP_CARD_ID
|
||||
coEvery { appAuthProvider.getCardPublicKey() } returns APP_CARD_PUBLIC_KEY
|
||||
|
|
@ -117,6 +121,11 @@ internal class ProdApiConfigsManagerTest {
|
|||
ApiConfig.ID.P2PEthPool -> P2PEthPool(p2pAuthProvider = p2pEthPoolAuthProvider)
|
||||
ApiConfig.ID.News -> News(authProvider = appAuthProvider)
|
||||
ApiConfig.ID.TangemPayAuth -> TangemPayAuth(appVersionProvider = appVersionProvider)
|
||||
ApiConfig.ID.GaslessTxService -> GaslessTxService(
|
||||
authProvider = appAuthProvider,
|
||||
appVersionProvider = appVersionProvider,
|
||||
appInfoProvider = appInfoProvider,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -133,6 +142,7 @@ internal class ProdApiConfigsManagerTest {
|
|||
ApiConfig.ID.P2PEthPool -> createP2PModel()
|
||||
ApiConfig.ID.News -> createNewsModel()
|
||||
ApiConfig.ID.TangemPayAuth -> createTangemPayAuthModel()
|
||||
ApiConfig.ID.GaslessTxService -> createGaslessTxServiceModel()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -274,6 +284,37 @@ internal class ProdApiConfigsManagerTest {
|
|||
)
|
||||
}
|
||||
|
||||
private fun createGaslessTxServiceModel(): TestModel {
|
||||
val (environment, baseUrl) = when (BuildConfig.BUILD_TYPE) {
|
||||
MOCKED_BUILD_TYPE,
|
||||
DEBUG_BUILD_TYPE,
|
||||
-> ApiEnvironment.DEV to "[REDACTED_ENV_URL]"
|
||||
INTERNAL_BUILD_TYPE,
|
||||
EXTERNAL_BUILD_TYPE,
|
||||
RELEASE_BUILD_TYPE,
|
||||
-> ApiEnvironment.PROD to "https://tangem.com/"
|
||||
else -> error("Unknown build type [${BuildConfig.BUILD_TYPE}]")
|
||||
}
|
||||
return TestModel(
|
||||
id = ApiConfig.ID.GaslessTxService,
|
||||
expected = ApiEnvironmentConfig(
|
||||
environment = environment,
|
||||
baseUrl = baseUrl,
|
||||
headers = mapOf(
|
||||
"Authorization" to ProviderSuspend { "Bearer $TANGEM_GASLESS_API_KEY" },
|
||||
"version" to ProviderSuspend { VERSION_NAME },
|
||||
"platform" to ProviderSuspend { "android" },
|
||||
"system_version" to ProviderSuspend { "Android 16" },
|
||||
"language" to ProviderSuspend { Locale.getDefault().language.checkHeaderValueOrEmpty() },
|
||||
"timezone" to ProviderSuspend {
|
||||
TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT).checkHeaderValueOrEmpty()
|
||||
},
|
||||
"device" to ProviderSuspend { "${Build.MANUFACTURER} ${Build.MODEL}".checkHeaderValueOrEmpty() },
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createBlockAidSdkModel(): TestModel {
|
||||
return TestModel(
|
||||
id = ApiConfig.ID.BlockAid,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue