Updated on 2026-08-14
This commit is contained in:
commit
0becaafc0a
74 changed files with 641 additions and 249 deletions
|
|
@ -228,8 +228,8 @@ dependencies {
|
|||
implementation(deps.armadillo)
|
||||
implementation(deps.mviCore.watcher)
|
||||
implementation(deps.kotlin.serialization)
|
||||
implementation(deps.walletConnectCore)
|
||||
implementation(deps.walletConnectWeb3)
|
||||
implementation(deps.reownCore)
|
||||
implementation(deps.reownWeb3)
|
||||
implementation(deps.prettyLogger)
|
||||
|
||||
/** Testing libraries */
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit cce49feacb18dc9ad7cc5da62d58f1b3338a1057
|
||||
Subproject commit f1aa2f2cbf374ecba5da753d9f51c9df81749ef2
|
||||
|
|
@ -3,6 +3,7 @@ package com.tangem.tap
|
|||
import com.tangem.TangemSdkLogger
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.blockchainsdk.signer.TransactionSignerFactory
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.filter.OneTimeEventFilter
|
||||
import com.tangem.core.configtoggle.blockchain.ExcludedBlockchainsManager
|
||||
|
|
@ -119,4 +120,6 @@ interface ApplicationEntryPoint {
|
|||
fun getOnboardingV2FeatureToggles(): OnboardingV2FeatureToggles
|
||||
|
||||
fun getCoroutineDispatcherProvider(): CoroutineDispatcherProvider
|
||||
|
||||
fun getExcludedBlockchains(): ExcludedBlockchains
|
||||
}
|
||||
|
|
@ -92,6 +92,7 @@ import kotlinx.coroutines.flow.*
|
|||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
lateinit var tangemSdkManager: TangemSdkManager
|
||||
lateinit var backupService: BackupService
|
||||
|
|
@ -330,7 +331,11 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
|
||||
private fun installAppTheme() {
|
||||
appThemeModeFlow = createAppThemeModeFlow()
|
||||
val mode = runBlocking { appThemeModeFlow.first() }
|
||||
val mode = runBlocking {
|
||||
withTimeoutOrNull(APP_THEME_LOAD_TIMEOUT.seconds) {
|
||||
appThemeModeFlow.first()
|
||||
} ?: AppThemeMode.DEFAULT
|
||||
}
|
||||
|
||||
updateAppTheme(mode)
|
||||
}
|
||||
|
|
@ -599,4 +604,8 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
.onRight { Timber.d("Submitting hashes succeeded") }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val APP_THEME_LOAD_TIMEOUT = 2
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import com.tangem.TangemSdkLogger
|
|||
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.blockchainsdk.signer.TransactionSignerFactory
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.api.ParamsInterceptor
|
||||
|
|
@ -189,6 +190,9 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
|||
|
||||
private val dispatchers: CoroutineDispatcherProvider
|
||||
get() = entryPoint.getCoroutineDispatcherProvider()
|
||||
|
||||
private val excludedBlockchains: ExcludedBlockchains
|
||||
get() = entryPoint.getExcludedBlockchains()
|
||||
// endregion
|
||||
|
||||
override fun onCreate() {
|
||||
|
|
@ -269,6 +273,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
|
|||
onrampFeatureToggles = onrampFeatureToggles,
|
||||
environmentConfigStorage = environmentConfigStorage,
|
||||
onboardingV2FeatureToggles = onboardingV2FeatureToggles,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.di
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.datasource.exchangeservice.swap.SwapServiceLoader
|
||||
import com.tangem.domain.card.ScanCardUseCase
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
|
|
@ -49,6 +50,7 @@ internal object ActivityModule {
|
|||
swapServiceLoader: SwapServiceLoader,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): RampStateManager {
|
||||
return DefaultRampManager(
|
||||
|
|
@ -58,6 +60,7 @@ internal object ActivityModule {
|
|||
swapServiceLoader = swapServiceLoader,
|
||||
currenciesRepository = currenciesRepository,
|
||||
getNetworkCoinStatusUseCase = getNetworkCoinStatusUseCase,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.di.data
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.card.repository.DerivationsRepository
|
||||
import com.tangem.sdk.api.TangemSdkManager
|
||||
|
|
@ -20,8 +21,9 @@ internal object CardDataModule {
|
|||
fun providesDerivationsRepository(
|
||||
tangemSdkManager: TangemSdkManager,
|
||||
userWalletsStore: UserWalletsStore,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): DerivationsRepository {
|
||||
return DefaultDerivationsRepository(tangemSdkManager, userWalletsStore, dispatchers)
|
||||
return DefaultDerivationsRepository(tangemSdkManager, userWalletsStore, excludedBlockchains, dispatchers)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.domain.card
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
|
|
@ -32,6 +33,7 @@ private typealias DerivedKeys = Map<ByteArrayKey, ExtendedPublicKeysMap>
|
|||
internal class DefaultDerivationsRepository(
|
||||
private val tangemSdkManager: TangemSdkManager,
|
||||
private val userWalletsStore: UserWalletsStore,
|
||||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : DerivationsRepository {
|
||||
|
||||
|
|
@ -49,6 +51,7 @@ internal class DefaultDerivationsRepository(
|
|||
blockchain = Blockchain.fromNetworkId(it.value) ?: return@mapNotNull null,
|
||||
extraDerivationPath = null,
|
||||
scanResponse = userWallet.scanResponse,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -85,6 +88,7 @@ internal class DefaultDerivationsRepository(
|
|||
blockchain = Blockchain.fromNetworkId(backendId) ?: return@mapNotNull null,
|
||||
extraDerivationPath = extraDerivationPath,
|
||||
scanResponse = userWallet.scanResponse,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@ package com.tangem.tap.domain.walletconnect2.data
|
|||
|
||||
import android.app.Application
|
||||
import arrow.core.flatten
|
||||
import com.reown.android.Core
|
||||
import com.reown.android.CoreClient
|
||||
import com.reown.android.relay.ConnectionType
|
||||
import com.reown.walletkit.client.Wallet
|
||||
import com.reown.walletkit.client.WalletKit
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.tap.common.analytics.events.WalletConnect
|
||||
import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository
|
||||
|
|
@ -9,11 +14,6 @@ import com.tangem.tap.domain.walletconnect2.domain.WcJrpcMethods
|
|||
import com.tangem.tap.domain.walletconnect2.domain.WcJrpcRequestsDeserializer
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WcRequest
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.*
|
||||
import com.walletconnect.android.Core
|
||||
import com.walletconnect.android.CoreClient
|
||||
import com.walletconnect.android.relay.ConnectionType
|
||||
import com.walletconnect.web3.wallet.client.Wallet
|
||||
import com.walletconnect.web3.wallet.client.Web3Wallet
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
|
@ -72,7 +72,7 @@ internal class DefaultLegacyWalletConnectRepository(
|
|||
}
|
||||
}
|
||||
|
||||
Web3Wallet.initialize(Wallet.Params.Init(core = CoreClient)) { error ->
|
||||
WalletKit.initialize(Wallet.Params.Init(core = CoreClient)) { error ->
|
||||
Timber.e("Error while initializing Web3Wallet: $error")
|
||||
scope.launch {
|
||||
_events.emit(
|
||||
|
|
@ -84,11 +84,11 @@ internal class DefaultLegacyWalletConnectRepository(
|
|||
}
|
||||
|
||||
val walletDelegate = defineWalletDelegate()
|
||||
Web3Wallet.setWalletDelegate(walletDelegate)
|
||||
WalletKit.setWalletDelegate(walletDelegate)
|
||||
}
|
||||
|
||||
private fun defineWalletDelegate(): Web3Wallet.WalletDelegate {
|
||||
return object : Web3Wallet.WalletDelegate {
|
||||
private fun defineWalletDelegate(): WalletKit.WalletDelegate {
|
||||
return object : WalletKit.WalletDelegate {
|
||||
override fun onSessionProposal(
|
||||
sessionProposal: Wallet.Model.SessionProposal,
|
||||
verifyContext: Wallet.Model.VerifyContext,
|
||||
|
|
@ -188,14 +188,6 @@ internal class DefaultLegacyWalletConnectRepository(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onAuthRequest(
|
||||
authRequest: Wallet.Model.AuthRequest,
|
||||
verifyContext: Wallet.Model.VerifyContext,
|
||||
) {
|
||||
// Triggered when Dapp / Requester makes an authorization request
|
||||
Timber.i("onAuthRequest: $authRequest")
|
||||
}
|
||||
|
||||
override fun onSessionDelete(sessionDelete: Wallet.Model.SessionDelete) {
|
||||
// Triggered when the session is deleted by the peer
|
||||
if (sessionDelete is Wallet.Model.SessionDelete.Success) {
|
||||
|
|
@ -251,7 +243,7 @@ internal class DefaultLegacyWalletConnectRepository(
|
|||
}
|
||||
|
||||
override fun pair(uri: String) {
|
||||
Web3Wallet.pair(
|
||||
WalletKit.pair(
|
||||
params = Wallet.Params.Pair(uri),
|
||||
onSuccess = {
|
||||
Timber.i("Paired successfully: $it")
|
||||
|
|
@ -303,7 +295,7 @@ internal class DefaultLegacyWalletConnectRepository(
|
|||
|
||||
Timber.i("Session approval is prepared for sending: $sessionApproval")
|
||||
|
||||
Web3Wallet.approveSession(
|
||||
WalletKit.approveSession(
|
||||
params = sessionApproval,
|
||||
onSuccess = {
|
||||
Timber.i("Approved successfully: $it")
|
||||
|
|
@ -364,7 +356,7 @@ internal class DefaultLegacyWalletConnectRepository(
|
|||
)
|
||||
}
|
||||
|
||||
Web3Wallet.respondSessionRequest(
|
||||
WalletKit.respondSessionRequest(
|
||||
params = Wallet.Params.SessionRequestResponse(
|
||||
sessionTopic = requestData.topic,
|
||||
jsonRpcResponse = Wallet.Model.JsonRpcResponse.JsonRpcResult(
|
||||
|
|
@ -409,7 +401,7 @@ internal class DefaultLegacyWalletConnectRepository(
|
|||
}
|
||||
|
||||
override fun cancelRequest(topic: String, id: Long, message: String) {
|
||||
Web3Wallet.respondSessionRequest(
|
||||
WalletKit.respondSessionRequest(
|
||||
params = Wallet.Params.SessionRequestResponse(
|
||||
sessionTopic = topic,
|
||||
jsonRpcResponse = Wallet.Model.JsonRpcResponse.JsonRpcError(
|
||||
|
|
@ -424,7 +416,7 @@ internal class DefaultLegacyWalletConnectRepository(
|
|||
}
|
||||
|
||||
override fun reject() {
|
||||
Web3Wallet.rejectSession(
|
||||
WalletKit.rejectSession(
|
||||
params = Wallet.Params.SessionReject(
|
||||
proposerPublicKey = sessionProposal?.proposerPublicKey ?: "",
|
||||
reason = "",
|
||||
|
|
@ -440,7 +432,7 @@ internal class DefaultLegacyWalletConnectRepository(
|
|||
|
||||
override fun disconnect(topic: String) {
|
||||
val session = currentSessions.find { it.topic == topic }
|
||||
Web3Wallet.disconnectSession(
|
||||
WalletKit.disconnectSession(
|
||||
params = Wallet.Params.SessionDisconnect(topic),
|
||||
onSuccess = {
|
||||
analyticsHandler.send(
|
||||
|
|
@ -459,7 +451,7 @@ internal class DefaultLegacyWalletConnectRepository(
|
|||
}
|
||||
|
||||
fun send(topic: String, id: Long, data: String) {
|
||||
Web3Wallet.respondSessionRequest(
|
||||
WalletKit.respondSessionRequest(
|
||||
params = Wallet.Params.SessionRequestResponse(
|
||||
sessionTopic = topic,
|
||||
jsonRpcResponse = Wallet.Model.JsonRpcResponse.JsonRpcResult(
|
||||
|
|
@ -477,7 +469,7 @@ internal class DefaultLegacyWalletConnectRepository(
|
|||
}
|
||||
|
||||
private fun updateSessionsInternal(): Job = scope.launch {
|
||||
val availableSessions = Web3Wallet.getListOfActiveSessions()
|
||||
val availableSessions = WalletKit.getListOfActiveSessions()
|
||||
.map {
|
||||
WalletConnectSession(
|
||||
topic = it.topic,
|
||||
|
|
|
|||
|
|
@ -163,7 +163,9 @@ internal class WcSessionRequestConverter(
|
|||
return sessionsRepository.loadSessions(userWalletId)
|
||||
.firstOrNull { it.topic == sessionRequest.topic }
|
||||
?.accounts?.firstOrNull {
|
||||
it.chainId == sessionRequest.chainId && it.walletAddress.lowercase() == walletAddress?.lowercase()
|
||||
// if walletAddress == null take first account
|
||||
it.chainId == sessionRequest.chainId &&
|
||||
(walletAddress == null || it.walletAddress.lowercase() == walletAddress.lowercase())
|
||||
}?.derivationPath
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
package com.tangem.tap.domain.walletconnect2.domain.mapper
|
||||
|
||||
import com.tangem.blockchain.blockchains.solana.solanaj.core.SolanaTransaction
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.solana.SolanaTransactionRequest
|
||||
import org.p2p.solanaj.core.AccountMeta
|
||||
import org.p2p.solanaj.core.PublicKey
|
||||
import org.p2p.solanaj.core.TransactionInstruction
|
||||
|
||||
internal fun SolanaTransactionRequest.mapToTransaction(): SolanaTransaction {
|
||||
val from = PublicKey(feePayer)
|
||||
val instructions = instructions.map(SolanaTransactionRequest.Instruction::mapToInstruction)
|
||||
|
||||
return SolanaTransaction(from)
|
||||
.apply {
|
||||
instructions.forEach(::addInstruction)
|
||||
setRecentBlockHash(recentBlockhash)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SolanaTransactionRequest.Instruction.mapToInstruction() = TransactionInstruction(
|
||||
/* programId = */ PublicKey(programId),
|
||||
/* keys = */ keys.map(SolanaTransactionRequest.Key::mapToAccountMeta),
|
||||
/* data = */ data.toByteArray(),
|
||||
)
|
||||
|
||||
private fun SolanaTransactionRequest.Key.mapToAccountMeta() = AccountMeta(
|
||||
/* publicKey = */ PublicKey(publicKey),
|
||||
/* isSigner = */ isSigner,
|
||||
/* isWritable = */ isWritable,
|
||||
)
|
||||
|
|
@ -7,39 +7,8 @@ import com.tangem.tap.domain.walletconnect2.domain.WcRequestData
|
|||
@JsonClass(generateAdapter = true)
|
||||
data class SolanaTransactionRequest(
|
||||
@Json(name = "feePayer")
|
||||
val feePayer: String,
|
||||
|
||||
@Json(name = "recentBlockhash")
|
||||
val recentBlockhash: String,
|
||||
|
||||
@Json(name = "instructions")
|
||||
val instructions: List<Instruction>,
|
||||
val feePayer: String?,
|
||||
|
||||
@Json(name = "transaction")
|
||||
val transaction: String,
|
||||
) : WcRequestData {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Instruction(
|
||||
@Json(name = "programId")
|
||||
val programId: String,
|
||||
|
||||
@Json(name = "data")
|
||||
val data: String,
|
||||
|
||||
@Json(name = "keys")
|
||||
val keys: List<Key>,
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Key(
|
||||
@Json(name = "isSigner")
|
||||
val isSigner: Boolean,
|
||||
|
||||
@Json(name = "isWritable")
|
||||
val isWritable: Boolean,
|
||||
|
||||
@Json(name = "pubkey")
|
||||
val publicKey: String,
|
||||
)
|
||||
}
|
||||
) : WcRequestData
|
||||
|
|
@ -53,6 +53,9 @@ private fun handlePrepareScreen(action: DetailsAction.PrepareScreen): DetailsSta
|
|||
store.inject(DaggerGraphState::balanceHidingRepository)
|
||||
.getBalanceHidingSettings().isHidingEnabledInSettings
|
||||
},
|
||||
needEnrollBiometrics = runBlocking {
|
||||
runCatching(tangemSdkManager::needEnrollBiometrics).getOrNull() ?: false
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ import com.tangem.wallet.R
|
|||
internal object SignTransactionDialog {
|
||||
|
||||
fun create(preparedData: WcPreparedRequest.SignTransaction, context: Context): AlertDialog {
|
||||
val message = context.getString(R.string.wallet_connect_alert_sign_message, "")
|
||||
val signMessage = context.getString(R.string.wallet_connect_alert_sign_message, "")
|
||||
val message = "${preparedData.preparedRequestData.dAppName}\n$signMessage"
|
||||
return AlertDialog.Builder(context).apply {
|
||||
setTitle(context.getString(R.string.wallet_connect_title))
|
||||
setMessage(message)
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import com.tangem.tap.common.extensions.*
|
|||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletAction
|
||||
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletAction
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStartedSource
|
||||
import com.tangem.tap.features.saveWallet.redux.SaveWalletAction
|
||||
import com.tangem.tap.mainScope
|
||||
|
|
@ -224,7 +224,9 @@ object OnboardingHelper {
|
|||
|
||||
fun handleTopUpAction(walletManager: WalletManager, scanResponse: ScanResponse, globalState: GlobalState) {
|
||||
val blockchain = walletManager.wallet.blockchain
|
||||
val cryptoCurrency = CryptoCurrencyFactory().createCoin(
|
||||
val excludedBlockchains = store.inject(DaggerGraphState::excludedBlockchains)
|
||||
|
||||
val cryptoCurrency = CryptoCurrencyFactory(excludedBlockchains).createCoin(
|
||||
blockchain = blockchain,
|
||||
extraDerivationPath = null,
|
||||
scanResponse = scanResponse,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.network.exchangeServices
|
|||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
|
|
@ -10,9 +11,11 @@ import com.tangem.tap.proxy.redux.DaggerGraphState
|
|||
import com.tangem.tap.store
|
||||
import com.tangem.utils.converter.TwoWayConverter
|
||||
|
||||
internal class CryptoCurrencyConverter : TwoWayConverter<Currency, CryptoCurrency> {
|
||||
internal class CryptoCurrencyConverter(
|
||||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
) : TwoWayConverter<Currency, CryptoCurrency> {
|
||||
|
||||
private val cryptoCurrencyFactory by lazy { CryptoCurrencyFactory() }
|
||||
private val cryptoCurrencyFactory by lazy { CryptoCurrencyFactory(excludedBlockchains) }
|
||||
|
||||
override fun convert(value: Currency): CryptoCurrency {
|
||||
return when (value) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.tap.network.exchangeServices
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
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
|
||||
|
|
@ -25,9 +26,10 @@ internal class DefaultRampManager(
|
|||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
) : RampStateManager {
|
||||
|
||||
private val cryptoCurrencyConverter = CryptoCurrencyConverter()
|
||||
private val cryptoCurrencyConverter = CryptoCurrencyConverter(excludedBlockchains)
|
||||
|
||||
override fun isSellSupportedByService(cryptoCurrency: CryptoCurrency): Boolean {
|
||||
return exchangeService?.availableForSell(
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.proxy.redux
|
|||
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.blockchainsdk.signer.TransactionSignerFactory
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.core.navigation.share.ShareManager
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
|
|
@ -71,4 +72,5 @@ data class DaggerGraphState(
|
|||
val onrampFeatureToggles: OnrampFeatureToggles? = null,
|
||||
val environmentConfigStorage: EnvironmentConfigStorage? = null,
|
||||
val onboardingV2FeatureToggles: OnboardingV2FeatureToggles? = null,
|
||||
val excludedBlockchains: ExcludedBlockchains? = null,
|
||||
) : StateType
|
||||
|
|
@ -3,6 +3,7 @@ package com.tangem.tap.domain.card
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.FeePaidCurrency
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.toNetworkId
|
||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||
import com.tangem.data.common.currency.getNetworkDerivationPath
|
||||
|
|
@ -17,7 +18,7 @@ import com.tangem.domain.tokens.model.Network
|
|||
*/
|
||||
internal class CryptoCurrenciesMocks(private val scanResponse: ScanResponse) {
|
||||
|
||||
private val factory = CryptoCurrencyFactory()
|
||||
private val factory = CryptoCurrencyFactory(excludedBlockchains = ExcludedBlockchains())
|
||||
|
||||
val cardano by lazy { listOf(createCoin(blockchain = Blockchain.Cardano)) }
|
||||
val chia by lazy { listOf(element = createCoin(Blockchain.Chia)) }
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.tap.domain.card
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.card.ScanCardException
|
||||
|
|
@ -29,6 +30,7 @@ internal class DefaultDerivationsRepositoryTest {
|
|||
tangemSdkManager = tangemSdkManager,
|
||||
userWalletsStore = userWalletsStore,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
excludedBlockchains = ExcludedBlockchains(),
|
||||
)
|
||||
|
||||
private val defaultUserWalletId = UserWalletId("011")
|
||||
|
|
|
|||
|
|
@ -37,4 +37,10 @@ data class ExpressErrorValue(
|
|||
|
||||
@Json(name = "expressFromDecimals")
|
||||
val expressFromDecimals: Int?,
|
||||
|
||||
@Json(name = "fromAmount")
|
||||
val fromAmount: String?,
|
||||
|
||||
@Json(name = "fromAmountProvider")
|
||||
val fromAmountProvider: String?,
|
||||
)
|
||||
|
|
@ -10,6 +10,8 @@ import androidx.datastore.preferences.core.Preferences
|
|||
import androidx.datastore.preferences.core.emptyPreferences
|
||||
import androidx.datastore.preferences.preferencesDataStoreFile
|
||||
import com.tangem.datasource.local.preferences.PreferencesDataStore.INSTANCE
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys.APP_LOGS_KEY
|
||||
import com.tangem.datasource.local.preferences.utils.CleanupKeyMigration
|
||||
import com.tangem.datasource.local.preferences.utils.SharedPreferencesKeyMigration
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
|
|
@ -77,6 +79,7 @@ internal object PreferencesDataStore {
|
|||
legacyKeyName = LEGACY_DEFAULT_KEY_NAME,
|
||||
keyName = PreferencesKeys.BALANCE_HIDING_SETTINGS_KEY.name,
|
||||
),
|
||||
CleanupKeyMigration(key = APP_LOGS_KEY),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.datasource.local.preferences.utils
|
||||
|
||||
import androidx.datastore.core.DataMigration
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
|
||||
internal class CleanupKeyMigration<T>(private val key: Preferences.Key<T>) : DataMigration<Preferences> {
|
||||
|
||||
override suspend fun cleanUp() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
override suspend fun shouldMigrate(currentData: Preferences): Boolean = currentData.contains(key)
|
||||
|
||||
override suspend fun migrate(currentData: Preferences): Preferences {
|
||||
currentData.toMutablePreferences().remove(key)
|
||||
return currentData
|
||||
}
|
||||
}
|
||||
|
|
@ -891,6 +891,7 @@
|
|||
<string name="tokens_list_unavailable_to_purchase_header">Nicht verfügbar zum Kauf</string>
|
||||
<string name="tokens_list_unavailable_to_sell_header">Nicht zum Verkauf verfügbar</string>
|
||||
<string name="tokens_list_unavailable_to_swap_header">Nicht verfügbar für Tausch von %s</string>
|
||||
<string name="tokens_list_unavailable_to_swap_source_header">Nicht zum Tausch verfügbar</string>
|
||||
<string name="transaction_history_contract_address">Vertrag: %s</string>
|
||||
<string name="transaction_history_empty_transactions">Du hast noch keine Transaktionen</string>
|
||||
<string name="transaction_history_error_failed_to_load">Der Transaktionsverlauf konnte nicht geladen werden.\nKlicke auf die Schaltfläche Neu laden, um die Informationen zu aktualisieren.</string>
|
||||
|
|
|
|||
|
|
@ -882,6 +882,7 @@
|
|||
<string name="tokens_list_unavailable_to_purchase_header">買付できません</string>
|
||||
<string name="tokens_list_unavailable_to_sell_header">売却できません</string>
|
||||
<string name="tokens_list_unavailable_to_swap_header">%sからのスワップは利用できません</string>
|
||||
<string name="tokens_list_unavailable_to_swap_source_header">スワップはできません</string>
|
||||
<string name="transaction_history_contract_address">コントラクト: %s</string>
|
||||
<string name="transaction_history_empty_transactions">まだ取引はありません</string>
|
||||
<string name="transaction_history_error_failed_to_load">取引履歴の読み込みに失敗しました。\n情報を更新するには、リロードボタンをクリックしてください。</string>
|
||||
|
|
|
|||
|
|
@ -914,6 +914,7 @@
|
|||
<string name="tokens_list_unavailable_to_purchase_header">Недоступно для покупки</string>
|
||||
<string name="tokens_list_unavailable_to_sell_header">Недоступно для продажи</string>
|
||||
<string name="tokens_list_unavailable_to_swap_header">Недоступно для обмена с %s</string>
|
||||
<string name="tokens_list_unavailable_to_swap_source_header">Недоступно для обмена</string>
|
||||
<string name="transaction_history_contract_address">контракт: %s</string>
|
||||
<string name="transaction_history_empty_transactions">У вас еще нет транзакций</string>
|
||||
<string name="transaction_history_error_failed_to_load">Не удалось загрузить историю транзакций.\nНажмите на кнопку перезагрузки, чтобы обновить информацию.</string>
|
||||
|
|
|
|||
|
|
@ -898,6 +898,7 @@
|
|||
<string name="tokens_list_unavailable_to_purchase_header">Unavailable to purchase</string>
|
||||
<string name="tokens_list_unavailable_to_sell_header">Unavailable to sell</string>
|
||||
<string name="tokens_list_unavailable_to_swap_header">Unavailable for swap from %s</string>
|
||||
<string name="tokens_list_unavailable_to_swap_source_header">Unavailable for swap</string>
|
||||
<string name="transaction_history_contract_address">contract: %s</string>
|
||||
<string name="transaction_history_empty_transactions">You don\'t have any transactions yet</string>
|
||||
<string name="transaction_history_error_failed_to_load">Failed to load transaction history.\nClick on reload button to update the information.</string>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.core.ui.components.tokenlist
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -10,6 +11,7 @@ import com.tangem.core.ui.components.tokenlist.internal.GroupTitleItem
|
|||
import com.tangem.core.ui.components.tokenlist.internal.NetworkTitleItem
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
|
||||
/**
|
||||
* Multi-currency content item
|
||||
|
|
@ -39,5 +41,13 @@ fun TokenListItem(state: TokensListItemUM, isBalanceHidden: Boolean, modifier: M
|
|||
is TokensListItemUM.SearchBar -> {
|
||||
SearchBar(state = state.searchBarUM, modifier = modifier.padding(all = 12.dp))
|
||||
}
|
||||
is TokensListItemUM.Text -> {
|
||||
Text(
|
||||
text = state.text.resolveReference(),
|
||||
modifier = modifier.padding(all = 12.dp),
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
style = TangemTheme.typography.body2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -48,4 +48,6 @@ sealed interface TokensListItemUM {
|
|||
data class Token(val state: TokenItemState) : TokensListItemUM {
|
||||
override val id: String = state.id
|
||||
}
|
||||
|
||||
data class Text(override val id: Any, val text: TextReference) : TokensListItemUM
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.data.common.currency
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.blockchainsdk.utils.toCoinId
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -10,7 +11,9 @@ import timber.log.Timber
|
|||
import com.tangem.blockchain.common.Token as SdkToken
|
||||
|
||||
// FIXME: Make internal
|
||||
class CryptoCurrencyFactory {
|
||||
class CryptoCurrencyFactory(
|
||||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
) {
|
||||
|
||||
@Suppress("LongParameterList") // Yep, it's long
|
||||
fun createToken(
|
||||
|
|
@ -46,7 +49,7 @@ class CryptoCurrencyFactory {
|
|||
return null
|
||||
}
|
||||
|
||||
val network = getNetwork(blockchain, extraDerivationPath, scanResponse) ?: return null
|
||||
val network = getNetwork(blockchain, extraDerivationPath, scanResponse, excludedBlockchains) ?: return null
|
||||
val id = getTokenId(network, sdkToken)
|
||||
|
||||
return CryptoCurrency.Token(
|
||||
|
|
@ -70,7 +73,7 @@ class CryptoCurrencyFactory {
|
|||
Timber.e("Unable to map the SDK token to the domain token with Unknown blockchain")
|
||||
return null
|
||||
}
|
||||
val network = getNetwork(blockchain, extraDerivationPath, scanResponse) ?: return null
|
||||
val network = getNetwork(blockchain, extraDerivationPath, scanResponse, excludedBlockchains) ?: return null
|
||||
|
||||
return createCoin(network)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.data.common.currency
|
|||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.FeePaidCurrency
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.toNetworkId
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.extensions.canHandleToken
|
||||
|
|
@ -19,10 +20,10 @@ fun getNetwork(
|
|||
blockchain: Blockchain,
|
||||
extraDerivationPath: String?,
|
||||
derivationStyleProvider: DerivationStyleProvider?,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
canHandleTokens: Boolean,
|
||||
): Network? {
|
||||
if (blockchain == Blockchain.Unknown) {
|
||||
Timber.e("Unable to convert Unknown blockchain to the domain network model")
|
||||
if (!isBlockchainSupported(blockchain, excludedBlockchains)) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
@ -43,10 +44,14 @@ fun getNetwork(
|
|||
)
|
||||
}
|
||||
|
||||
fun getNetwork(networkId: Network.ID, derivationPath: Network.DerivationPath, scanResponse: ScanResponse): Network? {
|
||||
fun getNetwork(
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
scanResponse: ScanResponse,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): Network? {
|
||||
val blockchain = getBlockchain(networkId)
|
||||
if (blockchain == Blockchain.Unknown) {
|
||||
Timber.e("Unable to convert Unknown blockchain to the domain network model")
|
||||
if (!isBlockchainSupported(blockchain, excludedBlockchains)) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
@ -59,16 +64,43 @@ fun getNetwork(networkId: Network.ID, derivationPath: Network.DerivationPath, sc
|
|||
currencySymbol = blockchain.currency,
|
||||
standardType = getNetworkStandardType(blockchain),
|
||||
hasFiatFeeRate = blockchain.feePaidCurrency() !is FeePaidCurrency.FeeResource,
|
||||
canHandleTokens = scanResponse.card.canHandleToken(blockchain, scanResponse.cardTypesResolver),
|
||||
canHandleTokens = scanResponse.card.canHandleToken(
|
||||
blockchain,
|
||||
scanResponse.cardTypesResolver,
|
||||
excludedBlockchains,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun getNetwork(blockchain: Blockchain, extraDerivationPath: String?, scanResponse: ScanResponse): Network? {
|
||||
private fun isBlockchainSupported(blockchain: Blockchain, excludedBlockchains: ExcludedBlockchains): Boolean {
|
||||
if (blockchain == Blockchain.Unknown) {
|
||||
Timber.w("Unable to convert Unknown blockchain to the domain network model")
|
||||
return false
|
||||
}
|
||||
if (blockchain in excludedBlockchains) {
|
||||
Timber.w("Unable to convert excluded blockchain to the domain network model")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun getNetwork(
|
||||
blockchain: Blockchain,
|
||||
extraDerivationPath: String?,
|
||||
scanResponse: ScanResponse,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): Network? {
|
||||
return getNetwork(
|
||||
blockchain = blockchain,
|
||||
extraDerivationPath = extraDerivationPath,
|
||||
derivationStyleProvider = scanResponse.derivationStyleProvider,
|
||||
canHandleTokens = scanResponse.card.canHandleToken(blockchain, scanResponse.cardTypesResolver),
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
canHandleTokens = scanResponse.card.canHandleToken(
|
||||
blockchain,
|
||||
scanResponse.cardTypesResolver,
|
||||
excludedBlockchains,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.data.common.currency
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchainsdk.compatibility.l2BlockchainsList
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.blockchainsdk.utils.toCoinId
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
|
|
@ -12,7 +13,9 @@ import com.tangem.domain.tokens.model.CryptoCurrency
|
|||
import timber.log.Timber
|
||||
import com.tangem.blockchain.common.Token as SdkToken
|
||||
|
||||
class ResponseCryptoCurrenciesFactory {
|
||||
class ResponseCryptoCurrenciesFactory(
|
||||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
) {
|
||||
|
||||
fun createCurrency(currencyId: String, response: UserTokensResponse, scanResponse: ScanResponse): CryptoCurrency {
|
||||
return response.tokens
|
||||
|
|
@ -65,7 +68,12 @@ class ResponseCryptoCurrenciesFactory {
|
|||
responseToken: UserTokensResponse.Token,
|
||||
scanResponse: ScanResponse,
|
||||
): CryptoCurrency.Coin? {
|
||||
val network = getNetwork(blockchain, responseToken.derivationPath, scanResponse) ?: return null
|
||||
val network = getNetwork(
|
||||
blockchain,
|
||||
responseToken.derivationPath,
|
||||
scanResponse,
|
||||
excludedBlockchains,
|
||||
) ?: return null
|
||||
|
||||
return CryptoCurrency.Coin(
|
||||
id = getCoinId(network, blockchain.toCoinId()),
|
||||
|
|
@ -111,8 +119,13 @@ class ResponseCryptoCurrenciesFactory {
|
|||
responseDerivationPath: String?,
|
||||
scanResponse: ScanResponse,
|
||||
): CryptoCurrency.Token? {
|
||||
val network = getNetwork(blockchain, responseDerivationPath, scanResponse)
|
||||
?: return null
|
||||
val network = getNetwork(
|
||||
blockchain,
|
||||
responseDerivationPath,
|
||||
scanResponse,
|
||||
excludedBlockchains,
|
||||
) ?: return null
|
||||
|
||||
val id = getTokenId(network, sdkToken)
|
||||
|
||||
return CryptoCurrency.Token(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.data.managetokens
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.toNetworkId
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.data.common.api.safeApiCall
|
||||
|
|
@ -36,10 +37,11 @@ internal class DefaultCustomTokensRepository(
|
|||
private val userWalletsStore: UserWalletsStore,
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : CustomTokensRepository {
|
||||
|
||||
private val cryptoCurrencyFactory = CryptoCurrencyFactory()
|
||||
private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains)
|
||||
private val userTokensResponseFactory = UserTokensResponseFactory()
|
||||
private val tokenAddressConverter = TokenAddressesConverter()
|
||||
private val userTokensBackwardCompatibility = UserTokensBackwardCompatibility()
|
||||
|
|
@ -87,7 +89,9 @@ internal class DefaultCustomTokensRepository(
|
|||
val userWallet = requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
|
||||
"User wallet [$userWalletId] not found while finding token"
|
||||
}
|
||||
val network = requireNotNull(getNetwork(networkId, derivationPath, userWallet.scanResponse)) {
|
||||
val network = requireNotNull(
|
||||
getNetwork(networkId, derivationPath, userWallet.scanResponse, excludedBlockchains),
|
||||
) {
|
||||
"Network [$networkId] not found while finding token"
|
||||
}
|
||||
val tokenAddress = tokenAddressConverter.convertTokenAddress(
|
||||
|
|
@ -97,7 +101,7 @@ internal class DefaultCustomTokensRepository(
|
|||
)
|
||||
|
||||
val supportedTokenNetworkIds = userWallet.scanResponse.card
|
||||
.supportedBlockchains(userWallet.scanResponse.cardTypesResolver)
|
||||
.supportedBlockchains(userWallet.scanResponse.cardTypesResolver, excludedBlockchains)
|
||||
.filter(Blockchain::canHandleTokens)
|
||||
.map(Blockchain::toNetworkId)
|
||||
|
||||
|
|
@ -137,7 +141,9 @@ internal class DefaultCustomTokensRepository(
|
|||
val userWallet = requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
|
||||
"User wallet [$userWalletId] not found while creating coin"
|
||||
}
|
||||
val network = requireNotNull(getNetwork(networkId, derivationPath, userWallet.scanResponse)) {
|
||||
val network = requireNotNull(
|
||||
getNetwork(networkId, derivationPath, userWallet.scanResponse, excludedBlockchains),
|
||||
) {
|
||||
"Network [$networkId] not found while creating coin"
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +174,9 @@ internal class DefaultCustomTokensRepository(
|
|||
val userWallet = requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
|
||||
"User wallet [$userWalletId] not found while creating custom token"
|
||||
}
|
||||
val network = requireNotNull(getNetwork(networkId, derivationPath, userWallet.scanResponse)) {
|
||||
val network = requireNotNull(
|
||||
getNetwork(networkId, derivationPath, userWallet.scanResponse, excludedBlockchains),
|
||||
) {
|
||||
"Network [$networkId] not found while creating custom token"
|
||||
}
|
||||
val tokenAddress = tokenAddressConverter.convertTokenAddress(
|
||||
|
|
@ -230,11 +238,18 @@ internal class DefaultCustomTokensRepository(
|
|||
|
||||
Blockchain.entries
|
||||
.mapNotNull { blockchain ->
|
||||
if (scanResponse.card.canHandleBlockchain(blockchain, scanResponse.cardTypesResolver)) {
|
||||
val canHandleBlockchain = scanResponse.card.canHandleBlockchain(
|
||||
blockchain,
|
||||
scanResponse.cardTypesResolver,
|
||||
excludedBlockchains,
|
||||
)
|
||||
|
||||
if (canHandleBlockchain) {
|
||||
getNetwork(
|
||||
blockchain = blockchain,
|
||||
extraDerivationPath = null,
|
||||
scanResponse = scanResponse,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package com.tangem.data.managetokens
|
|||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.compatibility.l2BlockchainsCoinIds
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.blockchainsdk.utils.isSupportedInApp
|
||||
import com.tangem.blockchainsdk.utils.toNetworkId
|
||||
import com.tangem.data.common.api.safeApiCall
|
||||
import com.tangem.data.common.currency.UserTokensResponseFactory
|
||||
|
|
@ -47,12 +47,13 @@ internal class DefaultManageTokensRepository(
|
|||
private val manageTokensUpdateFetcher: ManageTokensUpdateFetcher,
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val testnetTokensStorage: TestnetTokensStorage,
|
||||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : ManageTokensRepository {
|
||||
|
||||
private val managedCryptoCurrencyFactory = ManagedCryptoCurrencyFactory()
|
||||
private val managedCryptoCurrencyFactory = ManagedCryptoCurrencyFactory(excludedBlockchains)
|
||||
private val userTokensResponseFactory = UserTokensResponseFactory()
|
||||
private val cardCurrenciesFactory = CardCryptoCurrenciesFactory(DemoConfig())
|
||||
private val cardCurrenciesFactory = CardCryptoCurrenciesFactory(DemoConfig(), excludedBlockchains)
|
||||
|
||||
// region getTokenListBatchFlow
|
||||
override fun getTokenListBatchFlow(
|
||||
|
|
@ -202,9 +203,9 @@ internal class DefaultManageTokensRepository(
|
|||
|
||||
private fun getSupportedBlockchains(userWallet: UserWallet?): List<Blockchain> {
|
||||
return userWallet?.scanResponse?.let {
|
||||
it.card.supportedBlockchains(it.cardTypesResolver)
|
||||
it.card.supportedBlockchains(it.cardTypesResolver, excludedBlockchains)
|
||||
} ?: Blockchain.entries.filter {
|
||||
!it.isTestnet() && it.isSupportedInApp()
|
||||
!it.isTestnet() && it !in excludedBlockchains
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
|
@ -290,6 +291,7 @@ internal class DefaultManageTokensRepository(
|
|||
val canHandleBlockchain = userWallet.scanResponse.card.canHandleBlockchain(
|
||||
blockchain = blockchain,
|
||||
cardTypesResolver = userWallet.cardTypesResolver,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
)
|
||||
|
||||
return if (!canHandleBlockchain) {
|
||||
|
|
@ -304,7 +306,10 @@ internal class DefaultManageTokensRepository(
|
|||
blockchain: Blockchain,
|
||||
): CurrencyUnsupportedState.Token? {
|
||||
val cardTypesResolver = userWallet.scanResponse.cardTypesResolver
|
||||
val supportedTokens = userWallet.scanResponse.card.supportedTokens(cardTypesResolver)
|
||||
val supportedTokens = userWallet.scanResponse.card.supportedTokens(
|
||||
cardTypesResolver,
|
||||
excludedBlockchains,
|
||||
)
|
||||
|
||||
return when {
|
||||
// refactor this later by moving all this logic in card config
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.data.managetokens.di
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.data.managetokens.DefaultCustomTokensRepository
|
||||
import com.tangem.data.managetokens.DefaultManageTokensRepository
|
||||
import com.tangem.data.managetokens.utils.ManageTokensUpdateFetcher
|
||||
|
|
@ -30,6 +31,7 @@ internal object ManageTokensDataModule {
|
|||
appPreferencesStore: AppPreferencesStore,
|
||||
testnetTokensStorage: TestnetTokensStorage,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): ManageTokensRepository {
|
||||
return DefaultManageTokensRepository(
|
||||
tangemTechApi,
|
||||
|
|
@ -37,6 +39,7 @@ internal object ManageTokensDataModule {
|
|||
manageTokensUpdateFetcher,
|
||||
appPreferencesStore,
|
||||
testnetTokensStorage,
|
||||
excludedBlockchains,
|
||||
dispatchers,
|
||||
)
|
||||
}
|
||||
|
|
@ -49,12 +52,14 @@ internal object ManageTokensDataModule {
|
|||
appPreferencesStore: AppPreferencesStore,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): CustomTokensRepository {
|
||||
return DefaultCustomTokensRepository(
|
||||
tangemTechApi,
|
||||
userWalletsStore,
|
||||
appPreferencesStore,
|
||||
walletManagersFacade,
|
||||
excludedBlockchains,
|
||||
dispatchers,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import com.tangem.blockchain.common.Blockchain
|
|||
import com.tangem.blockchainsdk.compatibility.applyL2Compatibility
|
||||
import com.tangem.blockchainsdk.compatibility.getL2CompatibilityTokenComparison
|
||||
import com.tangem.blockchainsdk.compatibility.l2BlockchainsList
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.blockchainsdk.utils.isSupportedInApp
|
||||
import com.tangem.blockchainsdk.utils.toCoinId
|
||||
import com.tangem.data.common.currency.getCoinId
|
||||
import com.tangem.data.common.currency.getNetwork
|
||||
|
|
@ -22,7 +22,9 @@ import com.tangem.domain.managetokens.model.ManagedCryptoCurrency.SourceNetwork
|
|||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
|
||||
internal class ManagedCryptoCurrencyFactory {
|
||||
internal class ManagedCryptoCurrencyFactory(
|
||||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
) {
|
||||
|
||||
fun create(
|
||||
coinsResponse: CoinsResponse,
|
||||
|
|
@ -88,7 +90,7 @@ internal class ManagedCryptoCurrencyFactory {
|
|||
scanResponse: ScanResponse,
|
||||
): ManagedCryptoCurrency? {
|
||||
val blockchain = Blockchain.fromNetworkId(token.networkId)
|
||||
?.takeIf { it.isSupportedInApp() }
|
||||
?.takeUnless { it in excludedBlockchains }
|
||||
?: return null
|
||||
|
||||
if (!checkIsCustomToken(token, blockchain, scanResponse.derivationStyleProvider)) {
|
||||
|
|
@ -99,6 +101,7 @@ internal class ManagedCryptoCurrencyFactory {
|
|||
blockchain = blockchain,
|
||||
extraDerivationPath = token.derivationPath,
|
||||
scanResponse = scanResponse,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
) ?: return null
|
||||
val contractAddress = token.contractAddress
|
||||
|
||||
|
|
@ -161,15 +164,16 @@ internal class ManagedCryptoCurrencyFactory {
|
|||
extraDerivationPath: String? = null,
|
||||
): SourceNetwork? {
|
||||
val blockchain = Blockchain.fromNetworkId(networkId)
|
||||
?.takeIf { it.isSupportedInApp() }
|
||||
?.takeUnless { it in excludedBlockchains }
|
||||
?: return null
|
||||
|
||||
val network = getNetwork(
|
||||
blockchain,
|
||||
extraDerivationPath,
|
||||
scanResponse?.derivationStyleProvider,
|
||||
excludedBlockchains,
|
||||
canHandleTokens = scanResponse?.let {
|
||||
it.card.canHandleToken(blockchain, it.cardTypesResolver)
|
||||
it.card.canHandleToken(blockchain, it.cardTypesResolver, excludedBlockchains)
|
||||
} ?: true,
|
||||
) ?: return null
|
||||
|
||||
|
|
@ -200,13 +204,14 @@ internal class ManagedCryptoCurrencyFactory {
|
|||
.mapNotNullTo(mutableSetOf()) { token ->
|
||||
val blockchain = Blockchain.fromNetworkId(token.networkId)
|
||||
|
||||
if (blockchain != null && blockchain.isSupportedInApp()) {
|
||||
if (blockchain != null && blockchain !in excludedBlockchains) {
|
||||
getNetwork(
|
||||
blockchain,
|
||||
token.derivationPath,
|
||||
scanResponse?.derivationStyleProvider,
|
||||
excludedBlockchains,
|
||||
canHandleTokens = scanResponse?.let {
|
||||
it.card.canHandleToken(blockchain, it.cardTypesResolver)
|
||||
it.card.canHandleToken(blockchain, it.cardTypesResolver, excludedBlockchains)
|
||||
} ?: true,
|
||||
)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ dependencies {
|
|||
implementation(projects.core.pagination)
|
||||
implementation(projects.core.analytics)
|
||||
implementation(projects.core.analytics.models)
|
||||
implementation(projects.core.configToggles)
|
||||
|
||||
implementation(projects.domain.legacy)
|
||||
implementation(projects.domain.markets)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.data.markets
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.compatibility.applyL2Compatibility
|
||||
import com.tangem.blockchainsdk.compatibility.getTokenIdIfL2Network
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
|
|
@ -37,10 +38,14 @@ internal class DefaultMarketsTokenRepository(
|
|||
private val userWalletsStore: UserWalletsStore,
|
||||
private val dispatcherProvider: CoroutineDispatcherProvider,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
private val cacheRegistry: CacheRegistry,
|
||||
private val tokenExchangesStore: RuntimeStateStore<List<TokenMarketExchangesResponse.Exchange>>,
|
||||
) : MarketsTokenRepository {
|
||||
|
||||
private val tokenMarketInfoConverter: TokenMarketInfoConverter = TokenMarketInfoConverter(excludedBlockchains)
|
||||
private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains)
|
||||
|
||||
private fun createTokenMarketsFetcher(firstBatchSize: Int, nextBatchSize: Int) = LimitOffsetBatchFetcher(
|
||||
prefetchDistance = firstBatchSize,
|
||||
batchSize = nextBatchSize,
|
||||
|
|
@ -204,7 +209,7 @@ internal class DefaultMarketsTokenRepository(
|
|||
}
|
||||
|
||||
val resultResponse = result.applyL2Compatibility(tokenId)
|
||||
return@withContext TokenMarketInfoConverter.convert(resultResponse)
|
||||
return@withContext tokenMarketInfoConverter.convert(resultResponse)
|
||||
}
|
||||
|
||||
override suspend fun getTokenQuotes(fiatCurrencyCode: String, tokenId: String, tokenSymbol: String) =
|
||||
|
|
@ -234,7 +239,7 @@ internal class DefaultMarketsTokenRepository(
|
|||
val blockchain = Blockchain.fromNetworkId(network.networkId) ?: error("Unknown network [${network.networkId}]")
|
||||
|
||||
return if (network.contractAddress == null) {
|
||||
CryptoCurrencyFactory().createCoin(
|
||||
cryptoCurrencyFactory.createCoin(
|
||||
blockchain = blockchain,
|
||||
extraDerivationPath = null,
|
||||
scanResponse = userWallet.scanResponse,
|
||||
|
|
@ -244,9 +249,10 @@ internal class DefaultMarketsTokenRepository(
|
|||
blockchain = blockchain,
|
||||
extraDerivationPath = null,
|
||||
scanResponse = userWallet.scanResponse,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
) ?: return null
|
||||
|
||||
CryptoCurrencyFactory().createToken(
|
||||
cryptoCurrencyFactory.createToken(
|
||||
network = currencyNetwork,
|
||||
rawId = token.id,
|
||||
name = token.name,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package com.tangem.data.markets.converters
|
|||
|
||||
import android.net.Uri
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.blockchainsdk.utils.isSupportedInApp
|
||||
import com.tangem.datasource.api.markets.models.response.TokenMarketInfoResponse
|
||||
import com.tangem.domain.markets.BuildConfig
|
||||
import com.tangem.domain.markets.TokenMarketInfo
|
||||
|
|
@ -11,10 +11,9 @@ import com.tangem.domain.markets.TokenQuotes
|
|||
import com.tangem.utils.converter.Converter
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal object TokenMarketInfoConverter : Converter<TokenMarketInfoResponse, TokenMarketInfo> {
|
||||
|
||||
private const val PROD_IMAGE_HOST = "https://s3.eu-central-1.amazonaws.com/tangem.api/security_provider/"
|
||||
private const val DEV_IMAGE_HOST = "https://s3.eu-central-1.amazonaws.com/tangem.api.dev/security_provider/"
|
||||
internal class TokenMarketInfoConverter(
|
||||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
) : Converter<TokenMarketInfoResponse, TokenMarketInfo> {
|
||||
|
||||
override fun convert(value: TokenMarketInfoResponse): TokenMarketInfo {
|
||||
return with(value) {
|
||||
|
|
@ -68,7 +67,8 @@ internal object TokenMarketInfoConverter : Converter<TokenMarketInfoResponse, To
|
|||
decimalCount = network.decimalCount,
|
||||
)
|
||||
}
|
||||
blockchain != null && blockchain.isSupportedInApp() && blockchain.canHandleTokens() -> {
|
||||
blockchain != null && blockchain !in excludedBlockchains &&
|
||||
blockchain.canHandleTokens() -> {
|
||||
TokenMarketInfo.Network(
|
||||
networkId = network.networkId,
|
||||
exchangeable = network.exchangeable,
|
||||
|
|
@ -193,4 +193,10 @@ internal object TokenMarketInfoConverter : Converter<TokenMarketInfoResponse, To
|
|||
PROD_IMAGE_HOST
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
const val PROD_IMAGE_HOST = "https://s3.eu-central-1.amazonaws.com/tangem.api/security_provider/"
|
||||
const val DEV_IMAGE_HOST = "https://s3.eu-central-1.amazonaws.com/tangem.api.dev/security_provider/"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.data.markets.di
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.markets.DefaultMarketsTokenRepository
|
||||
|
|
@ -28,6 +29,7 @@ internal object MarketsDataModule {
|
|||
dispatchers: CoroutineDispatcherProvider,
|
||||
analyticsEventHandler: AnalyticsEventHandler,
|
||||
cacheRegistry: CacheRegistry,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): MarketsTokenRepository {
|
||||
return DefaultMarketsTokenRepository(
|
||||
marketsApi = marketsApi,
|
||||
|
|
@ -37,6 +39,7 @@ internal object MarketsDataModule {
|
|||
analyticsEventHandler = analyticsEventHandler,
|
||||
cacheRegistry = cacheRegistry,
|
||||
tokenExchangesStore = RuntimeStateStore(defaultValue = emptyList()),
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.data.tokens.di
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.tokens.repository.*
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
|
|
@ -31,6 +32,7 @@ internal object TokensDataModule {
|
|||
cacheRegistry: CacheRegistry,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
swapServiceLoader: SwapServiceLoader,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): CurrenciesRepository {
|
||||
return DefaultCurrenciesRepository(
|
||||
tangemTechApi = tangemTechApi,
|
||||
|
|
@ -40,6 +42,7 @@ internal object TokensDataModule {
|
|||
appPreferencesStore = appPreferencesStore,
|
||||
dispatchers = dispatchers,
|
||||
swapServiceLoader = swapServiceLoader,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -70,6 +73,7 @@ internal object TokensDataModule {
|
|||
appPreferencesStore: AppPreferencesStore,
|
||||
cacheRegistry: CacheRegistry,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): NetworksRepository {
|
||||
return DefaultNetworksRepository(
|
||||
networksStatusesStore = networksStatusesStore,
|
||||
|
|
@ -78,6 +82,7 @@ internal object TokensDataModule {
|
|||
appPreferencesStore = appPreferencesStore,
|
||||
cacheRegistry = cacheRegistry,
|
||||
dispatchers = dispatchers,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.data.tokens.repository
|
|||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.compatibility.getL2CompatibilityTokenComparison
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.toCoinId
|
||||
import com.tangem.blockchainsdk.utils.toNetworkId
|
||||
import com.tangem.data.common.api.safeApiCall
|
||||
|
|
@ -48,12 +49,13 @@ internal class DefaultCurrenciesRepository(
|
|||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val swapServiceLoader: SwapServiceLoader,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
) : CurrenciesRepository {
|
||||
|
||||
private val demoConfig = DemoConfig()
|
||||
private val responseCurrenciesFactory = ResponseCryptoCurrenciesFactory()
|
||||
private val cryptoCurrencyFactory = CryptoCurrencyFactory()
|
||||
private val cardCurrenciesFactory = CardCryptoCurrenciesFactory(demoConfig)
|
||||
private val responseCurrenciesFactory = ResponseCryptoCurrenciesFactory(excludedBlockchains)
|
||||
private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains)
|
||||
private val cardCurrenciesFactory = CardCryptoCurrenciesFactory(demoConfig, excludedBlockchains)
|
||||
private val userTokensResponseFactory = UserTokensResponseFactory()
|
||||
private val userTokensBackwardCompatibility = UserTokensBackwardCompatibility()
|
||||
private val customTokensMerger = CustomTokensMerger(tangemTechApi, dispatchers)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.tangem.data.tokens.repository
|
|||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
|
||||
|
|
@ -39,12 +40,13 @@ internal class DefaultNetworksRepository(
|
|||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val cacheRegistry: CacheRegistry,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
) : NetworksRepository {
|
||||
|
||||
private val demoConfig by lazy { DemoConfig() }
|
||||
private val cardCurrenciesFactory by lazy { CardCryptoCurrenciesFactory(demoConfig) }
|
||||
private val responseCurrenciesFactory by lazy { ResponseCryptoCurrenciesFactory() }
|
||||
private val networkStatusFactory by lazy { NetworkStatusFactory() }
|
||||
private val demoConfig = DemoConfig()
|
||||
private val cardCurrenciesFactory = CardCryptoCurrenciesFactory(demoConfig, excludedBlockchains)
|
||||
private val responseCurrenciesFactory = ResponseCryptoCurrenciesFactory(excludedBlockchains)
|
||||
private val networkStatusFactory = NetworkStatusFactory()
|
||||
|
||||
override fun getNetworkStatusesUpdates(
|
||||
userWalletId: UserWalletId,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.data.tokens.utils
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||
import com.tangem.domain.common.TapWorkarounds.isTestCard
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
|
|
@ -8,9 +9,12 @@ import com.tangem.domain.demo.DemoConfig
|
|||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
||||
class CardCryptoCurrenciesFactory(private val demoConfig: DemoConfig) {
|
||||
class CardCryptoCurrenciesFactory(
|
||||
private val demoConfig: DemoConfig,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
) {
|
||||
|
||||
private val cryptoCurrencyFactory = CryptoCurrencyFactory()
|
||||
private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains)
|
||||
|
||||
fun createDefaultCoinsForMultiCurrencyCard(scanResponse: ScanResponse): List<CryptoCurrency.Coin> {
|
||||
val card = scanResponse.card
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.domain.common.extensions
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.isSupportedInApp
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.common.card.FirmwareVersion
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
|
|
@ -15,7 +15,10 @@ import com.tangem.domain.models.scan.CardDTO
|
|||
val FirmwareVersion.Companion.SolanaTokensAvailable
|
||||
get() = FirmwareVersion(4, 52)
|
||||
|
||||
fun CardDTO.supportedBlockchains(cardTypesResolver: CardTypesResolver): List<Blockchain> {
|
||||
fun CardDTO.supportedBlockchains(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): List<Blockchain> {
|
||||
val supportedBlockchains = if (firmwareVersion < FirmwareVersion.MultiWalletAvailable) {
|
||||
Blockchain.fromCurve(EllipticCurve.Secp256k1).toMutableList()
|
||||
} else if (!cardTypesResolver.isWallet2() && !cardTypesResolver.isTangemWallet()) {
|
||||
|
|
@ -27,11 +30,14 @@ fun CardDTO.supportedBlockchains(cardTypesResolver: CardTypesResolver): List<Blo
|
|||
}
|
||||
return supportedBlockchains
|
||||
.filter { isTestCard == it.isTestnet() }
|
||||
.filter { it.isSupportedInApp() }
|
||||
.filter { it !in excludedBlockchains }
|
||||
}
|
||||
|
||||
fun CardDTO.supportedTokens(cardTypesResolver: CardTypesResolver): List<Blockchain> {
|
||||
val tokensSupportedByBlockchain = supportedBlockchains(cardTypesResolver)
|
||||
fun CardDTO.supportedTokens(
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): List<Blockchain> {
|
||||
val tokensSupportedByBlockchain = supportedBlockchains(cardTypesResolver, excludedBlockchains)
|
||||
.filter { it.canHandleTokens() }
|
||||
.toMutableList()
|
||||
val tokensSupportedByCard = when {
|
||||
|
|
@ -68,10 +74,14 @@ fun CardDTO.canHandleToken(
|
|||
}
|
||||
}
|
||||
|
||||
fun CardDTO.canHandleToken(blockchain: Blockchain, cardTypesResolver: CardTypesResolver): Boolean {
|
||||
fun CardDTO.canHandleToken(
|
||||
blockchain: Blockchain,
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): Boolean {
|
||||
val cardConfig = CardConfig.createConfig(this)
|
||||
val primaryCurveForBlockchain = cardConfig.primaryCurve(blockchain)
|
||||
val isContainsBlockchain = this.supportedTokens(cardTypesResolver).contains(blockchain)
|
||||
val isContainsBlockchain = blockchain in supportedTokens(cardTypesResolver, excludedBlockchains)
|
||||
val isWalletForCurveExists = wallets.any { it.curve == primaryCurveForBlockchain }
|
||||
// fixme: check for first wallets with 1 curve and remove condition
|
||||
return if (cardTypesResolver.isTangemWallet() || cardTypesResolver.isWallet2()) {
|
||||
|
|
@ -82,10 +92,14 @@ fun CardDTO.canHandleToken(blockchain: Blockchain, cardTypesResolver: CardTypesR
|
|||
}
|
||||
}
|
||||
|
||||
fun CardDTO.canHandleBlockchain(blockchain: Blockchain, cardTypesResolver: CardTypesResolver): Boolean {
|
||||
fun CardDTO.canHandleBlockchain(
|
||||
blockchain: Blockchain,
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): Boolean {
|
||||
val cardConfig = CardConfig.createConfig(this)
|
||||
val primaryCurveForBlockchain = cardConfig.primaryCurve(blockchain)
|
||||
val isContainsBlockchain = this.supportedBlockchains(cardTypesResolver).contains(blockchain)
|
||||
val isContainsBlockchain = blockchain in supportedBlockchains(cardTypesResolver, excludedBlockchains)
|
||||
val isWalletForCurveExists = wallets.any { it.curve == primaryCurveForBlockchain }
|
||||
// fixme: check for first wallets with 1 curve and remove condition
|
||||
return if (cardTypesResolver.isTangemWallet() || cardTypesResolver.isWallet2()) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.features.markets.details.impl.model
|
|||
import androidx.compose.runtime.Stable
|
||||
import arrow.core.Either
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.common.ui.charts.state.MarketChartData
|
||||
import com.tangem.common.ui.charts.state.MarketChartDataProducer
|
||||
import com.tangem.common.ui.charts.state.sorted
|
||||
|
|
@ -64,6 +65,7 @@ internal class MarketsTokenDetailsModel @Inject constructor(
|
|||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val urlOpener: UrlOpener,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
) : Model() {
|
||||
|
||||
private var quotesJob = JobHolder()
|
||||
|
|
@ -400,7 +402,7 @@ internal class MarketsTokenDetailsModel @Inject constructor(
|
|||
}
|
||||
|
||||
val networks = newInfo.networks?.filter {
|
||||
BlockchainUtils.isSupportedNetworkId(it.networkId)
|
||||
BlockchainUtils.isSupportedNetworkId(it.networkId, excludedBlockchains)
|
||||
}
|
||||
|
||||
networksState.value = if (networks.isNullOrEmpty()) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import com.tangem.features.onramp.swap.availablepairs.AvailableSwapPairsComponen
|
|||
import com.tangem.features.onramp.swap.availablepairs.entity.transformers.SetLoadingTokenItemsTransformer
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMController
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.SetNothingToFoundStateTransformer
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.UpdateTokenItemsTransformer
|
||||
import com.tangem.features.onramp.utils.InputManager
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer
|
||||
|
|
@ -80,24 +81,35 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
} else {
|
||||
val (appCurrency, isBalanceHidden) = appCurrencyAndBalanceHiding
|
||||
|
||||
val filterTokenList = currencies
|
||||
val filterByQueryTokenList = currencies
|
||||
.filter { it.currency != selectedStatus?.currency }
|
||||
.filterByQuery(query = query)
|
||||
.filterByAvailability(availablePairs = availablePairs)
|
||||
|
||||
UpdateTokenItemsTransformer(
|
||||
appCurrency = appCurrency,
|
||||
onItemClick = params.onTokenClick,
|
||||
statuses = filterTokenList,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
hasSearchBar = currencies.isNotEmpty(),
|
||||
unavailableTokensHeaderReference = resourceReference(
|
||||
id = R.string.tokens_list_unavailable_to_swap_header,
|
||||
wrappedList(selectedStatus?.currency?.name?.capitalize() ?: ""),
|
||||
),
|
||||
onQueryChange = ::onSearchQueryChange,
|
||||
onActiveChange = ::onSearchBarActiveChange,
|
||||
)
|
||||
if (query.isNotEmpty() && filterByQueryTokenList.isEmpty()) {
|
||||
SetNothingToFoundStateTransformer(
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
hasSearchBar = currencies.isNotEmpty(),
|
||||
emptySearchMessageReference = resourceReference(
|
||||
id = R.string.action_buttons_swap_empty_search_message,
|
||||
),
|
||||
onQueryChange = ::onSearchQueryChange,
|
||||
onActiveChange = ::onSearchBarActiveChange,
|
||||
)
|
||||
} else {
|
||||
UpdateTokenItemsTransformer(
|
||||
appCurrency = appCurrency,
|
||||
onItemClick = params.onTokenClick,
|
||||
statuses = filterByQueryTokenList.filterByAvailability(availablePairs = availablePairs),
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
hasSearchBar = currencies.isNotEmpty(),
|
||||
unavailableTokensHeaderReference = resourceReference(
|
||||
id = R.string.tokens_list_unavailable_to_swap_header,
|
||||
wrappedList(selectedStatus?.currency?.name?.capitalize() ?: ""),
|
||||
),
|
||||
onQueryChange = ::onSearchQueryChange,
|
||||
onActiveChange = ::onSearchBarActiveChange,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.onEach(tokenListUMController::update)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
package com.tangem.features.onramp.tokenlist.entity.transformer
|
||||
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMTransformer
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class SetNothingToFoundStateTransformer(
|
||||
private val isBalanceHidden: Boolean,
|
||||
private val hasSearchBar: Boolean,
|
||||
private val emptySearchMessageReference: TextReference,
|
||||
private val onQueryChange: (String) -> Unit,
|
||||
private val onActiveChange: (Boolean) -> Unit,
|
||||
) : TokenListUMTransformer {
|
||||
|
||||
override fun transform(prevState: TokenListUM): TokenListUM {
|
||||
val searchBarItem = if (hasSearchBar) {
|
||||
prevState.getSearchBar() ?: createSearchBarItem()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return prevState.copy(
|
||||
availableItems = buildList {
|
||||
if (searchBarItem != null) {
|
||||
add(searchBarItem)
|
||||
}
|
||||
|
||||
createGroupTitle(
|
||||
textReference = resourceReference(id = R.string.exchange_tokens_available_tokens_header),
|
||||
)
|
||||
.let(::add)
|
||||
|
||||
TokensListItemUM.Text(
|
||||
id = emptySearchMessageReference.hashCode(),
|
||||
text = emptySearchMessageReference,
|
||||
).let(::add)
|
||||
}
|
||||
.toImmutableList(),
|
||||
unavailableItems = persistentListOf(),
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createSearchBarItem(): TokensListItemUM.SearchBar {
|
||||
return TokensListItemUM.SearchBar(
|
||||
searchBarUM = SearchBarUM(
|
||||
placeholderText = resourceReference(id = R.string.common_search),
|
||||
query = "",
|
||||
onQueryChange = onQueryChange,
|
||||
isActive = false,
|
||||
onActiveChange = onActiveChange,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createGroupTitle(textReference: TextReference): TokensListItemUM.GroupTitle {
|
||||
return TokensListItemUM.GroupTitle(id = textReference.hashCode(), text = textReference)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ import arrow.core.getOrElse
|
|||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
|
|
@ -19,6 +18,7 @@ import com.tangem.features.onramp.tokenlist.OnrampTokenListComponent
|
|||
import com.tangem.features.onramp.tokenlist.entity.OnrampOperation
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMController
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.SetNothingToFoundStateTransformer
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.UpdateTokenItemsTransformer
|
||||
import com.tangem.features.onramp.utils.InputManager
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer
|
||||
|
|
@ -65,30 +65,38 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
)
|
||||
.flattenCurrencies()
|
||||
|
||||
val filterTokenList = currencies
|
||||
val filterByQueryTokenList = currencies
|
||||
.filterByQuery(query = query)
|
||||
.filterByAvailability()
|
||||
|
||||
UpdateTokenItemsTransformer(
|
||||
appCurrency = appCurrency,
|
||||
onItemClick = params.onTokenClick,
|
||||
statuses = filterTokenList,
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
hasSearchBar = params.hasSearchBar && currencies.isNotEmpty(),
|
||||
unavailableTokensHeaderReference = when (params.filterOperation) {
|
||||
OnrampOperation.BUY -> resourceReference(id = R.string.tokens_list_unavailable_to_purchase_header)
|
||||
OnrampOperation.SELL -> resourceReference(id = R.string.tokens_list_unavailable_to_sell_header)
|
||||
OnrampOperation.SWAP -> {
|
||||
// TODO: [REDACTED_JIRA]
|
||||
resourceReference(
|
||||
id = R.string.tokens_list_unavailable_to_swap_header,
|
||||
wrappedList(""),
|
||||
)
|
||||
if (query.isNotEmpty() && filterByQueryTokenList.isEmpty()) {
|
||||
SetNothingToFoundStateTransformer(
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
hasSearchBar = params.hasSearchBar && currencies.isNotEmpty(),
|
||||
emptySearchMessageReference = when (params.filterOperation) {
|
||||
OnrampOperation.BUY -> R.string.action_buttons_buy_empty_search_message
|
||||
OnrampOperation.SELL -> R.string.action_buttons_sell_empty_search_message
|
||||
OnrampOperation.SWAP -> R.string.action_buttons_swap_empty_search_message
|
||||
}
|
||||
},
|
||||
onQueryChange = ::onSearchQueryChange,
|
||||
onActiveChange = ::onSearchBarActiveChange,
|
||||
)
|
||||
.let(::resourceReference),
|
||||
onQueryChange = ::onSearchQueryChange,
|
||||
onActiveChange = ::onSearchBarActiveChange,
|
||||
)
|
||||
} else {
|
||||
UpdateTokenItemsTransformer(
|
||||
appCurrency = appCurrency,
|
||||
onItemClick = params.onTokenClick,
|
||||
statuses = filterByQueryTokenList.filterByAvailability(),
|
||||
isBalanceHidden = isBalanceHidden,
|
||||
hasSearchBar = params.hasSearchBar && currencies.isNotEmpty(),
|
||||
unavailableTokensHeaderReference = when (params.filterOperation) {
|
||||
OnrampOperation.BUY -> R.string.tokens_list_unavailable_to_purchase_header
|
||||
OnrampOperation.SELL -> R.string.tokens_list_unavailable_to_sell_header
|
||||
OnrampOperation.SWAP -> R.string.tokens_list_unavailable_to_swap_source_header
|
||||
}.let(::resourceReference),
|
||||
onQueryChange = ::onSearchQueryChange,
|
||||
onActiveChange = ::onSearchBarActiveChange,
|
||||
)
|
||||
}
|
||||
}
|
||||
.onEach(tokenListUMController::update)
|
||||
.flowOn(dispatchers.main)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ dependencies {
|
|||
implementation(projects.domain.qrScanning)
|
||||
implementation(projects.domain.qrScanning.models)
|
||||
|
||||
/** Data */
|
||||
implementation(projects.data.card)
|
||||
|
||||
/** Compose */
|
||||
implementation(deps.compose.foundation)
|
||||
implementation(deps.compose.ui)
|
||||
|
|
@ -57,4 +60,5 @@ dependencies {
|
|||
/** Other dependencies */
|
||||
implementation(deps.arrow.core)
|
||||
implementation(deps.timber)
|
||||
implementation(deps.tangem.card.core)
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import androidx.lifecycle.SavedStateHandle
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.data.card.sdk.CardSdkProvider
|
||||
import com.tangem.domain.qrscanning.models.SourceType
|
||||
import com.tangem.feature.qrscanning.navigation.QrScanningInnerRouter
|
||||
import com.tangem.feature.qrscanning.presentation.QrScanningState
|
||||
|
|
@ -20,6 +21,7 @@ import javax.inject.Inject
|
|||
internal class QrScanningViewModel @Inject constructor(
|
||||
private val stateHolder: QrScanningStateController,
|
||||
private val clickIntents: QrScanningClickIntentsImplementor,
|
||||
private val cardSdkProvider: CardSdkProvider,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel() {
|
||||
|
||||
|
|
@ -31,6 +33,12 @@ internal class QrScanningViewModel @Inject constructor(
|
|||
val uiState: StateFlow<QrScanningState> = stateHolder.uiState
|
||||
val launchGalleryEvent: SharedFlow<GalleryRequest> = clickIntents.launchGallery
|
||||
|
||||
init {
|
||||
// samsung for some reason disables reader mode, and then it works unstable
|
||||
// to prevent this disable ir manually before scan QR
|
||||
cardSdkProvider.sdk.forceDisableReaderMode()
|
||||
}
|
||||
|
||||
fun setRouter(router: QrScanningInnerRouter) {
|
||||
clickIntents.initialize(
|
||||
router = router,
|
||||
|
|
@ -49,4 +57,10 @@ internal class QrScanningViewModel @Inject constructor(
|
|||
fun onDismissBottomSheetState() {
|
||||
stateHolder.update(DismissBottomSheetTransformer())
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
// don't forget enable reader mode after scan complete
|
||||
cardSdkProvider.sdk.forceEnableReaderMode()
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.tangem.feature.referral.data
|
|||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
|
|
@ -18,14 +19,18 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class ReferralRepositoryImpl @Inject constructor(
|
||||
private val referralApi: TangemTechApi,
|
||||
private val referralConverter: ReferralConverter,
|
||||
private val coroutineDispatcher: CoroutineDispatcherProvider,
|
||||
private val demoModeDatasource: DemoModeDatasource,
|
||||
private val userWalletsStore: UserWalletsStore,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
) : ReferralRepository {
|
||||
|
||||
private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains)
|
||||
|
||||
override val isDemoMode: Boolean
|
||||
get() = demoModeDatasource.isDemoModeActive
|
||||
|
||||
|
|
@ -65,8 +70,6 @@ internal class ReferralRepositoryImpl @Inject constructor(
|
|||
val blockchain = Blockchain.fromNetworkId(tokenData.networkId)
|
||||
?: error("Blockchain ${tokenData.networkId} not found")
|
||||
|
||||
val cryptoCurrencyFactory = CryptoCurrencyFactory()
|
||||
|
||||
val contractAddress = tokenData.contractAddress
|
||||
val decimalCount = tokenData.decimalCount
|
||||
return if (contractAddress != null && decimalCount != null) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.feature.referral.di
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.demo.DemoModeDatasource
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
|
|
@ -25,6 +26,7 @@ class ReferralRepositoryModule {
|
|||
coroutineDispatcherProvider: CoroutineDispatcherProvider,
|
||||
demoModeDatasource: DemoModeDatasource,
|
||||
userWalletsStore: UserWalletsStore,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): ReferralRepository {
|
||||
return ReferralRepositoryImpl(
|
||||
referralApi = tangemTechApi,
|
||||
|
|
@ -32,6 +34,7 @@ class ReferralRepositoryModule {
|
|||
coroutineDispatcher = coroutineDispatcherProvider,
|
||||
demoModeDatasource = demoModeDatasource,
|
||||
userWalletsStore = userWalletsStore,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -75,6 +75,7 @@ internal class StakingStateController @Inject constructor(
|
|||
walletName = "",
|
||||
cryptoCurrencyName = "",
|
||||
cryptoCurrencySymbol = "",
|
||||
cryptoCurrencyBlockchainId = "",
|
||||
currentStep = StakingStep.InitialInfo,
|
||||
initialInfoState = StakingStates.InitialInfoState.Empty(),
|
||||
amountState = AmountState.Empty(),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
|
|||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.domain.staking.analytics.StakingAnalyticsEvent
|
||||
import com.tangem.features.staking.impl.analytics.utils.StakingAnalyticSender
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isSolana
|
||||
|
||||
internal class StakingStateRouter(
|
||||
private val appRouter: AppRouter,
|
||||
|
|
@ -23,7 +24,13 @@ internal class StakingStateRouter(
|
|||
fun onNextClick() {
|
||||
when (stateController.value.currentStep) {
|
||||
StakingStep.InitialInfo -> when (stateController.value.actionType) {
|
||||
StakingActionCommonType.Enter, StakingActionCommonType.Exit -> showAmount()
|
||||
StakingActionCommonType.Enter -> showAmount()
|
||||
// TODO staking [REDACTED_TASK_KEY] support solana multisize hashes signing
|
||||
StakingActionCommonType.Exit -> if (isSolana(stateController.value.cryptoCurrencyBlockchainId)) {
|
||||
showConfirmation()
|
||||
} else {
|
||||
showAmount()
|
||||
}
|
||||
StakingActionCommonType.Pending.Other,
|
||||
StakingActionCommonType.Pending.Rewards,
|
||||
-> showConfirmation()
|
||||
|
|
@ -50,7 +57,9 @@ internal class StakingStateRouter(
|
|||
val isEnter = uiState.actionType == StakingActionCommonType.Enter
|
||||
val isExit = uiState.actionType == StakingActionCommonType.Exit
|
||||
|
||||
if (isEnter || isExit) {
|
||||
// TODO staking [REDACTED_TASK_KEY] support solana multisize hashes signing
|
||||
val isSolana = isSolana(uiState.cryptoCurrencyBlockchainId)
|
||||
if (isEnter || isExit && !isSolana) {
|
||||
showAmount()
|
||||
} else {
|
||||
showInitial()
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ internal data class StakingUiState(
|
|||
val walletName: String,
|
||||
val cryptoCurrencyName: String,
|
||||
val cryptoCurrencySymbol: String,
|
||||
val cryptoCurrencyBlockchainId: String,
|
||||
val currentStep: StakingStep,
|
||||
val initialInfoState: StakingStates.InitialInfoState,
|
||||
val amountState: AmountState,
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ internal class SetInitialDataStateTransformer(
|
|||
title = TextReference.EMPTY,
|
||||
cryptoCurrencyName = cryptoCurrency.name,
|
||||
cryptoCurrencySymbol = cryptoCurrency.symbol,
|
||||
cryptoCurrencyBlockchainId = cryptoCurrency.network.id.value,
|
||||
clickIntents = clickIntents,
|
||||
currentStep = StakingStep.InitialInfo,
|
||||
initialInfoState = createInitialInfoState(),
|
||||
|
|
|
|||
|
|
@ -40,9 +40,10 @@ internal fun StakingConfirmationContent(
|
|||
validatorState: StakingStates.ValidatorState,
|
||||
clickIntents: StakingClickIntents,
|
||||
type: StakingActionCommonType,
|
||||
isSolana: Boolean, // TODO staking [REDACTED_TASK_KEY] support solana multisize hashes signing
|
||||
) {
|
||||
if (state !is StakingStates.ConfirmationState.Data) return
|
||||
val isAmountEditable = type == StakingActionCommonType.Enter || type == StakingActionCommonType.Exit
|
||||
val isAmountEditable = type == StakingActionCommonType.Enter || type == StakingActionCommonType.Exit && !isSolana
|
||||
val isTransactionSent = state.innerState == InnerConfirmationStakingState.COMPLETED
|
||||
val isTransactionInProgress = state.notifications.any { it is StakingNotification.Warning.TransactionInProgress }
|
||||
Column(
|
||||
|
|
@ -90,6 +91,7 @@ private fun Preview_StakingConfirmationContent() {
|
|||
validatorState = ValidatorStatePreviewData.validatorState,
|
||||
clickIntents = StakingClickIntentsStub,
|
||||
type = StakingActionCommonType.Enter,
|
||||
isSolana = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import com.tangem.features.staking.impl.presentation.state.bottomsheet.StakingAc
|
|||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.StakingInfoBottomSheetConfig
|
||||
import com.tangem.features.staking.impl.presentation.ui.bottomsheet.StakingActionSelectorBottomSheet
|
||||
import com.tangem.features.staking.impl.presentation.ui.bottomsheet.StakingInfoBottomSheet
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isSolana
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
|
@ -170,6 +171,7 @@ private fun StakingScreenContent(uiState: StakingUiState, modifier: Modifier = M
|
|||
validatorState = uiState.validatorState,
|
||||
clickIntents = uiState.clickIntents,
|
||||
type = uiState.actionType,
|
||||
isSolana = isSolana(uiState.cryptoCurrencyBlockchainId),
|
||||
)
|
||||
StakingStep.RestakeValidator,
|
||||
StakingStep.Validators,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import arrow.core.raise.either
|
|||
import arrow.core.right
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
|
|
@ -48,12 +49,13 @@ internal class DefaultSwapRepository(
|
|||
private val errorsDataConverter: ErrorsDataConverter,
|
||||
private val dataSignatureVerifier: DataSignatureVerifier,
|
||||
moshi: Moshi,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
) : SwapRepository {
|
||||
|
||||
private val expressDataConverter = ExpressDataConverter()
|
||||
private val leastTokenInfoConverter = LeastTokenInfoConverter()
|
||||
private val swapPairInfoConverter = SwapPairInfoConverter()
|
||||
private val cryptoCurrencyFactory = CryptoCurrencyFactory()
|
||||
private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains)
|
||||
private val exchangeStatusConverter = ExchangeStatusConverter()
|
||||
private val txDetailsMoshiAdapter = moshi.adapter(TxDetails::class.java)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.feature.swap
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectList
|
||||
|
|
@ -18,12 +19,13 @@ import kotlinx.coroutines.flow.flowOn
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class DefaultSwapTransactionRepository(
|
||||
internal class DefaultSwapTransactionRepository(
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
) : SwapTransactionRepository {
|
||||
|
||||
private val converter = SavedSwapTransactionListConverter()
|
||||
private val converter = SavedSwapTransactionListConverter(excludedBlockchains)
|
||||
|
||||
override suspend fun storeTransaction(
|
||||
userWalletId: UserWalletId,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ internal class ErrorsDataConverter(
|
|||
2270 -> ExpressDataError.ExchangeNotEnoughBalanceError(code = error.code)
|
||||
2280 -> ExpressDataError.ExchangeInvalidAddressError(code = error.code)
|
||||
2290 -> tryParseExchangeInvalidFromDecimalsError(error = error)
|
||||
2320 -> tryParseProviderDifferentAmountError(error = error)
|
||||
else -> ExpressDataError.UnknownErrorWithCode(error.code)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
|
@ -79,4 +80,20 @@ internal class ErrorsDataConverter(
|
|||
expressFromDecimals = expressFromDecimals,
|
||||
)
|
||||
}
|
||||
|
||||
private fun tryParseProviderDifferentAmountError(error: ExpressError): ExpressDataError {
|
||||
val decimals = error.value?.decimals ?: return ExpressDataError.UnknownErrorWithCode(error.code)
|
||||
|
||||
val fromAmount = error.value?.fromAmount?.toBigDecimalOrNull()
|
||||
?: return ExpressDataError.UnknownErrorWithCode(error.code)
|
||||
val fromAmountProvider = error.value?.fromAmountProvider?.toBigDecimalOrNull()
|
||||
?: return ExpressDataError.UnknownErrorWithCode(error.code)
|
||||
|
||||
return ExpressDataError.ProviderDifferentAmountError(
|
||||
code = error.code,
|
||||
decimals = decimals,
|
||||
fromAmount = fromAmount.movePointLeft(decimals),
|
||||
fromProviderAmount = fromAmountProvider.movePointLeft(decimals),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.feature.swap.converters
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
|
||||
import com.tangem.data.common.currency.UserTokensResponseFactory
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -11,10 +12,11 @@ import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListMode
|
|||
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionModel
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
class SavedSwapTransactionListConverter :
|
||||
Converter<SavedSwapTransactionListModel, SavedSwapTransactionListModelInner> {
|
||||
internal class SavedSwapTransactionListConverter(
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
) : Converter<SavedSwapTransactionListModel, SavedSwapTransactionListModelInner> {
|
||||
|
||||
private val responseCryptoCurrenciesFactory = ResponseCryptoCurrenciesFactory()
|
||||
private val responseCryptoCurrenciesFactory = ResponseCryptoCurrenciesFactory(excludedBlockchains)
|
||||
private val userTokensResponseFactory = UserTokensResponseFactory()
|
||||
|
||||
override fun convert(value: SavedSwapTransactionListModel) = SavedSwapTransactionListModelInner(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.feature.swap.di
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.datasource.api.express.TangemExpressApi
|
||||
import com.tangem.datasource.api.express.models.response.ExpressErrorResponse
|
||||
import com.tangem.datasource.crypto.DataSignatureVerifier
|
||||
|
|
@ -34,6 +35,7 @@ internal class SwapDataModule {
|
|||
userWalletsListManager: UserWalletsListManager,
|
||||
errorsDataConverter: ErrorsDataConverter,
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): SwapRepository {
|
||||
return DefaultSwapRepository(
|
||||
tangemExpressApi = tangemExpressApi,
|
||||
|
|
@ -43,6 +45,7 @@ internal class SwapDataModule {
|
|||
errorsDataConverter = errorsDataConverter,
|
||||
dataSignatureVerifier = dataSignature,
|
||||
moshi = moshi,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -51,10 +54,12 @@ internal class SwapDataModule {
|
|||
fun provideSwapTransactionRepository(
|
||||
appPreferencesStore: AppPreferencesStore,
|
||||
dispatcherProvider: CoroutineDispatcherProvider,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): SwapTransactionRepository {
|
||||
return DefaultSwapTransactionRepository(
|
||||
appPreferencesStore = appPreferencesStore,
|
||||
dispatchers = dispatcherProvider,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,13 @@ sealed class ExpressDataError {
|
|||
val expressFromDecimals: Int,
|
||||
) : ExpressDataError()
|
||||
|
||||
data class ProviderDifferentAmountError(
|
||||
override val code: Int,
|
||||
val fromAmount: BigDecimal,
|
||||
val fromProviderAmount: BigDecimal,
|
||||
val decimals: Int,
|
||||
) : ExpressDataError()
|
||||
|
||||
data class UnknownErrorWithCode(override val code: Int) : ExpressDataError()
|
||||
|
||||
data class InvalidSignatureError(override val code: Int = 990) : ExpressDataError()
|
||||
|
|
|
|||
|
|
@ -10,10 +10,7 @@ import com.tangem.core.ui.components.notifications.NotificationConfig
|
|||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.event.triggeredEvent
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.format.bigdecimal.anyDecimals
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.format.bigdecimal.uncapped
|
||||
import com.tangem.core.ui.format.bigdecimal.*
|
||||
import com.tangem.core.ui.utils.BigDecimalFormatter
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
|
|
@ -781,6 +778,19 @@ internal class StateBuilder(
|
|||
iconResId = R.drawable.ic_alert_circle_24,
|
||||
),
|
||||
)
|
||||
is ExpressDataError.ProviderDifferentAmountError -> SwapWarning.GeneralError(
|
||||
notificationConfig = NotificationConfig(
|
||||
title = resourceReference(id = R.string.common_error),
|
||||
subtitle = resourceReference(
|
||||
R.string.express_error_provider_amount_roundup,
|
||||
formatArgs = wrappedList(
|
||||
expressDataError.code,
|
||||
expressDataError.fromProviderAmount.format { simple(decimals = expressDataError.decimals) },
|
||||
),
|
||||
),
|
||||
iconResId = R.drawable.ic_alert_circle_24,
|
||||
),
|
||||
)
|
||||
else -> SwapWarning.GeneralWarning(
|
||||
notificationConfig = NotificationConfig(
|
||||
title = providerErrorTitle,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,13 @@ internal fun getExpressErrorMessage(expressDataError: ExpressDataError): TextRef
|
|||
id = R.string.express_error_swap_pair_unavailable,
|
||||
formatArgs = wrappedList(expressDataError.code),
|
||||
)
|
||||
is ExpressDataError.ProviderDifferentAmountError -> resourceReference(
|
||||
R.string.express_error_provider_amount_roundup,
|
||||
formatArgs = wrappedList(
|
||||
expressDataError.code,
|
||||
expressDataError.fromProviderAmount.format { simple(decimals = expressDataError.decimals) },
|
||||
),
|
||||
)
|
||||
else -> resourceReference(R.string.express_error_code, wrappedList(expressDataError.code.toString()))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
|
|||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
|
||||
|
|
@ -25,6 +26,7 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
|
|||
private val isReadyToShowRateAppUseCase: IsReadyToShowRateAppUseCase,
|
||||
private val isNeedToBackupUseCase: IsNeedToBackupUseCase,
|
||||
private val hasSingleWalletSignedHashesUseCase: HasSingleWalletSignedHashesUseCase,
|
||||
private val getWalletsUseCase: GetWalletsUseCase,
|
||||
) {
|
||||
|
||||
private var readyForRateAppNotification = false
|
||||
|
|
@ -36,22 +38,32 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
|
|||
flow = getPrimaryCurrencyStatusUpdatesUseCase(userWallet.walletId),
|
||||
flow2 = isReadyToShowRateAppUseCase().conflate(),
|
||||
flow3 = isNeedToBackupUseCase(userWallet.walletId).conflate(),
|
||||
) { primaryCurrencyStatus, isReadyToShowRating, isNeedToBackup ->
|
||||
flow4 = getWalletsUseCase().conflate(),
|
||||
) { maybePrimaryCurrencyStatus, isReadyToShowRating, isNeedToBackup, userWallets ->
|
||||
readyForRateAppNotification = true
|
||||
buildList {
|
||||
addCriticalNotifications(cardTypesResolver)
|
||||
|
||||
addInformationalNotifications(cardTypesResolver, clickIntents)
|
||||
|
||||
addWarningNotifications(
|
||||
userWallet,
|
||||
cardTypesResolver,
|
||||
primaryCurrencyStatus,
|
||||
isNeedToBackup,
|
||||
clickIntents,
|
||||
addCriticalNotifications(
|
||||
cardTypesResolver = cardTypesResolver,
|
||||
)
|
||||
|
||||
addRateTheAppNotification(isReadyToShowRating, clickIntents)
|
||||
addInformationalNotifications(
|
||||
userWallets = userWallets,
|
||||
cardTypesResolver = cardTypesResolver,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
|
||||
addWarningNotifications(
|
||||
userWallet = userWallet,
|
||||
cardTypesResolver = cardTypesResolver,
|
||||
maybePrimaryCurrencyStatus = maybePrimaryCurrencyStatus,
|
||||
isNeedToBackup = isNeedToBackup,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
|
||||
addRateTheAppNotification(
|
||||
isReadyToShowRating = isReadyToShowRating,
|
||||
clickIntents = clickIntents,
|
||||
)
|
||||
}.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
|
@ -76,14 +88,19 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
|
|||
}
|
||||
|
||||
private fun MutableList<WalletNotification>.addInformationalNotifications(
|
||||
userWallets: List<UserWallet>,
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
clickIntents: WalletClickIntents,
|
||||
) {
|
||||
val userHasWalletOrWallet2 = userWallets.any {
|
||||
val typesResolver = it.scanResponse.cardTypesResolver
|
||||
typesResolver.isTangemWallet() || typesResolver.isWallet2()
|
||||
}
|
||||
addIf(
|
||||
element = WalletNotification.NoteMigration(
|
||||
onClick = { clickIntents.onNoteMigrationButtonClick(NOTE_MIGRATION_URL) },
|
||||
),
|
||||
condition = cardTypesResolver.isTangemNote(),
|
||||
condition = cardTypesResolver.isTangemNote() && !userHasWalletOrWallet2,
|
||||
)
|
||||
|
||||
addIf(
|
||||
|
|
|
|||
|
|
@ -70,8 +70,8 @@ zxingQrCode = "3.5.1"
|
|||
mviCore = "1.3.1"
|
||||
kotlinSerialization = "1.4.1"
|
||||
arrow = "1.2.3"
|
||||
walletConnectCore = "1.35.2"
|
||||
walletConnectWeb3 = "1.35.2"
|
||||
reownCore = "1.0.2"
|
||||
reownWeb3 = "1.0.2"
|
||||
prettyLogger = "2.2.0"
|
||||
okHttp-prettyLogging = "3.1.0"
|
||||
chucker = "4.0.0"
|
||||
|
|
@ -88,9 +88,9 @@ markdownComposeView = "0.5.4"
|
|||
# endregion Other libraries
|
||||
|
||||
# region Tangem
|
||||
tangemBlockchainSdk = "develop-871"
|
||||
tangemBlockchainSdk = "develop-875"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-403"
|
||||
tangemCardSdk = "develop-410"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
tangemVico = "2.0.0-alpha.25-tangem17"
|
||||
#tangemVico = "0.0.1" # Keep it! - used for local builds ^
|
||||
|
|
@ -251,8 +251,8 @@ mviCore-watcher = { module = "com.github.badoo.mvicore:mvicore-diff", version.re
|
|||
kotlin-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinSerialization" }
|
||||
arrow-core = { module = "io.arrow-kt:arrow-core", version.ref = "arrow" }
|
||||
arrow-fx = { module = "io.arrow-kt:arrow-fx-coroutines", version.ref = "arrow" }
|
||||
walletConnectCore = { module = "com.walletconnect:android-core", version.ref = "walletConnectCore" }
|
||||
walletConnectWeb3 = { module = "com.walletconnect:web3wallet", version.ref = "walletConnectWeb3" }
|
||||
reownCore = { module = "com.reown:android-core", version.ref = "reownCore" }
|
||||
reownWeb3 = { module = "com.reown:walletkit", version.ref = "reownWeb3" }
|
||||
prettyLogger = { module = "com.orhanobut:logger", version.ref = "prettyLogger" }
|
||||
chucker = { module = "com.github.chuckerteam.chucker:library", version.ref = "chucker" }
|
||||
chuckerStub = { module = "com.github.chuckerteam.chucker:library-no-op", version.ref = "chucker" }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.blockchainsdk.di
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.core.configtoggle.blockchain.ExcludedBlockchainsManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object ExcludedBlockchainsModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun bindExcludedBlockchains(excludedBlockchainsManager: ExcludedBlockchainsManager): ExcludedBlockchains {
|
||||
return ExcludedBlockchains(excludedBlockchainsManager)
|
||||
}
|
||||
}
|
||||
|
|
@ -387,10 +387,6 @@ fun Blockchain.toMigratedCointId(): String = when (this) {
|
|||
else -> toCoinId()
|
||||
}
|
||||
|
||||
fun Blockchain.isSupportedInApp(): Boolean {
|
||||
return !excludedBlockchains.contains(this)
|
||||
}
|
||||
|
||||
fun Blockchain.amountToCreateAccount(token: Token? = null): BigDecimal? {
|
||||
return when (this) {
|
||||
Blockchain.Stellar -> if (token?.symbol == NODL) BigDecimal(NODL_AMOUNT_TO_CREATE_ACCOUNT) else BigDecimal.ONE
|
||||
|
|
@ -409,11 +405,4 @@ fun Blockchain.minimalAmount(): BigDecimal {
|
|||
}
|
||||
|
||||
private const val NODL = "NODL"
|
||||
private const val NODL_AMOUNT_TO_CREATE_ACCOUNT = 1.5
|
||||
|
||||
// no need to add testnets
|
||||
private val excludedBlockchains = listOf(
|
||||
Blockchain.Unknown,
|
||||
Blockchain.Nexa,
|
||||
Blockchain.NexaTestnet,
|
||||
)
|
||||
private const val NODL_AMOUNT_TO_CREATE_ACCOUNT = 1.5
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.tangem.blockchainsdk.utils
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.core.configtoggle.blockchain.ExcludedBlockchainsManager
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import javax.inject.Inject
|
||||
|
||||
class ExcludedBlockchains @Inject internal constructor(
|
||||
private val excludedBlockchainsManager: ExcludedBlockchainsManager,
|
||||
) : Set<Blockchain> {
|
||||
|
||||
private val excludedBlockchains: Set<Blockchain> by lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||
excludedBlockchainsManager.excludedBlockchainsIds.fold(mutableSetOf()) { acc, blockchainId ->
|
||||
val blockchain = Blockchain.fromId(blockchainId)
|
||||
acc.add(blockchain)
|
||||
|
||||
blockchain.getTestnetVersion()?.let { acc.add(it) }
|
||||
|
||||
acc
|
||||
}
|
||||
}
|
||||
|
||||
override val size: Int
|
||||
get() = excludedBlockchains.size
|
||||
|
||||
@TestOnly
|
||||
constructor() : this(
|
||||
excludedBlockchainsManager = object : ExcludedBlockchainsManager {
|
||||
|
||||
override val excludedBlockchainsIds: Set<String> = emptySet()
|
||||
|
||||
override suspend fun init() {
|
||||
/* no-op */
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
override fun contains(element: Blockchain): Boolean = excludedBlockchains.contains(element)
|
||||
|
||||
override fun containsAll(elements: Collection<Blockchain>): Boolean = excludedBlockchains.containsAll(elements)
|
||||
|
||||
override fun isEmpty(): Boolean = excludedBlockchains.isEmpty()
|
||||
|
||||
override fun iterator(): Iterator<Blockchain> = excludedBlockchains.iterator()
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ fun createPrivateProviderType(name: String): ProviderType? {
|
|||
"tangemRosetta" -> ProviderType.Cardano.Rosetta
|
||||
"fireAcademy" -> ProviderType.Chia.FireAcademy
|
||||
"tangemChia" -> ProviderType.Chia.Tangem
|
||||
"tangemChia3" -> ProviderType.Chia.TangemNew
|
||||
"infura" -> ProviderType.EthereumLike.Infura
|
||||
"getblock" -> ProviderType.GetBlock
|
||||
"arkhiaHedera" -> ProviderType.Hedera.Arkhia
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package com.tangem.lib.crypto
|
|||
import com.tangem.blockchain.blockchains.xrp.XrpAddressService
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.compatibility.l2BlockchainsList
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.blockchainsdk.utils.isSupportedInApp
|
||||
import com.tangem.lib.crypto.converter.XrpTaggedAddressConverter
|
||||
import com.tangem.lib.crypto.models.XrpTaggedAddress
|
||||
|
||||
|
|
@ -64,8 +64,10 @@ object BlockchainUtils {
|
|||
return blockchain == Blockchain.Tron || blockchain == Blockchain.TronTestnet
|
||||
}
|
||||
|
||||
fun isSupportedNetworkId(blockchainId: String): Boolean {
|
||||
return Blockchain.fromNetworkId(blockchainId)?.isSupportedInApp() ?: false
|
||||
fun isSupportedNetworkId(blockchainId: String, excludedBlockchains: ExcludedBlockchains): Boolean {
|
||||
val blockchain = Blockchain.fromNetworkId(blockchainId)
|
||||
|
||||
return blockchain != null && blockchain !in excludedBlockchains
|
||||
}
|
||||
|
||||
fun isArbitrum(blockchainId: String): Boolean {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue