Updated on 2026-08-14
This commit is contained in:
commit
00805c1380
268 changed files with 6515 additions and 1380 deletions
|
|
@ -1,178 +0,0 @@
|
|||
package com.tangem.datasource.api.onramp
|
||||
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.datasource.api.onramp.models.common.OnrampDestinationDTO
|
||||
import com.tangem.datasource.api.onramp.models.request.OnrampPairsRequest
|
||||
import com.tangem.datasource.api.onramp.models.response.OnrampDataResponse
|
||||
import com.tangem.datasource.api.onramp.models.response.OnrampQuoteResponse
|
||||
import com.tangem.datasource.api.onramp.models.response.OnrampStatusResponse
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampCountryDTO
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampCurrencyDTO
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampPairDTO
|
||||
import com.tangem.datasource.api.onramp.models.response.model.PaymentMethodDTO
|
||||
|
||||
internal class MockedOnrampApi : OnrampApi {
|
||||
override suspend fun getCurrencies(): ApiResponse<List<OnrampCurrencyDTO>> = ApiResponse.Success(
|
||||
COUNTRIES.map(OnrampCountryDTO::defaultCurrency),
|
||||
)
|
||||
|
||||
override suspend fun getCountries(): ApiResponse<List<OnrampCountryDTO>> = ApiResponse.Success(COUNTRIES + RUSSIA)
|
||||
|
||||
override suspend fun getCountryByIp(): ApiResponse<OnrampCountryDTO> = ApiResponse.Success(RUSSIA)
|
||||
|
||||
override suspend fun getPaymentMethods(): ApiResponse<List<PaymentMethodDTO>> = ApiResponse.Success(
|
||||
listOf(
|
||||
PaymentMethodDTO(id = "google", name = "Google Play", image = ""),
|
||||
PaymentMethodDTO(id = "apple", name = "Apple Pay", image = ""),
|
||||
PaymentMethodDTO(id = "card", name = "Card", image = ""),
|
||||
),
|
||||
)
|
||||
|
||||
override suspend fun getPairs(body: OnrampPairsRequest): ApiResponse<List<OnrampPairDTO>> = ApiResponse.Success(
|
||||
listOf(
|
||||
OnrampPairDTO(
|
||||
fromCurrencyCode = "USD",
|
||||
to = OnrampDestinationDTO(contractAddress = "0xcontract_address", network = "ethereum"),
|
||||
providers = listOf(),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
override suspend fun getQuote(
|
||||
fromCurrencyCode: String,
|
||||
toContractAddress: String,
|
||||
toNetwork: String,
|
||||
paymentMethod: String,
|
||||
countryCode: String,
|
||||
fromAmount: String,
|
||||
toDecimals: Int,
|
||||
providerId: String,
|
||||
): ApiResponse<OnrampQuoteResponse> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun getData(
|
||||
fromCurrencyCode: String,
|
||||
toContractAddress: String,
|
||||
toNetwork: String,
|
||||
paymentMethod: String,
|
||||
countryCode: String,
|
||||
fromAmount: String,
|
||||
toDecimals: Int,
|
||||
providerId: String,
|
||||
toAddress: String,
|
||||
redirectUrl: String,
|
||||
language: String?,
|
||||
theme: String?,
|
||||
requestId: String,
|
||||
): ApiResponse<OnrampDataResponse> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun getStatus(txId: String): ApiResponse<OnrampStatusResponse> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private val RUSSIA = OnrampCountryDTO(
|
||||
name = "Russia",
|
||||
code = "RU",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/ru.svg",
|
||||
alpha3 = "RUS",
|
||||
continent = "",
|
||||
defaultCurrency = OnrampCurrencyDTO(
|
||||
name = "Russian ruble",
|
||||
code = "RUB",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/ru.svg",
|
||||
precision = 2,
|
||||
),
|
||||
onrampAvailable = false,
|
||||
)
|
||||
private val COUNTRIES = listOf(
|
||||
OnrampCountryDTO(
|
||||
name = "United States of America",
|
||||
code = "USA",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/us.svg",
|
||||
alpha3 = "USA",
|
||||
continent = "",
|
||||
defaultCurrency = OnrampCurrencyDTO(
|
||||
name = "US Dollar",
|
||||
code = "USD",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/us.svg",
|
||||
precision = 2,
|
||||
),
|
||||
onrampAvailable = true,
|
||||
),
|
||||
OnrampCountryDTO(
|
||||
name = "Europe Union",
|
||||
code = "EU",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/eu.svg",
|
||||
alpha3 = "EUR",
|
||||
continent = "",
|
||||
defaultCurrency = OnrampCurrencyDTO(
|
||||
name = "Euro",
|
||||
code = "EUR",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/eu.svg",
|
||||
precision = 2,
|
||||
),
|
||||
onrampAvailable = true,
|
||||
),
|
||||
OnrampCountryDTO(
|
||||
name = "Great Britain",
|
||||
code = "GB",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/gb.svg",
|
||||
alpha3 = "GB",
|
||||
continent = "",
|
||||
defaultCurrency = OnrampCurrencyDTO(
|
||||
name = "British Pound Sterling",
|
||||
code = "GBP",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/gb.svg",
|
||||
precision = 2,
|
||||
),
|
||||
onrampAvailable = true,
|
||||
),
|
||||
OnrampCountryDTO(
|
||||
name = "CANADA",
|
||||
code = "CA",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/ca.svg",
|
||||
alpha3 = "CA",
|
||||
continent = "",
|
||||
defaultCurrency = OnrampCurrencyDTO(
|
||||
name = "Canadian Dollar",
|
||||
code = "CAD",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/ca.svg",
|
||||
precision = 2,
|
||||
),
|
||||
onrampAvailable = true,
|
||||
),
|
||||
OnrampCountryDTO(
|
||||
name = "Hon Kong",
|
||||
code = "HK",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/hk.svg",
|
||||
alpha3 = "HK",
|
||||
continent = "",
|
||||
defaultCurrency = OnrampCurrencyDTO(
|
||||
name = "Hon Kong Dollar",
|
||||
code = "HKD",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/hk.svg",
|
||||
precision = 2,
|
||||
),
|
||||
onrampAvailable = true,
|
||||
),
|
||||
OnrampCountryDTO(
|
||||
name = "Australia",
|
||||
code = "AU",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/au.svg",
|
||||
alpha3 = "AU",
|
||||
continent = "",
|
||||
defaultCurrency = OnrampCurrencyDTO(
|
||||
name = "Australian Dollar",
|
||||
code = "AUD",
|
||||
image = "https://hatscripts.github.io/circle-flags/flags/au.svg",
|
||||
precision = 2,
|
||||
),
|
||||
onrampAvailable = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@ import com.tangem.datasource.api.common.config.managers.ProdApiConfigsManager
|
|||
import com.tangem.datasource.api.common.response.ApiResponseCallAdapterFactory
|
||||
import com.tangem.datasource.api.express.TangemExpressApi
|
||||
import com.tangem.datasource.api.markets.TangemTechMarketsApi
|
||||
import com.tangem.datasource.api.onramp.MockedOnrampApi
|
||||
import com.tangem.datasource.api.onramp.OnrampApi
|
||||
import com.tangem.datasource.api.stakekit.StakeKitApi
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
|
|
@ -99,24 +98,22 @@ internal object NetworkModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampApi(
|
||||
// @NetworkMoshi moshi: Moshi,
|
||||
// @ApplicationContext context: Context,
|
||||
// apiConfigsManager: ApiConfigsManager,
|
||||
// appLogsStore: AppLogsStore,
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
apiConfigsManager: ApiConfigsManager,
|
||||
appLogsStore: AppLogsStore,
|
||||
): OnrampApi {
|
||||
// TODO: Remove when backend will be ready - [REDACTED_TASK_KEY]
|
||||
return MockedOnrampApi()
|
||||
// return createApi(
|
||||
// id = ApiConfig.ID.Express,
|
||||
// moshi = moshi,
|
||||
// context = context,
|
||||
// apiConfigsManager = apiConfigsManager,
|
||||
// clientBuilder = {
|
||||
// addInterceptor(
|
||||
// NetworkLogsSaveInterceptor(appLogsStore),
|
||||
// )
|
||||
// },
|
||||
// )
|
||||
return createApi(
|
||||
id = ApiConfig.ID.Express,
|
||||
moshi = moshi,
|
||||
context = context,
|
||||
apiConfigsManager = apiConfigsManager,
|
||||
clientBuilder = {
|
||||
addInterceptor(
|
||||
NetworkLogsSaveInterceptor(appLogsStore),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.datasource.di.exchangeservice
|
||||
|
||||
import com.tangem.datasource.exchangeservice.swap.DefaultSwapServiceLoader
|
||||
import com.tangem.datasource.exchangeservice.swap.SwapServiceLoader
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface ExchangeServiceLoaderModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindSwapServiceLoader(defaultSwapServiceLoader: DefaultSwapServiceLoader): SwapServiceLoader
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package com.tangem.datasource.exchangeservice.swap
|
||||
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.express.TangemExpressApi
|
||||
import com.tangem.datasource.api.express.models.TangemExpressValues.EMPTY_CONTRACT_ADDRESS_VALUE
|
||||
import com.tangem.datasource.api.express.models.request.AssetsRequestBody
|
||||
import com.tangem.datasource.api.express.models.request.LeastTokenInfo
|
||||
import com.tangem.datasource.api.express.models.response.Asset
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.datasource.local.token.ExpressAssetsStore
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.core.utils.lceContent
|
||||
import com.tangem.domain.core.utils.lceError
|
||||
import com.tangem.domain.core.utils.lceLoading
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
typealias InitializationStatusFlow = MutableStateFlow<Lce<Throwable, List<Asset>>>
|
||||
|
||||
/**
|
||||
* Default implementation of [SwapServiceLoader]
|
||||
*
|
||||
* @property tangemExpressApi express api
|
||||
* @property expressAssetsStore local storage
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultSwapServiceLoader @Inject constructor(
|
||||
private val tangemExpressApi: TangemExpressApi,
|
||||
private val expressAssetsStore: ExpressAssetsStore,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : SwapServiceLoader {
|
||||
|
||||
private val initializationStatuses =
|
||||
MutableStateFlow<Map<UserWalletId, InitializationStatusFlow>>(value = emptyMap())
|
||||
|
||||
override suspend fun update(userWalletId: UserWalletId, userTokens: UserTokensResponse) {
|
||||
withContext(dispatchers.io) {
|
||||
val initializationStatus = getInitializationStatusInternal(userWalletId)
|
||||
|
||||
initializationStatus.update { lceLoading() }
|
||||
|
||||
try {
|
||||
val tokensList = userTokens.tokens.map {
|
||||
LeastTokenInfo(
|
||||
contractAddress = it.contractAddress ?: EMPTY_CONTRACT_ADDRESS_VALUE,
|
||||
network = it.networkId,
|
||||
)
|
||||
}
|
||||
|
||||
if (tokensList.isNotEmpty()) {
|
||||
val response = tangemExpressApi.getAssets(
|
||||
body = AssetsRequestBody(tokensList = tokensList),
|
||||
).getOrThrow()
|
||||
|
||||
expressAssetsStore.store(userWalletId, response)
|
||||
|
||||
initializationStatus.update { response.lceContent() }
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
initializationStatus.update { e.lceError() }
|
||||
Timber.e(e, "Unable to fetch assets for: ${userWalletId.stringValue}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getInitializationStatus(userWalletId: UserWalletId): InitializationStatusFlow {
|
||||
return getInitializationStatusInternal(userWalletId)
|
||||
}
|
||||
|
||||
private fun getInitializationStatusInternal(userWalletId: UserWalletId): InitializationStatusFlow {
|
||||
val initializationStatus = initializationStatuses.value.get(key = userWalletId)
|
||||
|
||||
if (initializationStatus != null) return initializationStatus
|
||||
|
||||
val default: InitializationStatusFlow = MutableStateFlow(value = lceLoading())
|
||||
|
||||
initializationStatuses.update {
|
||||
it.toMutableMap().apply {
|
||||
put(key = userWalletId, value = default)
|
||||
}
|
||||
}
|
||||
|
||||
return default
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.tangem.datasource.exchangeservice.swap
|
||||
|
||||
import com.tangem.datasource.api.express.models.response.Asset
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/**
|
||||
* Swap service loader
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface SwapServiceLoader {
|
||||
|
||||
/** Update service using [userWalletId] and [userTokens] */
|
||||
suspend fun update(userWalletId: UserWalletId, userTokens: UserTokensResponse)
|
||||
|
||||
/** Get initialization status by [userWalletId] */
|
||||
fun getInitializationStatus(userWalletId: UserWalletId): StateFlow<Lce<Throwable, List<Asset>>>
|
||||
}
|
||||
|
|
@ -103,6 +103,10 @@ object PreferencesKeys {
|
|||
|
||||
val SHOULD_SHOW_RING_PROMO_KEY by lazy { booleanPreferencesKey(name = "shouldShowRingPromo") }
|
||||
|
||||
val ONRAMP_DEFAULT_CURRENCY by lazy { stringPreferencesKey(name = "onrampDefaultCurrency") }
|
||||
|
||||
val ONRAMP_DEFAULT_COUNTRY by lazy { stringPreferencesKey(name = "onrampDefaultCountry") }
|
||||
|
||||
// region Permission
|
||||
fun getShouldShowPermission(permission: String) = booleanPreferencesKey("shouldShowPushPermission_$permission")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue