Updated on 2026-08-14

This commit is contained in:
Tangem 2026-04-29 12:43:31 +04:00
parent d97b7b9bf7
commit 266e49734e
11 changed files with 67 additions and 32 deletions

View file

@ -18,8 +18,9 @@ internal class DefaultDeviceSecurityInfoProvider : DeviceSecurityInfoProvider {
val isPatched by lazy { hasSecurityPatch() }
val isVulnerable = isAffected && !isPatched
TangemLogger.i(
"CVE-2026-20435 check: isAffectedMediaTek=$isAffected, " +
messageString = "CVE-2026-20435 check: isAffectedMediaTek=$isAffected, " +
"isPatched=$isPatched, isVulnerable=$isVulnerable",
shouldSanitize = false,
)
isVulnerable
}
@ -27,7 +28,10 @@ internal class DefaultDeviceSecurityInfoProvider : DeviceSecurityInfoProvider {
private fun isAffectedMediaTekDevice(): Boolean {
val socModel = resolveMediaTekSocModel()
val isAffected = socModel != null && socModel in AFFECTED_MEDIATEK_SOCS
TangemLogger.i("CVE-2026-20435 SoC result: model=$socModel, isAffected=$isAffected")
TangemLogger.i(
messageString = "CVE-2026-20435 SoC result: model=$socModel, isAffected=$isAffected",
shouldSanitize = false,
)
return isAffected
}
@ -36,7 +40,10 @@ internal class DefaultDeviceSecurityInfoProvider : DeviceSecurityInfoProvider {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val manufacturer = Build.SOC_MANUFACTURER
val model = Build.SOC_MODEL
TangemLogger.i("CVE-2026-20435 Layer 1: SOC_MANUFACTURER=$manufacturer, SOC_MODEL=$model")
TangemLogger.i(
messageString = "CVE-2026-20435 Layer 1: SOC_MANUFACTURER=$manufacturer, SOC_MODEL=$model",
shouldSanitize = false,
)
if (manufacturer.equals("MediaTek", ignoreCase = true)) {
extractSocModel(model)?.let { return it }
}
@ -44,7 +51,7 @@ internal class DefaultDeviceSecurityInfoProvider : DeviceSecurityInfoProvider {
// Layer 2: Build.HARDWARE often contains "mtXXXX" on MediaTek devices (public API)
val hardware = Build.HARDWARE
TangemLogger.i("CVE-2026-20435 Layer 2: HARDWARE=$hardware")
TangemLogger.i(messageString = "CVE-2026-20435 Layer 2: HARDWARE=$hardware", shouldSanitize = false)
extractSocModel(hardware)?.let { return it }
return null

View file

@ -470,7 +470,7 @@ internal class DefaultSwapRepositoryV2 @Inject constructor(
).getOrThrow()
},
onError = { error ->
TangemLogger.w("Unable to get pairs", error)
TangemLogger.e("Unable to get pairs", error)
throw error
},
)

View file

@ -116,7 +116,10 @@ class BalanceFetchingOperations(
val stakingId = stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = currency)
if (stakingId.isLeft { it is StakingIdFactory.Error.UnableToGetAddress }) {
TangemLogger.e("Unable to get staking ID for user wallet $userWalletId and currency ${currency.id}")
TangemLogger.e(
messageString = "Unable to get stakingID for user wallet $userWalletId and currency ${currency.id}",
shouldSanitize = false,
)
}
stakingId.getOrNull()

View file

@ -620,6 +620,7 @@ internal class SwapAmountModel @Inject constructor(
| Primary -> $primaryStatus
| Secondary -> $secondaryStatus
""".trimIndent(),
shouldSanitize = false,
)
showErrorAlert(errorMessage = null)
}

View file

@ -23,12 +23,12 @@ import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.model.transfor
import com.tangem.features.swap.v2.impl.common.SwapUtils.SEND_WITH_SWAP_PROVIDER_TYPES
import com.tangem.features.swap.v2.impl.sendviaswap.analytics.SendWithSwapAnalyticEvents
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.logging.TangemLogger
import com.tangem.utils.transformer.update
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import com.tangem.utils.logging.TangemLogger
import javax.inject.Inject
@Suppress("LongParameterList")
@ -76,8 +76,8 @@ internal class SwapChooseTokenNetworkModel @Inject constructor(
val cryptoCurrencyList = createCryptoCurrencyUseCase(
token = params.token,
userWalletId = params.userWalletId,
).getOrElse {
TangemLogger.e("Failed to get crypto currency")
).getOrElse { throwable ->
TangemLogger.e("Failed to get crypto currency", throwable)
swapChooseTokenAlertFactory.getGenericErrorState(params.onDismiss)
return@launch
}
@ -88,7 +88,7 @@ internal class SwapChooseTokenNetworkModel @Inject constructor(
filterProviderTypes = SEND_WITH_SWAP_PROVIDER_TYPES,
swapTxType = SwapTxType.SendWithSwap,
).getOrElse { error ->
TangemLogger.e(error.toString())
TangemLogger.e("Error", error)
uiState.update(
SwapChooseErrorStateTransformer(
tokenName = params.token.name,

View file

@ -67,7 +67,10 @@ internal class SwapTransactionSender @AssistedInject constructor(
ExpressProviderType.DEX_BRIDGE,
ExpressProviderType.ONRAMP,
-> {
TangemLogger.w("Provider $providerType is not supported in Send With Swap")
TangemLogger.i(
messageString = "Provider $providerType is not supported in Send With Swap",
shouldSanitize = false,
)
onExpressError(ExpressError.UnknownError)
}
}

View file

@ -7,6 +7,7 @@ import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
import com.tangem.domain.account.status.usecase.GetFeePaidCryptoCurrencyStatusSyncUseCase
import com.tangem.domain.account.status.usecase.IsAccountsModeEnabledUseCase
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
@ -17,7 +18,6 @@ import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.swap.models.SwapDirection
import com.tangem.domain.account.status.usecase.GetFeePaidCryptoCurrencyStatusSyncUseCase
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
@ -32,9 +32,9 @@ import com.tangem.features.swap.v2.impl.sendviaswap.SendWithSwapRoute
import com.tangem.features.swap.v2.impl.sendviaswap.confirm.SendWithSwapConfirmComponent
import com.tangem.features.swap.v2.impl.sendviaswap.entity.SendWithSwapUM
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.logging.TangemLogger
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import com.tangem.utils.logging.TangemLogger
import javax.inject.Inject
import kotlin.properties.Delegates
@ -159,7 +159,7 @@ internal class SendWithSwapModel @Inject constructor(
getPrimaryCurrencyStatusUpdates(params.currency)
},
ifLeft = { error ->
TangemLogger.w(error.toString())
TangemLogger.e(error.toString())
swapAlertFactory.getGenericErrorState(
expressError = ExpressError.UnknownError,
onFailedTxEmailClick = {

View file

@ -249,7 +249,7 @@ internal class DefaultSwapRepository(
)
},
catch = { exception ->
TangemLogger.e("getExchangeStatus error: $exception")
TangemLogger.e("getExchangeStatus error", exception)
raise(UnknownError(exception.message))
},
)

View file

@ -208,6 +208,7 @@ internal class SwapInteractorImpl @Inject constructor(
|- amountToSwap: $amountToSwap
|- selectedFee: $txFeeSealedState
""".trimIndent(),
shouldSanitize = false,
)
val amountDecimal = toBigDecimalOrNull(amountToSwap)
@ -562,6 +563,7 @@ internal class SwapInteractorImpl @Inject constructor(
|- includeFeeInAmount: $includeFeeInAmount
|- fee: $fee
""".trimIndent(),
shouldSanitize = false,
)
val userWallet = fromSwapCurrencyStatus.userWallet
@ -1364,9 +1366,7 @@ internal class SwapInteractorImpl @Inject constructor(
reduceBalanceBy: BigDecimal,
feeValue: BigDecimal,
): IncludeFeeInAmount {
val feePaidCurrency = getFeePaidCurrency(fromSwapCurrencyStatus)
return when (feePaidCurrency) {
return when (val feePaidCurrency = getFeePaidCurrency(fromSwapCurrencyStatus)) {
is FeePaidCurrency.Token -> {
if (feePaidCurrency.balance > feeValue) {
IncludeFeeInAmount.Excluded
@ -1433,8 +1433,7 @@ internal class SwapInteractorImpl @Inject constructor(
vararg fees: BigDecimal,
): List<String> {
val appCurrency = getSelectedAppCurrencyUseCase.unwrap()
val feePaidCurrency = getFeePaidCurrency(fromSwapCurrencyStatus)
val feeCurrencyId: CryptoCurrency.ID = when (feePaidCurrency) {
val feeCurrencyId: CryptoCurrency.ID = when (val feePaidCurrency = getFeePaidCurrency(fromSwapCurrencyStatus)) {
is FeePaidCurrency.Token -> feePaidCurrency.tokenId
else -> getNativeToken(fromSwapCurrencyStatus).id
}
@ -2195,7 +2194,7 @@ internal class SwapInteractorImpl @Inject constructor(
return try {
SolanaTransactionHelper.removeSignaturesPlaceholders(hash)
} catch (e: Exception) {
TangemLogger.e("Failed to format the hash: ${e.message.orEmpty()}")
TangemLogger.e("Failed to format the hash: ${e.message.orEmpty()}", e)
hash
}
}

View file

@ -157,9 +157,10 @@ internal class DefaultSwapComponent @AssistedInject constructor(
LaunchedEffect(fromCryptoCurrency, feePaidCryptoCurrency, shouldHideBlock) {
if (shouldHideBlock) {
TangemLogger.e(
"Dismissing fee selector: " +
messageString = "Dismissing fee selector: " +
"shouldHideBlock = $shouldHideBlock, amount = ${dataState.amount}, " +
"isInsufficientFunds = ${model.uiState.isInsufficientFunds}",
shouldSanitize = false,
)
slotNavigation.dismiss()
return@LaunchedEffect

View file

@ -10,6 +10,7 @@ import com.arkivanov.decompose.router.slot.SlotNavigation
import com.arkivanov.decompose.router.slot.activate
import com.arkivanov.decompose.router.slot.dismiss
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.common.TangemBlogUrlBuilder
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.core.analytics.api.AnalyticsErrorHandler
@ -69,9 +70,6 @@ import com.tangem.domain.transaction.usecase.gasless.IsGaslessFeeSupportedForNet
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.feature.swap.analytics.SwapEvents
import com.tangem.feature.swap.analytics.SwapQuotePerformanceTracker
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenAnalyticsPayload
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult
import com.tangem.feature.swap.component.SwapFeeSelectorBlockComponent
import com.tangem.feature.swap.converters.SwapTransactionErrorStateConverter
import com.tangem.feature.swap.domain.AllowPermissionsHandler
@ -94,9 +92,11 @@ import com.tangem.feature.swap.ui.StateBuilder
import com.tangem.feature.swap.utils.formatToUIRepresentation
import com.tangem.feature.swap.utils.getContractAddress
import com.tangem.features.approval.api.GiveApprovalComponent
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenAnalyticsPayload
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenBridge
import com.tangem.features.commonfeatures.api.choosetoken.ChooseTokenResult
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
import com.tangem.features.send.v2.api.subcomponents.feeSelector.FeeSelectorReloadTrigger
import com.tangem.common.TangemBlogUrlBuilder
import com.tangem.features.swap.SwapComponent
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.*
@ -650,10 +650,16 @@ internal class SwapModel @Inject constructor(
userWalletId = fromSwapCurrencyStatus.userWalletId,
cryptoCurrencyStatus = fromSwapCurrencyStatus.status,
).onLeft {
TangemLogger.e("Unable to get fee paid crypto currency status for ${fromCryptoCurrency.id}")
TangemLogger.e(
messageString = "Unable to get fee paid crypto currency status for ${fromCryptoCurrency.id}",
shouldSanitize = false,
)
}.onRight { currencyStatus ->
if (currencyStatus == null) {
TangemLogger.e("Fee paid crypto currency status is null for ${fromCryptoCurrency.id}")
TangemLogger.e(
messageString = "Fee paid crypto currency status is null for ${fromCryptoCurrency.id}",
shouldSanitize = false,
)
}
}.getOrNull()
}
@ -722,7 +728,7 @@ internal class SwapModel @Inject constructor(
}
},
onError = { error ->
TangemLogger.e("Error when loading quotes: $error")
TangemLogger.e("Error when loading quotes", error)
performanceTracker.onLoadingFinished(hasError = true)
feeSelectorRepository.state.value = FeeSelectorUM.Error(GetFeeError.UnknownError, isHidden = true)
uiState = stateBuilder.addNotification(uiState, null) { startLoadingQuotesFromLastState() }
@ -966,6 +972,7 @@ internal class SwapModel @Inject constructor(
}.onSuccess { swapTransactionState ->
when (swapTransactionState) {
is SwapTransactionState.TxSent -> {
TangemLogger.i("onSwapClick: onSuccess: txHash: $swapTransactionState", shouldSanitize = false)
if (fee == null) {
TangemLogger.e("onSwapClick: onSuccess: fee is null after swap")
showAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
@ -1015,6 +1022,10 @@ internal class SwapModel @Inject constructor(
showDemoModeAlert()
}
is SwapTransactionState.Error -> {
TangemLogger.e(
messageString = "onSwapClick: swap transaction error: $swapTransactionState",
shouldSanitize = false,
)
startLoadingQuotesFromLastState()
showTransactionErrorAlert(swapTransactionState)
}
@ -1714,7 +1725,11 @@ internal class SwapModel @Inject constructor(
val feeStateUM = feeSelectorRepository.state.value as? FeeSelectorUM.Content
if (feeStateUM == null) {
TangemLogger.e("getSelectedFeeState: FeeSelectorUM is not Content: $feeStateUM, returning Legacy state")
TangemLogger.e(
messageString = "getSelectedFeeState: FeeSelectorUM is not Content: $feeStateUM, " +
"returning Legacy state",
shouldSanitize = false,
)
return TxFeeSealedState.Legacy(
txFeeState = TxFeeState.Empty,
selectedFee = dataState.selectedFee?.feeType ?: FeeType.NORMAL,
@ -1736,7 +1751,10 @@ internal class SwapModel @Inject constructor(
val feeStateUM = feeSelectorRepository.state.value as? FeeSelectorUM.Content
if (feeStateUM == null) {
TangemLogger.e("getSelectedFee: FeeSelectorUM is not Content: $feeStateUM, returning null")
TangemLogger.e(
messageString = "getSelectedFee: FeeSelectorUM is not Content: $feeStateUM, returning null",
shouldSanitize = false,
)
return null
}
@ -1842,7 +1860,10 @@ internal class SwapModel @Inject constructor(
val selectedProvider = dataStateStateFlow.first { it.selectedProvider != null }.selectedProvider!!
if (dataState.lastLoadedSwapStates[selectedProvider] !is SwapState.QuotesLoadedState) {
TangemLogger.e("loadFee: Quotes not loaded ${dataState.lastLoadedSwapStates[selectedProvider]}")
TangemLogger.e(
messageString = "loadFee: Quotes not loaded ${dataState.lastLoadedSwapStates[selectedProvider]}",
shouldSanitize = false,
)
return Either.Left(GetFeeError.UnknownError)
}