diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt index fdf2b792de..019f0078eb 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt @@ -179,6 +179,7 @@ sealed class AnalyticsParam { const val ERROR_CODE = "Error Code" const val ERROR_KEY = "Error Key" const val ERROR_TYPE = "Error Type" + const val ERROR_MESSAGE = "Error Message" const val CREATION_TYPE = "Creation type" const val DAPP_NAME = "DApp Name" const val DAPP_URL = "DApp Url" diff --git a/core/analytics/src/main/java/com/tangem/core/analytics/di/AnalyticsModule.kt b/core/analytics/src/main/java/com/tangem/core/analytics/di/AnalyticsModule.kt index ccdb5cd9fa..4b7cab5808 100644 --- a/core/analytics/src/main/java/com/tangem/core/analytics/di/AnalyticsModule.kt +++ b/core/analytics/src/main/java/com/tangem/core/analytics/di/AnalyticsModule.kt @@ -2,6 +2,7 @@ package com.tangem.core.analytics.di import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.api.ParamsInterceptorHolder import com.tangem.core.analytics.filter.OneTimeEventFilter import com.tangem.domain.analytics.repository.AnalyticsRepository import dagger.Module @@ -20,6 +21,12 @@ internal object AnalyticsModule { return Analytics // todo replace after refactoring calling Analytics in whole project } + @Singleton + @Provides + fun provideParamsInterceptorHolder(): ParamsInterceptorHolder { + return Analytics // todo replace after refactoring calling Analytics in whole project + } + @Provides fun provideOneTimeEventFilter(analyticsRepository: AnalyticsRepository): OneTimeEventFilter { return OneTimeEventFilter(analyticsRepository) diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/adapter/UnknownEnumMoshiAdapter.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/adapter/UnknownEnumMoshiAdapter.kt index 1e8da548c6..c1d5670100 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/adapter/UnknownEnumMoshiAdapter.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/adapter/UnknownEnumMoshiAdapter.kt @@ -11,8 +11,6 @@ import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO.RewardT import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO.ValidatorDTO.ValidatorStatusDTO import com.tangem.datasource.api.stakekit.models.response.model.action.StakingActionStatusDTO import com.tangem.datasource.api.stakekit.models.response.model.action.StakingActionTypeDTO -import com.tangem.datasource.api.stakekit.models.response.model.error.AccessDeniedErrorTypeDTO -import com.tangem.datasource.api.stakekit.models.response.model.error.StakeKitErrorMessageDTO import com.tangem.datasource.api.stakekit.models.response.model.transaction.StakingTransactionStatusDTO import com.tangem.datasource.api.stakekit.models.response.model.transaction.StakingTransactionTypeDTO @@ -40,9 +38,6 @@ fun Moshi.Builder.addStakeKitEnumFallbackAdapters(): Moshi.Builder { StakingTransactionStatusDTO::class.java to StakingTransactionStatusDTO.UNKNOWN, StakingTransactionTypeDTO::class.java to StakingTransactionTypeDTO.UNKNOWN, ValidatorStatusDTO::class.java to ValidatorStatusDTO.UNKNOWN, - // error enums - AccessDeniedErrorTypeDTO::class.java to AccessDeniedErrorTypeDTO.UNKNOWN, - StakeKitErrorMessageDTO::class.java to StakeKitErrorMessageDTO.UNKNOWN, ) return apply { diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/stakekit/models/response/model/error/StakeKitErrorResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/stakekit/models/response/model/error/StakeKitErrorResponse.kt index 7da4850d56..fd62fdf3a5 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/stakekit/models/response/model/error/StakeKitErrorResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/stakekit/models/response/model/error/StakeKitErrorResponse.kt @@ -3,18 +3,21 @@ package com.tangem.datasource.api.stakekit.models.response.model.error import com.squareup.moshi.Json class StakeKitErrorResponse( + @Json(name = "message") + val message: String? = null, + @Json(name = "code") + val code: Int? = null, + @Json(name = "path") + val path: String? = null, + @Json(name = "details") val details: StakeKitErrorDetailsDTO? = null, - @Json(name = "message") - val message: StakeKitErrorMessageDTO? = null, @Json(name = "level") val level: String? = null, // unused // 403 @Json(name = "type") - val type: AccessDeniedErrorTypeDTO? = null, - @Json(name = "code") - val code: String? = null, + val type: String? = null, @Json(name = "countryCode") val countryCode: String?, @Json(name = "regionCode") @@ -31,134 +34,3 @@ data class StakeKitErrorDetailsDTO( @Json(name = "yieldId") val yieldId: String? = null, ) - -enum class AccessDeniedErrorTypeDTO { - @Json(name = "GEO_LOCATION") - GEO_LOCATION, - - UNKNOWN, -} - -enum class StakeKitErrorMessageDTO { - @Json(name = "MissingArgumentsError") - MISSING_ARGUMENTS_ERROR, - - @Json(name = "MinimumAmountNotReached") - MINIMUM_AMOUNT_NOT_REACHED, - - @Json(name = "YieldUnderMaintenanceError") - YIELD_UNDER_MAINTENANCE_ERROR, - - @Json(name = "InsufficientFundsError") - INSUFFICIENT_FUNDS_ERROR, - - @Json(name = "StakedPositionNotFoundError") - STAKED_POSITION_NOT_FOUND_ERROR, - - @Json(name = "InvalidAmountSubmittedError") - INVALID_AMOUNT_SUBMITTED_ERROR, - - @Json(name = "BalanceUnavailableError") - BALANCE_UNAVAILABLE_ERROR, - - @Json(name = "GasPriceUnavailableError") - GAS_PRICE_UNAVAILABLE_ERROR, - - @Json(name = "NotImplementedError") - NOT_IMPLEMENTED_ERROR, - - @Json(name = "TokenNotFoundError") - TOKEN_NOT_FOUND_ERROR, - - @Json(name = "BroadcastTransactionError") - BROADCAST_TRANSACTION_ERROR, - - @Json(name = "MissingGasPriceStrategyError") - MISSING_GAS_PRICE_STRATEGY_ERROR, - - @Json(name = "SubstrateMalformedTransactionHashError") - SUBSTRATE_MALFORMED_TRANSACTION_HASH_ERROR, - - @Json(name = "TronMaximumAmountOfValidatorsExceededError") - TRON_MAXIMUM_AMOUNT_OF_VALIDATORS_EXCEEDED_ERROR, - - @Json(name = "SubstratePoolNotFoundError") - SUBSTRATE_POOL_NOT_FOUND_ERROR, - - @Json(name = "SubstrateBondedAmountTooLowError") - SUBSTRATE_BONDED_AMOUNT_TOO_LOW_ERROR, - - @Json(name = "TronMissingResourceTypeArgumentError") - TRON_MISSING_RESOURCE_TYPE_ARGUMENT_ERROR, - - @Json(name = "AaveV3PoolFrozenError") - AAVE_V3_POOL_FROZEN_ERROR, - - @Json(name = "AaveV3TokenPairNotFoundError") - AAVE_V3_TOKEN_PAIR_NOT_FOUND_ERROR, - - @Json(name = "YearnVaultAtMaxCapacityError") - YEARN_VAULT_AT_MAX_CAPACITY_ERROR, - - @Json(name = "StETHNoWithdrawalRequestsFoundError") - STETH_NO_WITHDRAWAL_REQUESTS_FOUND_ERROR, - - @Json(name = "MorphoLendingPoolPausedError") - MORPHO_LENDING_POOL_PAUSED_ERROR, - - @Json(name = "NonceUnavailableError") - NONCE_UNAVAILABLE_ERROR, - - @Json(name = "CosmosAcccountNotFoundError") - COSMOS_ACCOUNT_NOT_FOUND_ERROR, - - @Json(name = "AvalancheMissingAdditionalAddressesArgumentError") - AVALANCHE_MISSING_ADDITIONAL_ADDRESSES_ARGUMENT_ERROR, - - @Json(name = "AvalancheValidatorInfoNotFoundError") - AVALANCHE_VALIDATOR_INFO_NOT_FOUND_ERROR, - - @Json(name = "SolanaTransactionSignatureVerificationFailureError") - SOLANA_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE_ERROR, - - @Json(name = "SolanaUnableTocreateStakeAccountError") - SOLANA_UNABLE_TO_CREATE_STAKE_ACCOUNT_ERROR, - - @Json(name = "SolanaStakeAmountTooLowError") - SOLANA_STAKE_AMOUNT_TOO_LOW_ERROR, - - @Json(name = "SolanaUnstakeAmountTooLowError") - SOLANA_UNSTAKE_AMOUNT_TOO_LOW_ERROR, - - @Json(name = "SolanaStakeAccountsNotFoundError") - SOLANA_STAKE_ACCOUNTS_NOT_FOUND_ERROR, - - @Json(name = "SolanaEligibleStakeAccountsNotFoundError") - SOLANA_ELIGIBLE_STAKE_ACCOUNTS_NOT_FOUND_ERROR, - - @Json(name = "TezosNoBalanceDelegatedError") - TEZOS_NO_BALANCE_DELEGATED_ERROR, - - @Json(name = "TezosMissingPubkeyArgumentError") - TEZOS_MISSING_PUBKEY_ARGUMENT_ERROR, - - @Json(name = "TezosEstimateRevealGasLimitError") - TEZOS_ESTIMATE_REVEAL_GAS_LIMIT_ERROR, - - @Json(name = "TezosBalanceAlreadyDelegatedError") - TEZOS_BALANCE_ALREADY_DELEGATED_ERROR, - - @Json(name = "BinanceAccountNotFoundError") - BINANCE_ACCOUNT_NOT_FOUND_ERROR, - - @Json(name = "BinanceMissingAccountNumberOrSequenceError") - BINANCE_MISSING_ACCOUNT_NUMBER_OR_SEQUENCE_ERROR, - - @Json(name = "GRTStakingDisabledError") - GRT_STAKING_DISABLED_ERROR, - - @Json(name = "GRTStakingDisabledLedgerLiveError") - GRT_STAKING_DISABLED_LEDGER_LIVE_ERROR, - - UNKNOWN, -} diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingErrorResolver.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingErrorResolver.kt index e10f7470c7..59f650e5ee 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingErrorResolver.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingErrorResolver.kt @@ -1,19 +1,36 @@ package com.tangem.data.staking +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.data.staking.converters.error.StakeKitErrorConverter import com.tangem.datasource.api.common.response.ApiResponseError +import com.tangem.domain.staking.analytics.StakingAnalyticsEvent import com.tangem.domain.staking.model.stakekit.StakingError import com.tangem.domain.staking.repositories.StakingErrorResolver internal class DefaultStakingErrorResolver( + private val analyticsEventHandler: AnalyticsEventHandler, private val stakeKitErrorConverter: StakeKitErrorConverter, ) : StakingErrorResolver { override fun resolve(throwable: Throwable): StakingError { - return if (throwable is ApiResponseError.HttpException) { + val error = if (throwable is ApiResponseError.HttpException) { stakeKitErrorConverter.convert(throwable.errorBody.orEmpty()) } else { - StakingError.UnknownError() + StakingError.DomainError(throwable.message) } + + when (error) { + is StakingError.StakeKitApiError -> { + analyticsEventHandler.send(StakingAnalyticsEvent.StakeKitApiError(error)) + } + is StakingError.StakeKitUnknownError -> { + analyticsEventHandler.send(StakingAnalyticsEvent.StakeKitApiUnknownError(error)) + } + else -> { + // intentionally do nothing + } + } + + return error } } diff --git a/data/staking/src/main/java/com/tangem/data/staking/converters/error/StakeKitErrorConverter.kt b/data/staking/src/main/java/com/tangem/data/staking/converters/error/StakeKitErrorConverter.kt index 7b28f1ba90..de14c82e39 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/converters/error/StakeKitErrorConverter.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/converters/error/StakeKitErrorConverter.kt @@ -1,8 +1,6 @@ package com.tangem.data.staking.converters.error import com.squareup.moshi.JsonAdapter -import com.tangem.datasource.api.stakekit.models.response.model.error.AccessDeniedErrorTypeDTO -import com.tangem.datasource.api.stakekit.models.response.model.error.StakeKitErrorMessageDTO import com.tangem.datasource.api.stakekit.models.response.model.error.StakeKitErrorResponse import com.tangem.domain.staking.model.stakekit.StakingError import com.tangem.utils.converter.Converter @@ -11,105 +9,18 @@ internal class StakeKitErrorConverter( private val jsonAdapter: JsonAdapter, ) : Converter { - @Suppress("CyclomaticComplexMethod", "LongMethod") override fun convert(value: String): StakingError { return try { - val stakeKitErrorResponse = jsonAdapter.fromJson(value) ?: return StakingError.UnknownError(value) + val stakeKitErrorResponse = jsonAdapter.fromJson(value) + ?: return StakingError.StakeKitUnknownError(value) - if (stakeKitErrorResponse.type == AccessDeniedErrorTypeDTO.GEO_LOCATION) { - StakingError.UnavailableDueToGeolocationError( - tags = stakeKitErrorResponse.tags ?: emptyList(), - ) - } - - when (stakeKitErrorResponse.message) { - StakeKitErrorMessageDTO.MINIMUM_AMOUNT_NOT_REACHED -> StakingError.MinimumAmountNotReachedError( - amount = stakeKitErrorResponse.details?.amount ?: "", - ) - StakeKitErrorMessageDTO.MISSING_ARGUMENTS_ERROR -> StakingError.MissingArgumentsError( - arguments = stakeKitErrorResponse.details?.arguments ?: "", - ) - StakeKitErrorMessageDTO.YIELD_UNDER_MAINTENANCE_ERROR -> StakingError.YieldUnderMaintenanceError( - yieldId = stakeKitErrorResponse.details?.yieldId ?: "", - ) - StakeKitErrorMessageDTO.INSUFFICIENT_FUNDS_ERROR -> - StakingError.InsufficientFundsError - StakeKitErrorMessageDTO.STAKED_POSITION_NOT_FOUND_ERROR -> - StakingError.StakedPositionNotFoundError - StakeKitErrorMessageDTO.INVALID_AMOUNT_SUBMITTED_ERROR -> - StakingError.InvalidAmountSubmittedError - StakeKitErrorMessageDTO.BALANCE_UNAVAILABLE_ERROR -> - StakingError.BalanceUnavailableError - StakeKitErrorMessageDTO.GAS_PRICE_UNAVAILABLE_ERROR -> - StakingError.GasPriceUnavailableError - StakeKitErrorMessageDTO.NOT_IMPLEMENTED_ERROR -> - StakingError.NotImplementedError - StakeKitErrorMessageDTO.TOKEN_NOT_FOUND_ERROR -> - StakingError.TokenNotFoundError - StakeKitErrorMessageDTO.BROADCAST_TRANSACTION_ERROR -> - StakingError.BroadcastTransactionError - StakeKitErrorMessageDTO.MISSING_GAS_PRICE_STRATEGY_ERROR -> - StakingError.MissingGasPriceStrategyError - StakeKitErrorMessageDTO.SUBSTRATE_MALFORMED_TRANSACTION_HASH_ERROR -> - StakingError.SubstrateMalformedTransactionHashError - StakeKitErrorMessageDTO.TRON_MAXIMUM_AMOUNT_OF_VALIDATORS_EXCEEDED_ERROR -> - StakingError.TronMaximumAmountOfValidatorsExceededError - StakeKitErrorMessageDTO.SUBSTRATE_POOL_NOT_FOUND_ERROR -> - StakingError.SubstratePoolNotFoundError - StakeKitErrorMessageDTO.SUBSTRATE_BONDED_AMOUNT_TOO_LOW_ERROR -> - StakingError.SubstrateBondedAmountTooLowError - StakeKitErrorMessageDTO.TRON_MISSING_RESOURCE_TYPE_ARGUMENT_ERROR -> - StakingError.TronMissingResourceTypeArgumentError - StakeKitErrorMessageDTO.AAVE_V3_POOL_FROZEN_ERROR -> - StakingError.AaveV3PoolFrozenError - StakeKitErrorMessageDTO.AAVE_V3_TOKEN_PAIR_NOT_FOUND_ERROR -> - StakingError.AaveV3TokenPairNotFoundError - StakeKitErrorMessageDTO.YEARN_VAULT_AT_MAX_CAPACITY_ERROR -> - StakingError.YearnVaultAtMaxCapacityError - StakeKitErrorMessageDTO.STETH_NO_WITHDRAWAL_REQUESTS_FOUND_ERROR -> - StakingError.StETHNoWithdrawalRequestsFoundError - StakeKitErrorMessageDTO.MORPHO_LENDING_POOL_PAUSED_ERROR -> - StakingError.MorphoLendingPoolPausedError - StakeKitErrorMessageDTO.NONCE_UNAVAILABLE_ERROR -> - StakingError.NonceUnavailableError - StakeKitErrorMessageDTO.COSMOS_ACCOUNT_NOT_FOUND_ERROR -> - StakingError.CosmosAcccountNotFoundError - StakeKitErrorMessageDTO.AVALANCHE_MISSING_ADDITIONAL_ADDRESSES_ARGUMENT_ERROR -> - StakingError.AvalancheMissingAdditionalAddressesArgumentError - StakeKitErrorMessageDTO.AVALANCHE_VALIDATOR_INFO_NOT_FOUND_ERROR -> - StakingError.AvalancheValidatorInfoNotFoundError - StakeKitErrorMessageDTO.SOLANA_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE_ERROR -> - StakingError.SolanaTransactionSignatureVerificationFailureError - StakeKitErrorMessageDTO.SOLANA_UNABLE_TO_CREATE_STAKE_ACCOUNT_ERROR -> - StakingError.SolanaUnableTocreateStakeAccountError - StakeKitErrorMessageDTO.SOLANA_STAKE_AMOUNT_TOO_LOW_ERROR -> - StakingError.SolanaStakeAmountTooLowError - StakeKitErrorMessageDTO.SOLANA_UNSTAKE_AMOUNT_TOO_LOW_ERROR -> - StakingError.SolanaUnstakeAmountTooLowError - StakeKitErrorMessageDTO.SOLANA_STAKE_ACCOUNTS_NOT_FOUND_ERROR -> - StakingError.SolanaStakeAccountsNotFoundError - StakeKitErrorMessageDTO.SOLANA_ELIGIBLE_STAKE_ACCOUNTS_NOT_FOUND_ERROR -> - StakingError.SolanaEligibleStakeAccountsNotFoundError - StakeKitErrorMessageDTO.TEZOS_NO_BALANCE_DELEGATED_ERROR -> - StakingError.TezosNoBalanceDelegatedError - StakeKitErrorMessageDTO.TEZOS_MISSING_PUBKEY_ARGUMENT_ERROR -> - StakingError.TezosMissingPubkeyArgumentError - StakeKitErrorMessageDTO.TEZOS_ESTIMATE_REVEAL_GAS_LIMIT_ERROR -> - StakingError.TezosEstimateRevealGasLimitError - StakeKitErrorMessageDTO.TEZOS_BALANCE_ALREADY_DELEGATED_ERROR -> - StakingError.TezosBalanceAlreadyDelegatedError - StakeKitErrorMessageDTO.BINANCE_ACCOUNT_NOT_FOUND_ERROR -> - StakingError.BinanceAccountNotFoundError - StakeKitErrorMessageDTO.BINANCE_MISSING_ACCOUNT_NUMBER_OR_SEQUENCE_ERROR -> - StakingError.BinanceMissingAccountNumberOrSequenceError - StakeKitErrorMessageDTO.GRT_STAKING_DISABLED_ERROR -> - StakingError.GRTStakingDisabledError - StakeKitErrorMessageDTO.GRT_STAKING_DISABLED_LEDGER_LIVE_ERROR -> - StakingError.GRTStakingDisabledLedgerLiveError - else -> StakingError.UnknownError(value) - } + return StakingError.StakeKitApiError( + message = stakeKitErrorResponse.message, + code = stakeKitErrorResponse.code, + methodName = stakeKitErrorResponse.path, + ) } catch (e: Exception) { - StakingError.UnknownError(value) + StakingError.StakeKitUnknownError(value) } } } diff --git a/data/staking/src/main/java/com/tangem/data/staking/di/StakingDataModule.kt b/data/staking/src/main/java/com/tangem/data/staking/di/StakingDataModule.kt index 5a58dfefe0..01e8534ee5 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/di/StakingDataModule.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/di/StakingDataModule.kt @@ -1,6 +1,7 @@ package com.tangem.data.staking.di import com.squareup.moshi.Moshi +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.data.common.cache.CacheRegistry import com.tangem.data.staking.DefaultStakingErrorResolver import com.tangem.data.staking.DefaultStakingPendingTransactionRepository @@ -79,10 +80,14 @@ internal object StakingDataModule { @Provides @Singleton - internal fun provideStakingErrorResolver(@NetworkMoshi moshi: Moshi): StakingErrorResolver { + internal fun provideStakingErrorResolver( + @NetworkMoshi moshi: Moshi, + analyticsEventHandler: AnalyticsEventHandler, + ): StakingErrorResolver { val jsonAdapter = moshi.adapter(StakeKitErrorResponse::class.java) return DefaultStakingErrorResolver( stakeKitErrorConverter = StakeKitErrorConverter(jsonAdapter), + analyticsEventHandler = analyticsEventHandler, ) } } diff --git a/domain/staking/build.gradle.kts b/domain/staking/build.gradle.kts index 687ef79f59..c47b3d1cf0 100644 --- a/domain/staking/build.gradle.kts +++ b/domain/staking/build.gradle.kts @@ -12,6 +12,7 @@ android { dependencies { api(projects.domain.staking.models) api(projects.domain.core) + api(projects.core.analytics) implementation(deps.kotlin.serialization) implementation(deps.jodatime) diff --git a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/StakingError.kt b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/StakingError.kt index 0356d09d59..af6ba0c5e3 100644 --- a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/StakingError.kt +++ b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/StakingError.kt @@ -4,93 +4,17 @@ sealed class StakingError { // region stakekit errors - data class MinimumAmountNotReachedError(val amount: String) : StakingError() - - data class MissingArgumentsError(val arguments: String) : StakingError() - - data class YieldUnderMaintenanceError(val yieldId: String) : StakingError() - - data object InsufficientFundsError : StakingError() - - data object StakedPositionNotFoundError : StakingError() - - data object InvalidAmountSubmittedError : StakingError() - - data object BalanceUnavailableError : StakingError() - - data object GasPriceUnavailableError : StakingError() - - data object NotImplementedError : StakingError() - - data object TokenNotFoundError : StakingError() - - data object BroadcastTransactionError : StakingError() - - data object MissingGasPriceStrategyError : StakingError() - - data object SubstrateMalformedTransactionHashError : StakingError() - - data object TronMaximumAmountOfValidatorsExceededError : StakingError() - - data object SubstratePoolNotFoundError : StakingError() - - data object SubstrateBondedAmountTooLowError : StakingError() - - data object TronMissingResourceTypeArgumentError : StakingError() - - data object AaveV3PoolFrozenError : StakingError() - - data object AaveV3TokenPairNotFoundError : StakingError() - - data object YearnVaultAtMaxCapacityError : StakingError() - - data object StETHNoWithdrawalRequestsFoundError : StakingError() - - data object MorphoLendingPoolPausedError : StakingError() - - data object NonceUnavailableError : StakingError() - - data object CosmosAcccountNotFoundError : StakingError() - - data object AvalancheMissingAdditionalAddressesArgumentError : StakingError() - - data object AvalancheValidatorInfoNotFoundError : StakingError() - - data object SolanaTransactionSignatureVerificationFailureError : StakingError() - - data object SolanaUnableTocreateStakeAccountError : StakingError() - - data object SolanaStakeAmountTooLowError : StakingError() - - data object SolanaUnstakeAmountTooLowError : StakingError() - - data object SolanaStakeAccountsNotFoundError : StakingError() - - data object SolanaEligibleStakeAccountsNotFoundError : StakingError() - - data object TezosNoBalanceDelegatedError : StakingError() - - data object TezosMissingPubkeyArgumentError : StakingError() - - data object TezosEstimateRevealGasLimitError : StakingError() - - data object TezosBalanceAlreadyDelegatedError : StakingError() - - data object BinanceAccountNotFoundError : StakingError() - - data object BinanceMissingAccountNumberOrSequenceError : StakingError() - - data object GRTStakingDisabledError : StakingError() - - data object GRTStakingDisabledLedgerLiveError : StakingError() + data class StakeKitApiError( + val message: String?, + val code: Int?, + val methodName: String?, + ) : StakingError() - data class UnavailableDueToGeolocationError( - val tags: List, + data class StakeKitUnknownError( + val jsonString: String? = null, ) : StakingError() // endregion - data class DataError(val cause: Throwable) : StakingError() - - data class UnknownError(val message: String? = null) : StakingError() + data class DomainError(val message: String?) : StakingError() } diff --git a/domain/staking/src/main/java/com/tangem/domain/staking/analytics/StakingAnalyticsEvent.kt b/domain/staking/src/main/java/com/tangem/domain/staking/analytics/StakingAnalyticsEvent.kt new file mode 100644 index 0000000000..7fbd04f22f --- /dev/null +++ b/domain/staking/src/main/java/com/tangem/domain/staking/analytics/StakingAnalyticsEvent.kt @@ -0,0 +1,152 @@ +package com.tangem.domain.staking.analytics + +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.domain.staking.analytics.StakingAnalyticsEvent.ButtonRewards.addIfValueIsNotNull +import com.tangem.domain.staking.model.stakekit.StakingError +import com.tangem.domain.staking.model.stakekit.action.StakingActionType + +sealed class StakingAnalyticsEvent( + event: String, + params: Map = mapOf(), +) : AnalyticsEvent( + category = "Staking", + event = event, + params = params, +) { + + data class StakingInfoScreenOpened( + val validatorsCount: Int, + ) : StakingAnalyticsEvent( + event = "Staking Info Screen Opened", + params = mapOf( + "Validators Count" to validatorsCount.toString(), + ), + ) + + data object WhatIsStaking : StakingAnalyticsEvent( + event = "Link - What Is Staking", + ) + + data object AmountScreenOpened : StakingAnalyticsEvent( + event = "Amount Screen Opened", + ) + + data class ConfirmationScreenOpened( + val validator: String, + val action: StakingActionType, + ) : StakingAnalyticsEvent( + event = "Confirmation Screen Opened", + params = mapOf( + "Validator" to validator, + "Action" to action.asAnalyticName, + ), + ) + + data class StakeInProgressScreenOpened( + val validator: String, + val action: StakingActionType, + ) : StakingAnalyticsEvent( + event = "Stake In Progress Screen Opened", + params = mapOf( + "Validator" to validator, + "Action" to action.asAnalyticName, + ), + ) + + data object RewardScreenOpened : StakingAnalyticsEvent( + event = "Reward Screen Opened", + ) + + data class AmountSelectCurrency( + val isAppCurrency: Boolean, + ) : StakingAnalyticsEvent( + event = "Selected Currency", + params = mapOf( + AnalyticsParam.TYPE to if (isAppCurrency) "App Currency" else "Token", + ), + ) + + data object ButtonMax : StakingAnalyticsEvent( + event = "Button - Max", + ) + + data class ButtonCancel( + val source: StakeScreenSource, + ) : StakingAnalyticsEvent( + event = "Button - Cancel", + params = mapOf( + AnalyticsParam.SOURCE to source.name, + ), + ) + + data class ValidatorChosen( + val validator: String, + ) : StakingAnalyticsEvent( + event = "Validator Chosen", + params = mapOf( + "Validator" to validator, + ), + ) + + data class ButtonValidator( + val source: StakeScreenSource, + ) : StakingAnalyticsEvent( + event = "Button - Validator", + params = mapOf( + AnalyticsParam.SOURCE to source.name, + ), + ) + + data object ButtonRewards : StakingAnalyticsEvent( + event = "Button - Rewards", + ) + + data class ButtonAction( + val action: StakingActionType, + val validator: String, + ) : StakingAnalyticsEvent( + event = "Button - ${action.asAnalyticName}", + params = mapOf( + "Validator" to validator, + ), + ) + + data object ButtonShare : StakingAnalyticsEvent(event = "Button - Share") + + data object ButtonExplore : StakingAnalyticsEvent(event = "Button - Explore") + + data class StakeKitApiError( + val stakingError: StakingError.StakeKitApiError, + ) : StakingAnalyticsEvent( + event = "Errors", + params = buildMap { + addIfValueIsNotNull(AnalyticsParam.ERROR_MESSAGE, stakingError.message) + addIfValueIsNotNull(AnalyticsParam.ERROR_CODE, stakingError.code) + addIfValueIsNotNull(AnalyticsParam.METHOD_NAME, stakingError.methodName) + }, + ) + + data class StakeKitApiUnknownError( + val stakeKitUnknownError: StakingError.StakeKitUnknownError, + ) : StakingAnalyticsEvent( + event = "Errors", + params = buildMap { + addIfValueIsNotNull(AnalyticsParam.ERROR_DESCRIPTION, stakeKitUnknownError.jsonString) + }, + ) + + fun MutableMap.addIfValueIsNotNull(key: String, value: Any?) { + if (value != null) { + put(key, value.toString()) + } + } + + data object TransactionError : StakingAnalyticsEvent( + event = "Error - Transaction Rejected", + ) +} + +enum class StakeScreenSource { + Info, Amount, Confirmation, Validators, +} diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/StakingAnalyticsEvents.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/StakingAnalyticsEvents.kt deleted file mode 100644 index fd1b9dde5f..0000000000 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/StakingAnalyticsEvents.kt +++ /dev/null @@ -1,179 +0,0 @@ -package com.tangem.features.staking.impl.analytics - -import com.tangem.core.analytics.models.AnalyticsEvent -import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.domain.staking.model.stakekit.StakingError -import com.tangem.domain.staking.model.stakekit.action.StakingActionType - -internal sealed class StakingAnalyticsEvents( - event: String, - params: Map = mapOf(), -) : AnalyticsEvent( - category = "Staking", - event = event, - params = params, -) { - - data class StakingInfoScreenOpened( - val validatorsCount: Int, - val token: String, - ) : StakingAnalyticsEvents( - event = "Staking Info Screen Opened", - params = mapOf( - "Validators Count" to validatorsCount.toString(), - AnalyticsParam.TOKEN_PARAM to token, - ), - ) - - data class WhatIsStaking(val token: String) : StakingAnalyticsEvents( - event = "Link - What Is Staking", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - ), - ) - - data class AmountScreenOpened(val token: String) : StakingAnalyticsEvents( - event = "Amount Screen Opened", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - ), - ) - - data class ConfirmationScreenOpened( - val token: String, - val validator: String, - val action: StakingActionType, - ) : StakingAnalyticsEvents( - event = "Confirmation Screen Opened", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - "Validator" to validator, - "Action" to action.asAnalyticName, - ), - ) - - data class StakeInProgressScreenOpened( - val validator: String, - val token: String, - val action: StakingActionType, - ) : StakingAnalyticsEvents( - event = "Stake In Progress Screen Opened", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - "Validator" to validator, - "Action" to action.asAnalyticName, - ), - ) - - data class RewardScreenOpened(val token: String) : StakingAnalyticsEvents( - event = "Reward Screen Opened", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - ), - ) - - data class AmountSelectCurrency( - val token: String, - val isAppCurrency: Boolean, - ) : StakingAnalyticsEvents( - event = "Selected Currency", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - AnalyticsParam.TYPE to if (isAppCurrency) "App Currency" else "Token", - ), - ) - - data class ButtonMax(val token: String) : StakingAnalyticsEvents( - event = "Button - Max", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - ), - ) - - data class ButtonCancel( - val source: StakeScreenSource, - val token: String, - ) : StakingAnalyticsEvents( - event = "Button - Cancel", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - AnalyticsParam.SOURCE to source.name, - ), - ) - - data class ValidatorChosen( - val token: String, - val validator: String, - ) : StakingAnalyticsEvents( - event = "Validator Chosen", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - "Validator" to validator, - ), - ) - - data class ButtonValidator( - val source: StakeScreenSource, - val token: String, - ) : StakingAnalyticsEvents( - event = "Button - Validator", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - AnalyticsParam.SOURCE to source.name, - ), - ) - - data class ButtonRewards( - val token: String, - ) : StakingAnalyticsEvents( - event = "Button - Rewards", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - ), - ) - - data class ButtonAction( - val action: StakingActionType, - val token: String, - val validator: String, - ) : StakingAnalyticsEvents( - event = "Button - ${action.asAnalyticName}", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - "Validator" to validator, - ), - ) - - data object ButtonShare : StakingAnalyticsEvents(event = "Button - Share") - - data object ButtonExplore : StakingAnalyticsEvents(event = "Button - Explore") - - data class StakekitError( - val token: String, - val stakeKitError: StakingError, - ) : StakingAnalyticsEvents( - event = "Errors", - params = mapOf( - AnalyticsParam.TOKEN_PARAM to token, - if (stakeKitError is StakingError.UnknownError) { - AnalyticsParam.ERROR_DESCRIPTION to (stakeKitError.message ?: "Unknown") - } else { - AnalyticsParam.ERROR_TYPE to stakeKitError.javaClass.simpleName - }, - ), - ) - - data class TransactionError( - val token: String, - ) : StakingAnalyticsEvents( - event = "Error - Transaction Rejected", - params = mapOf(AnalyticsParam.TOKEN_PARAM to token), - ) -} - -enum class StakeScreenSource { - Info, - Amount, - Confirmation, - Validators, -} diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/StakingParamsInterceptor.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/StakingParamsInterceptor.kt new file mode 100644 index 0000000000..caf3875be7 --- /dev/null +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/StakingParamsInterceptor.kt @@ -0,0 +1,23 @@ +package com.tangem.features.staking.impl.analytics + +import com.tangem.core.analytics.api.ParamsInterceptor +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.domain.staking.analytics.StakingAnalyticsEvent + +class StakingParamsInterceptor(private val tokenSymbol: String) : ParamsInterceptor { + + override fun id() = ID + + override fun canBeAppliedTo(event: AnalyticsEvent): Boolean { + return event is StakingAnalyticsEvent + } + + override fun intercept(params: MutableMap) { + params[AnalyticsParam.TOKEN_PARAM] = tokenSymbol + } + + companion object { + const val ID = "StakingParamsInterceptorId" + } +} diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/utils/StakingAnalyticSender.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/utils/StakingAnalyticSender.kt index e3ba1be1d3..f2a427e0cf 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/utils/StakingAnalyticSender.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/analytics/utils/StakingAnalyticSender.kt @@ -7,8 +7,8 @@ import com.tangem.core.analytics.models.Basic import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType import com.tangem.domain.staking.model.stakekit.action.StakingActionType import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.features.staking.impl.analytics.StakeScreenSource -import com.tangem.features.staking.impl.analytics.StakingAnalyticsEvents +import com.tangem.domain.staking.analytics.StakeScreenSource +import com.tangem.domain.staking.analytics.StakingAnalyticsEvent import com.tangem.features.staking.impl.presentation.state.* internal class StakingAnalyticSender( @@ -24,9 +24,8 @@ internal class StakingAnalyticSender( ?.size ?: 0 analyticsEventHandler.send( - StakingAnalyticsEvents.StakingInfoScreenOpened( + StakingAnalyticsEvent.StakingInfoScreenOpened( validatorsCount = validatorCount, - token = value.cryptoCurrencySymbol, ), ) } @@ -39,8 +38,7 @@ internal class StakingAnalyticSender( if (confirmationState.innerState == InnerConfirmationStakingState.COMPLETED) return analyticsEventHandler.send( - StakingAnalyticsEvents.ConfirmationScreenOpened( - token = value.cryptoCurrencySymbol, + StakingAnalyticsEvent.ConfirmationScreenOpened( validator = validatorName, action = getStakingActionType(value), ), @@ -49,7 +47,7 @@ internal class StakingAnalyticSender( fun screenCancel(value: StakingUiState) { analyticsEventHandler.send( - StakingAnalyticsEvents.ButtonCancel( + StakingAnalyticsEvent.ButtonCancel( source = when (value.currentStep) { StakingStep.InitialInfo -> StakeScreenSource.Info StakingStep.Amount -> StakeScreenSource.Amount @@ -58,7 +56,6 @@ internal class StakingAnalyticSender( StakingStep.RewardsValidators, -> StakeScreenSource.Validators }, - token = value.cryptoCurrencyName, ), ) } @@ -93,9 +90,8 @@ internal class StakingAnalyticSender( ), ) analyticsEventHandler.send( - StakingAnalyticsEvents.StakeInProgressScreenOpened( + StakingAnalyticsEvent.StakeInProgressScreenOpened( validator = validatorName, - token = value.cryptoCurrencySymbol, action = getStakingActionType(value), ), ) @@ -107,9 +103,8 @@ internal class StakingAnalyticSender( val validatorName = validatorState?.chosenValidator?.name ?: return analyticsEventHandler.send( - StakingAnalyticsEvents.ButtonAction( + StakingAnalyticsEvent.ButtonAction( action = getStakingActionType(value), - token = value.cryptoCurrencySymbol, validator = validatorName, ), ) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt index 8bb9cc9238..c4f09d21b5 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingStateRouter.kt @@ -3,7 +3,7 @@ package com.tangem.features.staking.impl.presentation.state import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType -import com.tangem.features.staking.impl.analytics.StakingAnalyticsEvents +import com.tangem.domain.staking.analytics.StakingAnalyticsEvent import com.tangem.features.staking.impl.analytics.utils.StakingAnalyticSender internal class StakingStateRouter( @@ -60,16 +60,12 @@ internal class StakingStateRouter( } private fun showRewardsValidators() { - analyticsEventsHandler.send( - StakingAnalyticsEvents.RewardScreenOpened(stateController.value.cryptoCurrencySymbol), - ) + analyticsEventsHandler.send(StakingAnalyticsEvent.RewardScreenOpened) stateController.update { it.copy(currentStep = StakingStep.RewardsValidators) } } private fun showAmount() { - analyticsEventsHandler.send( - StakingAnalyticsEvents.AmountScreenOpened(stateController.value.cryptoCurrencySymbol), - ) + analyticsEventsHandler.send(StakingAnalyticsEvent.AmountScreenOpened) stateController.update { it.copy(currentStep = StakingStep.Amount) } } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingFeeTransactionLoader.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingFeeTransactionLoader.kt index cf771663dc..db4c6dcc0d 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingFeeTransactionLoader.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingFeeTransactionLoader.kt @@ -135,7 +135,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor( } if (result.isNullOrEmpty()) { - onStakingFeeError(StakingError.UnknownError()) + onStakingFeeError(StakingError.DomainError("Error estimating fee")) return } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt index ae51fe7ced..1d33ccae42 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/helpers/StakingTransactionSender.kt @@ -4,7 +4,6 @@ import arrow.core.getOrElse import com.tangem.blockchain.common.TransactionData import com.tangem.blockchain.common.transaction.Fee import com.tangem.common.ui.amountScreen.models.AmountState -import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.domain.staking.* import com.tangem.domain.staking.model.PendingTransaction import com.tangem.domain.staking.model.SubmitHashData @@ -20,7 +19,6 @@ import com.tangem.domain.transaction.usecase.SendTransactionUseCase import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase import com.tangem.domain.utils.convertToSdkAmount import com.tangem.domain.wallets.models.UserWallet -import com.tangem.features.staking.impl.analytics.StakingAnalyticsEvents import com.tangem.features.staking.impl.presentation.state.* import com.tangem.features.staking.impl.presentation.state.utils.checkAndCalculateSubtractedAmount import com.tangem.features.staking.impl.presentation.state.utils.isSolanaWithdraw @@ -46,7 +44,6 @@ internal class StakingTransactionSender @AssistedInject constructor( private val submitHashUseCase: SubmitHashUseCase, private val saveUnsubmittedHashUseCase: SaveUnsubmittedHashUseCase, private val savePendingTransactionUseCase: SavePendingTransactionUseCase, - private val analyticsEventHandler: AnalyticsEventHandler, @Assisted private val cryptoCurrencyStatus: CryptoCurrencyStatus, @Assisted private val userWallet: UserWallet, @Assisted private val yield: Yield, @@ -84,7 +81,7 @@ internal class StakingTransactionSender @AssistedInject constructor( ) if (fullTransactionsData.isNullOrEmpty()) { - onConstructError(StakingError.UnknownError()) + onConstructError(StakingError.DomainError("fullTransactionsData is null or empty")) return } @@ -198,12 +195,6 @@ internal class StakingTransactionSender @AssistedInject constructor( type = action?.type, ), ).getOrElse { - analyticsEventHandler.send( - StakingAnalyticsEvents.StakekitError( - token = state.cryptoCurrencySymbol, - stakeKitError = it, - ), - ) onConstructError(it) return emptyList() } @@ -255,13 +246,7 @@ internal class StakingTransactionSender @AssistedInject constructor( pendingTransaction = pendingTransaction, ), ) - .onLeft { error -> - analyticsEventHandler.send( - StakingAnalyticsEvents.StakekitError( - token = stateController.value.cryptoCurrencySymbol, - stakeKitError = error, - ), - ) + .onLeft { saveUnsubmittedHashUseCase.invoke( transactionId = transaction.id, transactionHash = transactionHash, diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/AddStakingErrorTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/AddStakingErrorTransformer.kt index ff835e1b85..125c28b52f 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/AddStakingErrorTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/AddStakingErrorTransformer.kt @@ -32,14 +32,8 @@ internal class AddStakingErrorTransformer( } private fun convertToNotification(error: StakingError): NotificationUM { - return when (error) { - is StakingError.StakedPositionNotFoundError -> StakingNotification.Error.StakedPositionNotFoundError( - message = error.toString(), - ) - // TODO staking - else -> StakingNotification.Error.Common( - subtitle = stringReference(error.toString()), - ) - } + return StakingNotification.Error.Common( + subtitle = stringReference(error.toString()), + ) } } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt index 7291330ff8..1ccacb1d43 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/viewmodel/StakingViewModel.kt @@ -15,6 +15,7 @@ import com.tangem.common.ui.bottomsheet.permission.state.ApproveType import com.tangem.common.ui.bottomsheet.permission.state.GiveTxPermissionBottomSheetConfig import com.tangem.common.ui.notifications.NotificationUM import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.analytics.api.ParamsInterceptorHolder import com.tangem.core.ui.haptic.TangemHapticEffect import com.tangem.core.ui.haptic.VibratorHapticManager import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase @@ -47,8 +48,9 @@ import com.tangem.domain.utils.convertToSdkAmount import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.usecase.GetUserWalletUseCase -import com.tangem.features.staking.impl.analytics.StakeScreenSource -import com.tangem.features.staking.impl.analytics.StakingAnalyticsEvents +import com.tangem.domain.staking.analytics.StakeScreenSource +import com.tangem.domain.staking.analytics.StakingAnalyticsEvent +import com.tangem.features.staking.impl.analytics.StakingParamsInterceptor import com.tangem.features.staking.impl.analytics.utils.StakingAnalyticSender import com.tangem.features.staking.impl.navigation.InnerStakingRouter import com.tangem.features.staking.impl.presentation.state.* @@ -106,6 +108,7 @@ internal class StakingViewModel @Inject constructor( private val stakingBalanceUpdater: StakingBalanceUpdater.Factory, private val analyticsEventHandler: AnalyticsEventHandler, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, + private val paramsInterceptorHolder: ParamsInterceptorHolder, @DelayedWork private val coroutineScope: CoroutineScope, savedStateHandle: SavedStateHandle, ) : ViewModel(), DefaultLifecycleObserver, StakingClickIntents { @@ -201,6 +204,7 @@ internal class StakingViewModel @Inject constructor( override fun onCleared() { super.onCleared() + paramsInterceptorHolder.removeParamsInterceptor(StakingParamsInterceptor.ID) approvalJobHolder.cancel() feeJobHolder.cancel() sendTransactionJobHolder.cancel() @@ -297,18 +301,12 @@ internal class StakingViewModel @Inject constructor( ) updateNotifications() }, - onStakingFeeError = { error -> - analyticsEventHandler.send( - StakingAnalyticsEvents.StakekitError( - value.cryptoCurrencySymbol, - error, - ), - ) + onStakingFeeError = { stateController.update(AddStakingErrorTransformer()) updateNotifications(GetFeeError.UnknownError) }, onFeeError = { error -> - analyticsEventHandler.send(StakingAnalyticsEvents.TransactionError(value.cryptoCurrencySymbol)) + analyticsEventHandler.send(StakingAnalyticsEvent.TransactionError) stateController.update(AddStakingErrorTransformer()) updateNotifications(error) }, @@ -336,13 +334,6 @@ internal class StakingViewModel @Inject constructor( transactionsInProgress.addAll(constructedTransactions) }, onConstructError = { error -> - Timber.e(error.toString()) - analyticsEventHandler.send( - StakingAnalyticsEvents.StakekitError( - token = value.cryptoCurrencySymbol, - stakeKitError = error, - ), - ) stakingEventFactory.createStakingErrorAlert(error) stateController.update(SetConfirmationStateResetAssentTransformer) }, @@ -353,7 +344,7 @@ internal class StakingViewModel @Inject constructor( }, onSendError = { error -> Timber.e(error.toString()) - analyticsEventHandler.send(StakingAnalyticsEvents.TransactionError(value.cryptoCurrencySymbol)) + analyticsEventHandler.send(StakingAnalyticsEvent.TransactionError) stakingEventFactory.createSendTransactionErrorAlert(error) stateController.update(SetConfirmationStateResetAssentTransformer) }, @@ -399,7 +390,7 @@ internal class StakingViewModel @Inject constructor( } override fun onInitialInfoBannerClick() { - analyticsEventHandler.send(StakingAnalyticsEvents.WhatIsStaking(value.cryptoCurrencySymbol)) + analyticsEventHandler.send(StakingAnalyticsEvent.WhatIsStaking) innerRouter.openUrl(WHAT_IS_STAKING_ARTICLE_URL) } @@ -446,22 +437,21 @@ internal class StakingViewModel @Inject constructor( } override fun onMaxValueClick() { - analyticsEventHandler.send(StakingAnalyticsEvents.ButtonMax(value.cryptoCurrencySymbol)) + analyticsEventHandler.send(StakingAnalyticsEvent.ButtonMax) stateController.update(AmountMaxValueStateTransformer(cryptoCurrencyStatus, yield)) } override fun onCurrencyChangeClick(isFiat: Boolean) { analyticsEventHandler.send( - StakingAnalyticsEvents.AmountSelectCurrency(value.cryptoCurrencySymbol, isFiat), + StakingAnalyticsEvent.AmountSelectCurrency(isFiat), ) stateController.update(AmountCurrencyChangeStateTransformer(cryptoCurrencyStatus, isFiat)) } override fun openValidators() { analyticsEventHandler.send( - StakingAnalyticsEvents.ButtonValidator( + StakingAnalyticsEvent.ButtonValidator( source = StakeScreenSource.Confirmation, - token = value.cryptoCurrencySymbol, ), ) stakingStateRouter.showValidators() @@ -469,18 +459,15 @@ internal class StakingViewModel @Inject constructor( override fun onValidatorSelect(validator: Yield.Validator) { analyticsEventHandler.send( - StakingAnalyticsEvents.ValidatorChosen( - value.cryptoCurrencySymbol, - validator.name, + StakingAnalyticsEvent.ValidatorChosen( + validator = validator.name, ), ) stateController.update(ValidatorSelectChangeTransformer(validator)) } override fun openRewardsValidators() { - analyticsEventHandler.send( - StakingAnalyticsEvents.ButtonRewards(value.cryptoCurrencySymbol), - ) + analyticsEventHandler.send(StakingAnalyticsEvent.ButtonRewards) val rewardsValidators = stateController.value.rewardsValidatorsState as? StakingStates.RewardsValidatorsState.Data val rewards = rewardsValidators?.rewards @@ -488,9 +475,8 @@ internal class StakingViewModel @Inject constructor( onActiveStake(rewards.first()) } else { analyticsEventHandler.send( - StakingAnalyticsEvents.ButtonValidator( + StakingAnalyticsEvent.ButtonValidator( source = StakeScreenSource.Info, - token = value.cryptoCurrencySymbol, ), ) onNextClick(actionTypeToOverwrite = StakingActionCommonType.PENDING_REWARDS) @@ -542,9 +528,8 @@ internal class StakingViewModel @Inject constructor( override fun onActiveStakeAnalytic() { analyticsEventHandler.send( - StakingAnalyticsEvents.ButtonValidator( + StakingAnalyticsEvent.ButtonValidator( source = StakeScreenSource.Info, - token = value.cryptoCurrencySymbol, ), ) } @@ -595,7 +580,7 @@ internal class StakingViewModel @Inject constructor( ).fold( ifLeft = { error -> Timber.e(error.toString()) - analyticsEventHandler.send(StakingAnalyticsEvents.TransactionError(value.cryptoCurrencySymbol)) + analyticsEventHandler.send(StakingAnalyticsEvent.TransactionError) stateController.update( SetConfirmationStateAssentApprovalTransformer( appCurrencyProvider = Provider { appCurrency }, @@ -617,7 +602,7 @@ internal class StakingViewModel @Inject constructor( ).fold( ifLeft = { error -> Timber.e(error.toString()) - analyticsEventHandler.send(StakingAnalyticsEvents.TransactionError(value.cryptoCurrencySymbol)) + analyticsEventHandler.send(StakingAnalyticsEvent.TransactionError) stateController.update( SetConfirmationStateAssentApprovalTransformer( appCurrencyProvider = Provider { appCurrency }, @@ -747,7 +732,7 @@ internal class StakingViewModel @Inject constructor( } override fun onExploreClick() { - analyticsEventHandler.send(StakingAnalyticsEvents.ButtonExplore) + analyticsEventHandler.send(StakingAnalyticsEvent.ButtonExplore) val confirmationDataState = uiState.value.confirmationState as? StakingStates.ConfirmationState.Data val transactionDoneState = confirmationDataState?.transactionDoneState as? TransactionDoneState.Content val txUrl = transactionDoneState?.txUrl @@ -761,7 +746,7 @@ internal class StakingViewModel @Inject constructor( val transactionDoneState = confirmationDataState?.transactionDoneState as? TransactionDoneState.Content val txUrl = transactionDoneState?.txUrl - analyticsEventHandler.send(StakingAnalyticsEvents.ButtonShare) + analyticsEventHandler.send(StakingAnalyticsEvent.ButtonShare) if (txUrl != null) { vibratorHapticManager.performOneTime(TangemHapticEffect.OneTime.Click) stakingEventFactory.createShareDialog(txUrl = txUrl) @@ -838,10 +823,12 @@ internal class StakingViewModel @Inject constructor( if (!isInitialInfoAnalyticSent) { isInitialInfoAnalyticSent = true val balances = status.value.yieldBalance as? YieldBalance.Data + paramsInterceptorHolder.addParamsInterceptor( + interceptor = StakingParamsInterceptor(status.currency.symbol), + ) analyticsEventHandler.send( - StakingAnalyticsEvents.StakingInfoScreenOpened( + StakingAnalyticsEvent.StakingInfoScreenOpened( validatorsCount = balances?.getValidatorsCount() ?: 0, - token = status.currency.symbol, ), ) }