Updated on 2026-08-14
This commit is contained in:
commit
85423227c4
390 changed files with 11140 additions and 1722 deletions
|
|
@ -8,6 +8,8 @@ import com.tangem.blockchain.common.Blockchain
|
|||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
|
||||
import com.tangem.domain.core.utils.lceContent
|
||||
import com.tangem.domain.core.utils.lceLoading
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
|
@ -19,6 +21,8 @@ import com.tangem.tap.domain.model.Currency
|
|||
import com.tangem.tap.features.demo.isDemoCard
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
|
|
@ -30,9 +34,19 @@ class CurrencyExchangeManager(
|
|||
private val primaryRules: ExchangeRules,
|
||||
) : ExchangeService {
|
||||
|
||||
override val initializationStatus: StateFlow<ExchangeServiceInitializationStatus>
|
||||
get() = _initializationStatus
|
||||
|
||||
private val _initializationStatus: MutableStateFlow<ExchangeServiceInitializationStatus> =
|
||||
MutableStateFlow(value = lceLoading())
|
||||
|
||||
override suspend fun update() {
|
||||
_initializationStatus.value = lceLoading()
|
||||
|
||||
buyService.update()
|
||||
sellService.update()
|
||||
|
||||
_initializationStatus.value = lceContent()
|
||||
}
|
||||
|
||||
override fun isBuyAllowed(): Boolean = primaryRules.isBuyAllowed() && buyService.isBuyAllowed()
|
||||
|
|
|
|||
|
|
@ -1,15 +1,29 @@
|
|||
package com.tangem.tap.network.exchangeServices
|
||||
|
||||
import com.tangem.datasource.api.express.models.TangemExpressValues.EMPTY_CONTRACT_ADDRESS_VALUE
|
||||
import com.tangem.datasource.exchangeservice.swap.SwapServiceLoader
|
||||
import com.tangem.domain.exchange.RampStateManager
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class DefaultRampManager(private val exchangeService: ExchangeService?) : RampStateManager {
|
||||
internal class DefaultRampManager(
|
||||
private val exchangeService: ExchangeService?,
|
||||
private val buyService: Provider<ExchangeService>,
|
||||
private val sellService: Provider<ExchangeService>,
|
||||
private val swapServiceLoader: SwapServiceLoader,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : RampStateManager {
|
||||
|
||||
private val cryptoCurrencyConverter = CryptoCurrencyConverter()
|
||||
|
||||
override fun availableForBuy(scanResponse: ScanResponse, cryptoCurrency: CryptoCurrency): Boolean {
|
||||
return exchangeService?.availableForBuy(
|
||||
scanResponse,
|
||||
scanResponse = scanResponse,
|
||||
currency = cryptoCurrencyConverter.convertBack(cryptoCurrency),
|
||||
) ?: false
|
||||
}
|
||||
|
|
@ -19,4 +33,46 @@ class DefaultRampManager(private val exchangeService: ExchangeService?) : RampSt
|
|||
currency = cryptoCurrencyConverter.convertBack(cryptoCurrency),
|
||||
) ?: false
|
||||
}
|
||||
|
||||
override suspend fun availableForSwap(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): Boolean {
|
||||
return getExchangeableFlag(userWalletId, cryptoCurrency) && !cryptoCurrency.isCustom
|
||||
}
|
||||
|
||||
override fun getBuyInitializationStatus(): Flow<ExchangeServiceInitializationStatus> {
|
||||
return buyService.invoke().initializationStatus
|
||||
}
|
||||
|
||||
override suspend fun fetchBuyServiceData() {
|
||||
withContext(dispatchers.io) {
|
||||
buyService.invoke().update()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSellInitializationStatus(): Flow<ExchangeServiceInitializationStatus> {
|
||||
return sellService.invoke().initializationStatus
|
||||
}
|
||||
|
||||
override suspend fun fetchSellServiceData() {
|
||||
withContext(dispatchers.io) {
|
||||
sellService.invoke().update()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSwapInitializationStatus(userWalletId: UserWalletId): Flow<ExchangeServiceInitializationStatus> {
|
||||
return swapServiceLoader.getInitializationStatus(userWalletId)
|
||||
}
|
||||
|
||||
private suspend fun getExchangeableFlag(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): Boolean {
|
||||
return withContext(dispatchers.io) {
|
||||
val contractAddress = (cryptoCurrency as? CryptoCurrency.Token)?.contractAddress
|
||||
?: EMPTY_CONTRACT_ADDRESS_VALUE
|
||||
|
||||
val asset = swapServiceLoader.getInitializationStatus(userWalletId).value.getOrNull()?.find {
|
||||
it.network == cryptoCurrency.network.backendId &&
|
||||
it.contractAddress.equals(contractAddress, ignoreCase = true)
|
||||
}
|
||||
|
||||
asset?.exchangeAvailable ?: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,14 @@
|
|||
package com.tangem.tap.network.exchangeServices
|
||||
|
||||
import com.tangem.domain.core.lce.Lce
|
||||
import com.tangem.domain.core.utils.lceLoading
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.tap.domain.model.Currency
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
typealias ExchangeServiceInitializationStatus = Lce<Throwable, Any>
|
||||
|
||||
interface Exchanger {
|
||||
fun isBuyAllowed(): Boolean
|
||||
|
|
@ -12,10 +18,17 @@ interface Exchanger {
|
|||
}
|
||||
|
||||
interface ExchangeService : Exchanger, ExchangeUrlBuilder {
|
||||
|
||||
val initializationStatus: StateFlow<ExchangeServiceInitializationStatus>
|
||||
|
||||
suspend fun update()
|
||||
|
||||
companion object {
|
||||
fun dummy(): ExchangeService = object : ExchangeService {
|
||||
|
||||
override val initializationStatus: StateFlow<ExchangeServiceInitializationStatus> =
|
||||
MutableStateFlow(value = lceLoading())
|
||||
|
||||
override suspend fun update() {}
|
||||
override fun isBuyAllowed(): Boolean = false
|
||||
override fun isSellAllowed(): Boolean = false
|
||||
|
|
|
|||
|
|
@ -138,6 +138,8 @@ internal val Blockchain.mercuryoNetwork: String?
|
|||
Blockchain.CasperTestnet -> null
|
||||
Blockchain.Core -> null
|
||||
Blockchain.CoreTestnet -> null
|
||||
Blockchain.Chiliz -> null
|
||||
Blockchain.ChilizTestnet -> null
|
||||
Blockchain.Unknown -> null
|
||||
Blockchain.Xodex -> null
|
||||
Blockchain.Canxium -> null
|
||||
|
|
|
|||
|
|
@ -6,12 +6,19 @@ import com.tangem.common.extensions.calculateSha512
|
|||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.common.services.performRequest
|
||||
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.models.scan.ScanResponse
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.tap.domain.model.Currency
|
||||
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
|
||||
import com.tangem.tap.network.exchangeServices.ExchangeService
|
||||
import com.tangem.tap.network.exchangeServices.ExchangeServiceInitializationStatus
|
||||
import com.tangem.tap.network.exchangeServices.ExchangeUrlBuilder
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
/**
|
||||
|
|
@ -19,10 +26,34 @@ import java.util.concurrent.CopyOnWriteArrayList
|
|||
*/
|
||||
internal class MercuryoService(private val environment: MercuryoEnvironment) : ExchangeService {
|
||||
|
||||
override val initializationStatus: StateFlow<ExchangeServiceInitializationStatus>
|
||||
get() = _initializationStatus
|
||||
|
||||
private val _initializationStatus: MutableStateFlow<ExchangeServiceInitializationStatus> =
|
||||
MutableStateFlow(value = lceLoading())
|
||||
|
||||
private val api: MercuryoApi = environment.mercuryoApi
|
||||
|
||||
private val availableMercuryoCurrencies = CopyOnWriteArrayList<MercuryoCurrenciesResponse.MercuryoCryptoCurrency>()
|
||||
|
||||
override suspend fun update() {
|
||||
Timber.i("Start updating")
|
||||
_initializationStatus.value = lceLoading()
|
||||
|
||||
val result = performRequest { api.currencies(environment.apiVersion) }
|
||||
when {
|
||||
result is Result.Success && result.data.status == RESPONSE_SUCCESS_STATUS_CODE -> {
|
||||
handleSuccessfullyUpdatedData(data = result.data.data)
|
||||
}
|
||||
result is Result.Failure -> {
|
||||
availableMercuryoCurrencies.clear()
|
||||
|
||||
Timber.e("Failed to load currencies", result.error)
|
||||
_initializationStatus.value = result.error.lceError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isBuyAllowed(): Boolean = true
|
||||
|
||||
override fun isSellAllowed(): Boolean = false
|
||||
|
|
@ -42,18 +73,6 @@ internal class MercuryoService(private val environment: MercuryoEnvironment) : E
|
|||
|
||||
override fun availableForSell(currency: Currency): Boolean = false
|
||||
|
||||
override suspend fun update() {
|
||||
val result = performRequest { api.currencies(environment.apiVersion) }
|
||||
when {
|
||||
result is Result.Success && result.data.status == RESPONSE_SUCCESS_STATUS_CODE -> {
|
||||
handleSuccessfullyUpdatedData(data = result.data.data)
|
||||
}
|
||||
result is Result.Failure -> {
|
||||
availableMercuryoCurrencies.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getUrl(
|
||||
action: CurrencyExchangeManager.Action,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
|
|
@ -89,6 +108,9 @@ internal class MercuryoService(private val environment: MercuryoEnvironment) : E
|
|||
private fun handleSuccessfullyUpdatedData(data: MercuryoCurrenciesResponse.Data) {
|
||||
availableMercuryoCurrencies.clear()
|
||||
availableMercuryoCurrencies.addAll(data.config.cryptoCurrencies)
|
||||
|
||||
Timber.i("Successfully updated")
|
||||
_initializationStatus.value = lceContent()
|
||||
}
|
||||
|
||||
private fun signature(address: String) = (address + environment.secret).calculateSha512().toHexString().lowercase()
|
||||
|
|
|
|||
|
|
@ -7,13 +7,20 @@ import com.tangem.common.services.Result
|
|||
import com.tangem.common.services.performRequest
|
||||
import com.tangem.datasource.api.common.createRetrofitInstance
|
||||
import com.tangem.domain.common.extensions.withIOContext
|
||||
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.models.scan.ScanResponse
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.tap.domain.model.Currency
|
||||
import com.tangem.tap.network.exchangeServices.CurrencyExchangeManager
|
||||
import com.tangem.tap.network.exchangeServices.ExchangeService
|
||||
import com.tangem.tap.network.exchangeServices.ExchangeServiceInitializationStatus
|
||||
import com.tangem.tap.network.exchangeServices.ExchangeUrlBuilder.Companion.SCHEME
|
||||
import com.tangem.tap.network.exchangeServices.moonpay.models.MoonPayAvailableCurrency
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import timber.log.Timber
|
||||
import javax.crypto.Mac
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
|
|
@ -23,6 +30,12 @@ class MoonPayService(
|
|||
private val logEnabled: Boolean,
|
||||
) : ExchangeService {
|
||||
|
||||
override val initializationStatus: StateFlow<ExchangeServiceInitializationStatus>
|
||||
get() = _initializationStatus
|
||||
|
||||
private val _initializationStatus: MutableStateFlow<ExchangeServiceInitializationStatus> =
|
||||
MutableStateFlow(value = lceLoading())
|
||||
|
||||
private val api: MoonPayApi by lazy {
|
||||
createRetrofitInstance(
|
||||
baseUrl = MoonPayApi.MOOONPAY_BASE_URL,
|
||||
|
|
@ -34,14 +47,25 @@ class MoonPayService(
|
|||
|
||||
override suspend fun update() {
|
||||
withIOContext {
|
||||
Timber.i("Start updating")
|
||||
_initializationStatus.value = lceLoading()
|
||||
|
||||
performRequest {
|
||||
val userStatus = when (val result = performRequest { api.getUserStatus(apiKey) }) {
|
||||
is Result.Failure -> return@performRequest
|
||||
is Result.Failure -> {
|
||||
Timber.e("Failed to load user status", result.error)
|
||||
_initializationStatus.value = result.error.lceError()
|
||||
return@performRequest
|
||||
}
|
||||
is Result.Success -> result.data
|
||||
}
|
||||
|
||||
val currencies = when (val result = performRequest { api.getCurrencies(apiKey) }) {
|
||||
is Result.Failure -> return@performRequest
|
||||
is Result.Failure -> {
|
||||
Timber.e("Failed to load currencies", result.error)
|
||||
_initializationStatus.value = result.error.lceError()
|
||||
return@performRequest
|
||||
}
|
||||
is Result.Success -> result.data
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +82,8 @@ class MoonPayService(
|
|||
)
|
||||
}
|
||||
|
||||
Timber.i("Successfully updated")
|
||||
_initializationStatus.value = lceContent()
|
||||
status = MoonPayStatus(currenciesToSell, userStatus, currencies)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ internal val Blockchain.moonPaySupportedCurrency: MoonPaySupportedCurrency?
|
|||
Filecoin -> MoonPaySupportedCurrency(networkCode = "filecoin", currencyCode = "fil")
|
||||
Sui -> MoonPaySupportedCurrency(networkCode = "sui", currencyCode = "sui")
|
||||
Core -> MoonPaySupportedCurrency(networkCode = "core", currencyCode = "core")
|
||||
Chiliz -> MoonPaySupportedCurrency(networkCode = "ethereum", currencyCode = "chz")
|
||||
ArbitrumTestnet -> null
|
||||
AvalancheTestnet -> null
|
||||
BinanceTestnet -> null
|
||||
|
|
@ -139,6 +140,7 @@ internal val Blockchain.moonPaySupportedCurrency: MoonPaySupportedCurrency?
|
|||
Casper -> null
|
||||
CasperTestnet -> null
|
||||
CoreTestnet -> null
|
||||
ChilizTestnet -> null
|
||||
Unknown -> null
|
||||
Xodex -> null
|
||||
Canxium -> null
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue