Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-16 10:57:01 +03:00
commit 3c2a006fb9
331 changed files with 8261 additions and 1670 deletions

View file

@ -1,6 +1,9 @@
package com.tangem.tap
import android.app.Application
import android.os.StrictMode
import android.os.StrictMode.ThreadPolicy
import android.os.StrictMode.VmPolicy
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import coil.ImageLoader
@ -71,9 +74,7 @@ import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.wallet.BuildConfig
import dagger.hilt.EntryPoints
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.*
import org.rekotlin.Store
import kotlin.collections.set
import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository as WalletConnect2Repository
@ -228,12 +229,32 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
// endregion
private val appScope = MainScope()
override fun onCreate() {
enableStrictModeInDebug()
super.onCreate()
init()
}
updateLogFiles()
private fun enableStrictModeInDebug() {
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectAll()
.penaltyLog()
.build(),
)
StrictMode.setVmPolicy(
VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.build(),
)
}
}
private fun updateLogFiles() {
@ -260,18 +281,31 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
foregroundActivityObserver = ForegroundActivityObserver()
registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks)
// TODO: Try to performance and user experience.
// [REDACTED_JIRA]
// We need to initialize the toggles and excludedBlockchainsManager before the MainActivity starts using them.
runBlocking {
awaitAll(
async { featureTogglesManager.init() },
async { excludedBlockchainsManager.init() },
async { initWithConfigDependency(environmentConfig = environmentConfigStorage.initialize()) },
async {
featureTogglesManager.init()
},
async {
excludedBlockchainsManager.init()
},
)
}
loadNativeLibraries()
appScope.launch {
initWithConfigDependency(environmentConfig = environmentConfigStorage.initialize())
launch(Dispatchers.IO) {
loadNativeLibraries()
walletConnect2Repository.init(
projectId = environmentConfigStorage.getConfigSync().walletConnectProjectId,
)
updateLogFiles()
}
}
ExceptionHandler.append(blockchainExceptionHandler)
if (LogConfig.network.blockchainSdkNetwork) {
BlockchainSdkRetrofitBuilder.interceptors = listOf(
createNetworkLoggingInterceptor(),
@ -287,9 +321,8 @@ abstract class TangemApplication : Application(), ImageLoaderFactory, Configurat
appPreferencesStore = appPreferencesStore,
dispatchers = dispatchers,
)
appStateHolder.mainStore = store
walletConnect2Repository.init(projectId = environmentConfigStorage.getConfigSync().walletConnectProjectId)
appStateHolder.mainStore = store
}
private fun createReduxStore(): Store<AppState> {

View file

@ -20,18 +20,22 @@ internal class DefaultVisaAuthTokenStorage @Inject constructor(
private val dispatcherProvider: CoroutineDispatcherProvider,
) : VisaAuthTokenStorage {
private val secureStorage = AndroidSecureStorage(
preferences = SecureStorage.createEncryptedSharedPreferences(
context = applicationContext,
storageName = "visa_auth_storage",
),
)
private val secureStorage by lazy {
AndroidSecureStorage(
preferences = SecureStorage.createEncryptedSharedPreferences(
context = applicationContext,
storageName = "visa_auth_storage",
),
)
}
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private val moshi by lazy {
Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
}
private val tokensAdapter = moshi.adapter(VisaAuthTokens::class.java)
private val tokensAdapter by lazy { moshi.adapter(VisaAuthTokens::class.java) }
override suspend fun store(cardId: String, tokens: VisaAuthTokens) = withContext(dispatcherProvider.io) {
val json = tokensAdapter.toJson(tokens)

View file

@ -20,12 +20,14 @@ class DefaultVisaOTPStorage @Inject constructor(
private val dispatcherProvider: CoroutineDispatcherProvider,
) : VisaOTPStorage {
private val secureStorage = AndroidSecureStorage(
preferences = SecureStorage.createEncryptedSharedPreferences(
context = applicationContext,
storageName = "visa_otp_storage",
),
)
private val secureStorage by lazy {
AndroidSecureStorage(
preferences = SecureStorage.createEncryptedSharedPreferences(
context = applicationContext,
storageName = "visa_otp_storage",
),
)
}
override suspend fun saveOTP(cardId: String, data: VisaOtpData) = withContext(dispatcherProvider.io) {
secureStorage.store(data.rootOTP, VISA_ROOT_OTP_KEY_PREFIX + cardId)

View file

@ -5,6 +5,7 @@ import com.tangem.domain.managetokens.*
import com.tangem.domain.managetokens.repository.CustomTokensRepository
import com.tangem.domain.managetokens.repository.ManageTokensRepository
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
import com.tangem.domain.quotes.multi.MultiQuoteFetcher
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.TokensFeatureToggles
import com.tangem.domain.tokens.repository.CurrenciesRepository
@ -73,6 +74,7 @@ internal object ManageTokensDomainModule {
stakingRepository: StakingRepository,
quotesRepository: QuotesRepository,
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteFetcher: MultiQuoteFetcher,
tokensFeatureToggles: TokensFeatureToggles,
): SaveManagedTokensUseCase {
return SaveManagedTokensUseCase(
@ -84,6 +86,7 @@ internal object ManageTokensDomainModule {
stakingRepository = stakingRepository,
quotesRepository = quotesRepository,
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteFetcher = multiQuoteFetcher,
tokensFeatureToggles = tokensFeatureToggles,
)
}

View file

@ -5,6 +5,8 @@ import com.tangem.domain.card.repository.DerivationsRepository
import com.tangem.domain.markets.*
import com.tangem.domain.markets.repositories.MarketsTokenRepository
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
import com.tangem.domain.quotes.multi.MultiQuoteFetcher
import com.tangem.domain.quotes.single.SingleQuoteSupplier
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.TokensFeatureToggles
import com.tangem.domain.tokens.repository.CurrenciesRepository
@ -49,8 +51,16 @@ object MarketsDomainModule {
@Provides
@Singleton
fun provideGetTokenQuotesUseCase(quotesRepository: QuotesRepository): GetCurrencyQuotesUseCase {
return GetCurrencyQuotesUseCase(quotesRepository = quotesRepository)
fun provideGetTokenQuotesUseCase(
quotesRepository: QuotesRepository,
singleQuoteSupplier: SingleQuoteSupplier,
tokensFeatureToggles: TokensFeatureToggles,
): GetCurrencyQuotesUseCase {
return GetCurrencyQuotesUseCase(
quotesRepository = quotesRepository,
singleQuoteSupplier = singleQuoteSupplier,
tokensFeatureToggles = tokensFeatureToggles,
)
}
@Provides
@ -63,6 +73,7 @@ object MarketsDomainModule {
stakingRepository: StakingRepository,
quotesRepository: QuotesRepository,
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteFetcher: MultiQuoteFetcher,
tokensFeatureToggles: TokensFeatureToggles,
): SaveMarketTokensUseCase {
return SaveMarketTokensUseCase(
@ -73,6 +84,7 @@ object MarketsDomainModule {
stakingRepository = stakingRepository,
quotesRepository = quotesRepository,
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteFetcher = multiQuoteFetcher,
tokensFeatureToggles = tokensFeatureToggles,
)
}

View file

@ -7,6 +7,9 @@ import com.tangem.domain.networks.multi.MultiNetworkStatusSupplier
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
import com.tangem.domain.networks.single.SingleNetworkStatusSupplier
import com.tangem.domain.promo.PromoRepository
import com.tangem.domain.quotes.QuotesRepositoryV2
import com.tangem.domain.quotes.multi.MultiQuoteFetcher
import com.tangem.domain.quotes.single.SingleQuoteSupplier
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.operations.BaseCurrenciesStatusesOperations
@ -35,6 +38,7 @@ internal object TokensDomainModule {
stakingRepository: StakingRepository,
quotesRepository: QuotesRepository,
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteFetcher: MultiQuoteFetcher,
tokensFeatureToggles: TokensFeatureToggles,
): AddCryptoCurrenciesUseCase {
return AddCryptoCurrenciesUseCase(
@ -43,6 +47,7 @@ internal object TokensDomainModule {
stakingRepository = stakingRepository,
quotesRepository = quotesRepository,
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteFetcher = multiQuoteFetcher,
tokensFeatureToggles = tokensFeatureToggles,
)
}
@ -55,6 +60,7 @@ internal object TokensDomainModule {
networksRepository: NetworksRepository,
stakingRepository: StakingRepository,
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteFetcher: MultiQuoteFetcher,
tokensFeatureToggles: TokensFeatureToggles,
): FetchTokenListUseCase {
return FetchTokenListUseCase(
@ -63,6 +69,7 @@ internal object TokensDomainModule {
quotesRepository = quotesRepository,
stakingRepository = stakingRepository,
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteFetcher = multiQuoteFetcher,
tokensFeatureToggles = tokensFeatureToggles,
)
}
@ -168,6 +175,7 @@ internal object TokensDomainModule {
networksRepository: NetworksRepository,
stakingRepository: StakingRepository,
singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
multiQuoteFetcher: MultiQuoteFetcher,
tokensFeatureToggles: TokensFeatureToggles,
): FetchCurrencyStatusUseCase {
return FetchCurrencyStatusUseCase(
@ -176,6 +184,7 @@ internal object TokensDomainModule {
quotesRepository = quotesRepository,
stakingRepository = stakingRepository,
singleNetworkStatusFetcher = singleNetworkStatusFetcher,
multiQuoteFetcher = multiQuoteFetcher,
tokensFeatureToggles = tokensFeatureToggles,
)
}
@ -188,6 +197,7 @@ internal object TokensDomainModule {
networksRepository: NetworksRepository,
stakingRepository: StakingRepository,
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteFetcher: MultiQuoteFetcher,
tokensFeatureToggles: TokensFeatureToggles,
): FetchCardTokenListUseCase {
return FetchCardTokenListUseCase(
@ -196,6 +206,7 @@ internal object TokensDomainModule {
quotesRepository = quotesRepository,
stakingRepository = stakingRepository,
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteFetcher = multiQuoteFetcher,
tokensFeatureToggles = tokensFeatureToggles,
)
}
@ -364,10 +375,14 @@ internal object TokensDomainModule {
fun provideRefreshMultiCurrencyWalletQuotesUseCase(
currenciesRepository: CurrenciesRepository,
quotesRepository: QuotesRepository,
multiQuoteFetcher: MultiQuoteFetcher,
tokensFeatureToggles: TokensFeatureToggles,
): RefreshMultiCurrencyWalletQuotesUseCase {
return RefreshMultiCurrencyWalletQuotesUseCase(
currenciesRepository = currenciesRepository,
quotesRepository = quotesRepository,
multiQuoteFetcher = multiQuoteFetcher,
tokensFeatureToggles = tokensFeatureToggles,
)
}
@ -386,20 +401,26 @@ internal object TokensDomainModule {
tokensFeatureToggles: TokensFeatureToggles,
currenciesRepository: CurrenciesRepository,
quotesRepository: QuotesRepository,
quotesRepositoryV2: QuotesRepositoryV2,
networksRepository: NetworksRepository,
stakingRepository: StakingRepository,
singleNetworkStatusSupplier: SingleNetworkStatusSupplier,
multiNetworkStatusSupplier: MultiNetworkStatusSupplier,
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteFetcher: MultiQuoteFetcher,
singleQuoteSupplier: SingleQuoteSupplier,
): BaseCurrenciesStatusesOperations {
return CachedCurrenciesStatusesOperations(
currenciesRepository = currenciesRepository,
quotesRepository = quotesRepository,
quotesRepositoryV2 = quotesRepositoryV2,
networksRepository = networksRepository,
stakingRepository = stakingRepository,
singleNetworkStatusSupplier = singleNetworkStatusSupplier,
multiNetworkStatusSupplier = multiNetworkStatusSupplier,
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteFetcher = multiQuoteFetcher,
singleQuoteSupplier = singleQuoteSupplier,
tokensFeatureToggles = tokensFeatureToggles,
)
}
@ -410,21 +431,33 @@ internal object TokensDomainModule {
tokensFeatureToggles: TokensFeatureToggles,
currenciesRepository: CurrenciesRepository,
quotesRepository: QuotesRepository,
quotesRepositoryV2: QuotesRepositoryV2,
networksRepository: NetworksRepository,
stakingRepository: StakingRepository,
singleNetworkStatusSupplier: SingleNetworkStatusSupplier,
multiNetworkStatusSupplier: MultiNetworkStatusSupplier,
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteFetcher: MultiQuoteFetcher,
singleQuoteSupplier: SingleQuoteSupplier,
): BaseCurrencyStatusOperations {
return CachedCurrenciesStatusesOperations(
currenciesRepository = currenciesRepository,
quotesRepository = quotesRepository,
quotesRepositoryV2 = quotesRepositoryV2,
networksRepository = networksRepository,
stakingRepository = stakingRepository,
singleNetworkStatusSupplier = singleNetworkStatusSupplier,
multiNetworkStatusSupplier = multiNetworkStatusSupplier,
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteFetcher = multiQuoteFetcher,
singleQuoteSupplier = singleQuoteSupplier,
tokensFeatureToggles = tokensFeatureToggles,
)
}
@Provides
@Singleton
fun provideGetCryptoCurrenciesUseCase(currenciesRepository: CurrenciesRepository): GetCryptoCurrenciesUseCase {
return GetCryptoCurrenciesUseCase(currenciesRepository)
}
}

View file

@ -147,4 +147,22 @@ internal object TransactionDomainModule {
fun provideGetAllowanceUseCase(transactionRepository: TransactionRepository): GetAllowanceUseCase {
return GetAllowanceUseCase(transactionRepository)
}
@Provides
@Singleton
fun providePrepareForSendUseCase(
transactionRepository: TransactionRepository,
cardSdkConfigRepository: CardSdkConfigRepository,
): PrepareForSendUseCase {
return PrepareForSendUseCase(transactionRepository, cardSdkConfigRepository)
}
@Provides
@Singleton
fun provideSignUseCase(
walletManagersFacade: WalletManagersFacade,
cardSdkConfigRepository: CardSdkConfigRepository,
): SignUseCase {
return SignUseCase(cardSdkConfigRepository, walletManagersFacade)
}
}

View file

@ -14,6 +14,8 @@ import com.tangem.feature.wallet.presentation.wallet.domain.IsWalletNFTEnabledSy
import com.tangem.feature.wallet.presentation.wallet.domain.WalletNameMigrationUseCase
import com.tangem.operations.attestation.OnlineCardVerifier
import com.tangem.features.nft.NFTFeatureToggles
import com.tangem.operations.attestation.CardArtworksProvider
import com.tangem.sdk.api.featuretoggles.CardSdkFeatureToggles
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
@ -172,8 +174,16 @@ internal object WalletsDomainModule {
@Provides
@Singleton
fun provideGetCardImageUseCase(onlineCardVerifier: OnlineCardVerifier): GetCardImageUseCase {
return GetCardImageUseCase(verifier = onlineCardVerifier)
fun provideGetCardImageUseCase(
onlineCardVerifier: OnlineCardVerifier,
cardArtworksProvider: CardArtworksProvider,
cardSdkFeatureToggles: CardSdkFeatureToggles,
): GetCardImageUseCase {
return GetCardImageUseCase(
verifier = onlineCardVerifier,
cardArtworksProvider = cardArtworksProvider,
cardSdkFeatureToggles = cardSdkFeatureToggles,
)
}
@Provides

View file

@ -6,6 +6,7 @@ import com.tangem.domain.common.TwinCardNumber
import com.tangem.domain.common.getTwinCardNumber
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.wallets.models.Artwork
import com.tangem.operations.attestation.CardArtworksProvider
import com.tangem.operations.attestation.OnlineCardVerifier
import com.tangem.operations.attestation.api.models.CardVerifyAndGetInfo
@ -37,7 +38,7 @@ suspend fun CardDTO.getOrLoadCardArtworkUrl(
if (artworkId.isNullOrEmpty()) {
ifAnyError()
} else {
OnlineCardVerifier.getUrlForArtwork(cardId, cardPublicKey.toHexString(), artworkId)
CardArtworksProvider.getUrlForArtwork(cardId, cardPublicKey.toHexString(), artworkId)
}
}

View file

@ -9,4 +9,10 @@ internal class DefaultTokensFeatureToggles(
override val isNetworksLoadingRefactoringEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(name = "NETWORKS_LOADING_REFACTORING_ENABLED")
override val isQuotesLoadingRefactoringEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(name = "QUOTES_LOADING_REFACTORING_ENABLED")
override val isStakingLoadingRefactoringEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(name = "STAKING_LOADING_REFACTORING_ENABLED")
}

View file

@ -21,8 +21,6 @@ internal data class UserWalletPublicInformation(
val name: String,
@Json(name = "walletId")
val walletId: UserWalletId,
@Json(name = "artworkUrl")
val artworkUrl: String,
@Json(name = "cardsInWallet")
val cardsInWallet: Set<String>,
@Json(name = "scanResponse")

View file

@ -20,9 +20,12 @@ internal class DefaultUserWalletsPublicInformationRepository(
moshi: Moshi,
private val secureStorage: SecureStorage,
) : UserWalletsPublicInformationRepository {
private val publicInformationAdapter: JsonAdapter<List<UserWalletPublicInformation>> = moshi.adapter(
Types.newParameterizedType(List::class.java, UserWalletPublicInformation::class.java),
)
private val publicInformationAdapter: JsonAdapter<List<UserWalletPublicInformation>> by lazy {
moshi.adapter(
Types.newParameterizedType(List::class.java, UserWalletPublicInformation::class.java),
)
}
override suspend fun save(userWallet: UserWallet, canOverride: Boolean): CompletionResult<Unit> {
return withContext(Dispatchers.IO) {

View file

@ -24,12 +24,15 @@ internal class DefaultUserWalletsSensitiveInformationRepository(
private val secureStorage: SecureStorage,
) : UserWalletsSensitiveInformationRepository {
private val sensitiveInformationAdapter: JsonAdapter<UserWalletSensitiveInformation> = moshi.adapter(
UserWalletSensitiveInformation::class.java,
)
private val encryptedSensitiveInformationMapAdapter: JsonAdapter<Map<String, ByteArray>> = moshi.adapter(
Types.newParameterizedType(Map::class.java, String::class.java, ByteArray::class.java),
)
private val sensitiveInformationAdapter: JsonAdapter<UserWalletSensitiveInformation> by lazy {
moshi.adapter(UserWalletSensitiveInformation::class.java)
}
private val encryptedSensitiveInformationMapAdapter: JsonAdapter<Map<String, ByteArray>> by lazy {
moshi.adapter(
Types.newParameterizedType(Map::class.java, String::class.java, ByteArray::class.java),
)
}
override suspend fun save(userWallet: UserWallet, encryptionKey: ByteArray?): CompletionResult<Unit> {
if (encryptionKey == null) {

View file

@ -15,7 +15,6 @@ internal val UserWallet.publicInformation: UserWalletPublicInformation
get() = UserWalletPublicInformation(
name = name,
walletId = walletId,
artworkUrl = artworkUrl,
cardsInWallet = cardsInWallet,
isMultiCurrency = isMultiCurrency,
scanResponse = scanResponse.copy(
@ -31,7 +30,6 @@ internal fun UserWalletPublicInformation.toUserWallet(): UserWallet {
return UserWallet(
name = name,
walletId = walletId,
artworkUrl = artworkUrl,
cardsInWallet = cardsInWallet,
scanResponse = scanResponse,
isMultiCurrency = isMultiCurrency,

View file

@ -4,7 +4,6 @@ import com.tangem.Message
import com.tangem.blockchain.blockchains.ethereum.EthereumGasLoader
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
import com.tangem.blockchain.blockchains.ethereum.EthereumUtils
import com.tangem.blockchain.blockchains.ethereum.EthereumUtils.toKeccak
import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.extensions.*
@ -16,6 +15,7 @@ import com.tangem.common.extensions.toHexString
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.models.Basic
import com.tangem.core.analytics.models.Basic.TransactionSent.MemoType
import com.tangem.data.walletconnect.network.ethereum.LegacySdkHelper
import com.tangem.operations.sign.SignHashCommand
import com.tangem.tap.common.extensions.inject
import com.tangem.tap.common.extensions.safeUpdate
@ -357,36 +357,9 @@ class WalletConnectSdkHelper {
)
}
private fun createMessageData(message: WcSignMessage): ByteArray {
val messageData = try {
message.data.removePrefix(HEX_PREFIX).hexToBytes()
} catch (exception: Exception) {
message.data.asciiToHex()?.hexToBytes() ?: byteArrayOf()
}
private fun createMessageData(message: WcSignMessage): ByteArray = LegacySdkHelper.createMessageData(message.data)
val prefixData = (ETH_MESSAGE_PREFIX + messageData.size.toString()).toByteArray()
return (prefixData + messageData).toKeccak()
}
private fun String.hexToAscii(): String? {
return try {
removePrefix(HEX_PREFIX).hexToBytes()
.map {
val char = it.toInt().toChar()
if (char.isAscii()) char else return null
}
.joinToString("")
} catch (exception: Exception) {
return null
}
}
private fun String.asciiToHex(): String? {
return map {
if (!it.isAscii()) return null
Integer.toHexString(it.code)
}.joinToString("")
}
private fun String.hexToAscii(): String? = LegacySdkHelper.hexToAscii(hex = this)
suspend fun signPersonalMessage(
hashToSign: ByteArray,
@ -535,7 +508,6 @@ class WalletConnectSdkHelper {
"{\"signature\":\"$signature\",\"publicKey\":\"$publicKey\"}"
private companion object {
const val ETH_MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n"
const val HEX_PREFIX = "0x"
const val DEFAULT_MAX_GASLIMIT = 350000
// TODO remove after [REDACTED_JIRA]

View file

@ -31,7 +31,7 @@ import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.onboarding.data.model.CreateWalletResponse
import com.tangem.feature.onboarding.presentation.wallet2.analytics.SeedPhraseSource
import com.tangem.feature.wallet.presentation.wallet.domain.BackupValidator
import com.tangem.operations.attestation.OnlineCardVerifier
import com.tangem.operations.attestation.CardArtworksProvider
import com.tangem.operations.backup.BackupService
import com.tangem.sdk.api.CreateProductWalletTaskResponse
import com.tangem.sdk.extensions.localizedDescriptionRes
@ -250,7 +250,7 @@ private suspend fun loadArtworkForCard(cardId: String, cardPublicKey: ByteArray,
if (artworkId.isNullOrEmpty()) {
defaultArtwork ?: Uri.EMPTY
} else {
Uri.parse(OnlineCardVerifier.getUrlForArtwork(cardId, cardPublicKey.toHexString(), artworkId))
Uri.parse(CardArtworksProvider.getUrlForArtwork(cardId, cardPublicKey.toHexString(), artworkId))
}
}
is Result.Failure -> defaultArtwork ?: Uri.EMPTY

View file

@ -32,6 +32,7 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
import com.tangem.features.onramp.OnrampFeatureToggles
import com.tangem.operations.attestation.CardArtworksProvider
import com.tangem.operations.attestation.OnlineCardVerifier
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
import com.tangem.tap.domain.walletconnect2.domain.LegacyWalletConnectRepository
@ -76,5 +77,6 @@ data class DaggerGraphState(
val settingsManager: SettingsManager? = null,
val uiMessageSender: UiMessageSender? = null,
val onlineCardVerifier: OnlineCardVerifier? = null,
val cardArworksProvider: CardArtworksProvider? = null,
val userWalletBuilderFactory: UserWalletBuilder.Factory? = null,
) : StateType

View file

@ -12,13 +12,12 @@ import com.tangem.features.disclaimer.api.components.DisclaimerComponent
import com.tangem.features.managetokens.component.ManageTokensComponent
import com.tangem.features.managetokens.component.ManageTokensSource
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
import com.tangem.features.nft.component.NFTCollectionsComponent
import com.tangem.features.nft.component.NFTDetailsComponent
import com.tangem.features.nft.component.NFTReceiveComponent
import com.tangem.features.nft.component.*
import com.tangem.features.onboarding.v2.entry.OnboardingEntryComponent
import com.tangem.features.onramp.component.*
import com.tangem.features.pushnotifications.api.PushNotificationsComponent
import com.tangem.features.send.api.SendComponent
import com.tangem.features.send.v2.api.NFTSendComponent
import com.tangem.features.send.v2.api.SendFeatureToggles
import com.tangem.features.staking.api.StakingComponent
import com.tangem.features.swap.SwapComponent
@ -83,9 +82,8 @@ internal class ChildFactory @Inject constructor(
private val sendComponentFactoryV2: com.tangem.features.send.v2.api.SendComponent.Factory,
private val sendFeatureToggles: SendFeatureToggles,
private val redesignedWalletConnectComponentFactory: RedisegnedWalletConnectComponent.Factory,
private val nftCollectionsComponentFactory: NFTCollectionsComponent.Factory,
private val nftReceiveComponentFactory: NFTReceiveComponent.Factory,
private val nftDetailsComponentFactory: NFTDetailsComponent.Factory,
private val nftComponentFactory: NFTComponent.Factory,
private val nftSendComponentFactory: NFTSendComponent.Factory,
private val testerRouter: TesterRouter,
private val routingFeatureToggles: RoutingFeatureToggles,
private val walletConnectFeatureToggles: WalletConnectFeatureToggles,
@ -405,24 +403,23 @@ internal class ChildFactory @Inject constructor(
componentFactory = walletComponentFactory,
)
}
is AppRoute.NFTCollections ->
is AppRoute.NFT ->
createComponentChild(
context = context,
params = NFTCollectionsComponent.Params(userWalletId = route.userWalletId),
componentFactory = nftCollectionsComponentFactory,
params = NFTComponent.Params(userWalletId = route.userWalletId),
componentFactory = nftComponentFactory,
)
is AppRoute.NFTReceive ->
is AppRoute.NFTSend -> {
createComponentChild(
context = context,
params = NFTReceiveComponent.Params(userWalletId = route.userWalletId),
componentFactory = nftReceiveComponentFactory,
)
is AppRoute.NFTDetails ->
createComponentChild(
context = context,
params = NFTDetailsComponent.Params(userWalletId = route.userWalletId, nftAsset = route.nftAsset),
componentFactory = nftDetailsComponentFactory,
params = NFTSendComponent.Params(
userWalletId = route.userWalletId,
nftAsset = route.nftAsset,
nftCollectionName = route.nftCollectionName,
),
componentFactory = nftSendComponentFactory,
)
}
is AppRoute.OnboardingNote,
is AppRoute.SaveWallet,
is AppRoute.OnboardingOther,
@ -757,24 +754,23 @@ internal class ChildFactory @Inject constructor(
componentFactory = storiesComponentFactory,
)
}
is AppRoute.NFTCollections ->
is AppRoute.NFT ->
route.asComponentChild(
contextProvider = contextProvider(route, contextFactory),
params = NFTCollectionsComponent.Params(userWalletId = route.userWalletId),
componentFactory = nftCollectionsComponentFactory,
params = NFTComponent.Params(userWalletId = route.userWalletId),
componentFactory = nftComponentFactory,
)
is AppRoute.NFTReceive ->
is AppRoute.NFTSend -> {
route.asComponentChild(
contextProvider = contextProvider(route, contextFactory),
params = NFTReceiveComponent.Params(userWalletId = route.userWalletId),
componentFactory = nftReceiveComponentFactory,
)
is AppRoute.NFTDetails ->
route.asComponentChild(
contextProvider = contextProvider(route, contextFactory),
params = NFTDetailsComponent.Params(userWalletId = route.userWalletId, nftAsset = route.nftAsset),
componentFactory = nftDetailsComponentFactory,
params = NFTSendComponent.Params(
userWalletId = route.userWalletId,
nftAsset = route.nftAsset,
nftCollectionName = route.nftCollectionName,
),
componentFactory = nftSendComponentFactory,
)
}
}
// endregion
}

View file

@ -39,7 +39,6 @@ internal class DefaultDerivationsRepositoryTest {
private val defaultUserWallet = UserWallet(
name = "",
walletId = defaultUserWalletId,
artworkUrl = "",
cardsInWallet = setOf(),
isMultiCurrency = false,
scanResponse = MockScanResponseFactory.create(cardConfig = GenericCardConfig(2), derivedKeys = emptyMap()),

View file

@ -194,7 +194,6 @@ internal class BiometricUserWalletsListManagerTest(private val model: Model) {
return UserWallet(
name = "Wallet $id",
walletId = UserWalletId(stringValue = id),
artworkUrl = "",
cardsInWallet = emptySet(),
isMultiCurrency = true,
hasBackupError = false,