Updated on 2026-08-14
This commit is contained in:
commit
6d3b416f0c
26 changed files with 231 additions and 517 deletions
|
|
@ -357,7 +357,10 @@ internal object TokensDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetCurrencyCheckUseCase(currencyChecksRepository: CurrencyChecksRepository): GetCurrencyCheckUseCase {
|
||||
return GetCurrencyCheckUseCase(currencyChecksRepository)
|
||||
fun provideGetCurrencyCheckUseCase(
|
||||
currencyChecksRepository: CurrencyChecksRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetCurrencyCheckUseCase {
|
||||
return GetCurrencyCheckUseCase(currencyChecksRepository, dispatchers)
|
||||
}
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@ object NotificationsFactory {
|
|||
if (!isAccountFunded && reserveAmount != null && reserveAmount > sendingAmount) {
|
||||
add(
|
||||
NotificationUM.Error.ReserveAmount(
|
||||
sendingAmount.format {
|
||||
reserveAmount.format {
|
||||
crypto(cryptoCurrency)
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
@ -30,135 +33,4 @@ data class StakeKitErrorDetailsDTO(
|
|||
val amount: String? = null,
|
||||
@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,
|
||||
}
|
||||
)
|
||||
|
|
@ -339,7 +339,7 @@
|
|||
<string name="manage_tokens_list_header_title">\nCoinMarketCap</string>
|
||||
<string name="manage_tokens_network_selector_native_subtitle">Blockchain, auf der die Kryptowährung ursprünglich erstellt wurde</string>
|
||||
<string name="manage_tokens_network_selector_native_title">Natives Netzwerk</string>
|
||||
<string name="manage_tokens_network_selector_non_native_info">Die Verwendung von nicht nativen Netzwerken für Token ermöglicht eine blockchainübergreifende Interoperabilität, sodass Vermögenswerte in verschiedenen dezentralen Anwendungen und Smart Contracts plattformübergreifend genutzt werden können. Dies erfordert jedoch häufig eine Verwahrstelle oder einen intelligenten Vertrag, um den ursprünglichen Vermögenswert sicher zu verwahren, was zu einer Zentralisierung und einem Kontrahentenrisiko führt.</string>
|
||||
<string name="manage_tokens_network_selector_non_native_info">Die Verwendung nicht-nativer Netzwerke für Token ermöglicht Interoperabilität zwischen Blockchains, sodass Vermögenswerte plattformübergreifend in verschiedenen dezentralen Anwendungen und Smart Contracts genutzt werden können. Dies erfordert jedoch häufig einen Verwahrer oder Smart Contract, um den ursprünglichen Vermögenswert sicher aufzubewahren, was zu Zentralisierung und Kontrahentenrisiken führt.</string>
|
||||
<string name="manage_tokens_network_selector_non_native_subtitle">Nicht die ursprüngliche oder primäre Blockchain, in der der Token gehostet wird</string>
|
||||
<string name="manage_tokens_network_selector_non_native_title">Nicht-native Netzwerke</string>
|
||||
<string name="manage_tokens_network_selector_title">Netzwerke auswählen</string>
|
||||
|
|
@ -710,7 +710,7 @@
|
|||
<string name="staking_details_market_rating">Marktbewertung</string>
|
||||
<string name="staking_details_metrics_block_header">Metriken</string>
|
||||
<string name="staking_details_minimum_requirement">Mindestanforderungen</string>
|
||||
<string name="staking_details_no_rewards_to_claim">Keine Belohnungen</string>
|
||||
<string name="staking_details_no_rewards_to_claim">Keine Belohnungen verfügbar</string>
|
||||
<string name="staking_details_reward_claiming">Belohnungen beanspruchen</string>
|
||||
<string name="staking_details_reward_claiming_info">Eine Möglichkeit, Staking-Belohnungen zu erhalten. Es kann automatisch oder manuell beansprucht werden.</string>
|
||||
<string name="staking_details_reward_schedule">Belohnungszeitplan</string>
|
||||
|
|
@ -760,7 +760,7 @@
|
|||
<string name="staking_reward_schedule_day">Täglich</string>
|
||||
<string name="staking_reward_schedule_each">Alle %s</string>
|
||||
<string name="staking_reward_schedule_each_day">Täglich</string>
|
||||
<string name="staking_reward_schedule_each_days">Alle %s</string>
|
||||
<string name="staking_reward_schedule_each_days">Alle %s Tage</string>
|
||||
<string name="staking_reward_schedule_each_plural">Jeder</string>
|
||||
<string name="staking_reward_schedule_epoch">Pro Epoche</string>
|
||||
<string name="staking_reward_schedule_era">Pro Ära</string>
|
||||
|
|
|
|||
|
|
@ -520,7 +520,7 @@
|
|||
</plurals>
|
||||
<string name="onboarding_seed_generate_title">Ваша seed-фраза</string>
|
||||
<plurals name="onboarding_seed_generate_words_count">
|
||||
<item quantity="one"></item>
|
||||
<item quantity="one">слово</item>
|
||||
<item quantity="few">%d слова</item>
|
||||
<item quantity="many">%d слів</item>
|
||||
<item quantity="other">%d слів</item>
|
||||
|
|
@ -741,7 +741,7 @@
|
|||
<string name="staking_details_unbonding_period_info">Період, який ви повинні чекати після запиту на виведення коштів зі стейкінгу, перш ніж токени стануть доступними.</string>
|
||||
<string name="staking_details_warmup_period">Період блокування</string>
|
||||
<string name="staking_details_warmup_period_info">Відведений час для активації участі в стейкінгу.</string>
|
||||
<string name="staking_give_permission_fee_footer">Комісія мережі за схвалення токену, щоб верифікувати, що саме ви даєте дозвіл на використання вашого токена для стейкінгу.</string>
|
||||
<string name="staking_give_permission_fee_footer">Комісія за схвалення токену, щоб верифікувати, що саме ви дозволяєте використання токена для стейкінгу.</string>
|
||||
<string name="staking_legal">Використовуючи функцію стейкінгу, ви погоджуєтесь з %1$s та %2$s</string>
|
||||
<string name="staking_locked">Заблоковано</string>
|
||||
<string name="staking_migrate">Перемістити</string>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -127,7 +127,7 @@ class YieldConverter(
|
|||
stakedBalance = validatorDTO.stakedBalance,
|
||||
votingPower = validatorDTO.votingPower,
|
||||
preferred = validatorDTO.preferred,
|
||||
isStrategicPartner = isStrategicPartner(address),
|
||||
isStrategicPartner = isStrategicPartner(validatorDTO.address, validatorDTO.name),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -180,11 +180,17 @@ class YieldConverter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun isStrategicPartner(validatorAddress: String): Boolean = PARTNERS.any { it == validatorAddress }
|
||||
private fun isStrategicPartner(validatorAddress: String?, validatorName: String): Boolean {
|
||||
return PARTNERS.any { it == validatorAddress } || PARTNERS_NAMES.any { it.equals(validatorName, true) }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val PARTNERS = listOf(
|
||||
"cosmosvaloper1wrx0x9m9ykdhw9sg04v7uljme53wuj03aa5d4f",
|
||||
"H2tJNyMHnRF6ahCQLQ1sSycM4FGchymuzyYzUqKEuydk",
|
||||
)
|
||||
val PARTNERS_NAMES = listOf(
|
||||
"Meria",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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<StakeKitErrorResponse>,
|
||||
) : Converter<String, StakingError> {
|
||||
|
||||
@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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.*
|
||||
import com.tangem.data.staking.DefaultStakingErrorResolver
|
||||
|
|
@ -83,10 +84,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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -4,93 +4,17 @@ sealed class StakingError {
|
|||
|
||||
// region stakekit errors
|
||||
|
||||
data class MinimumAmountNotReachedError(val amount: String) : StakingError()
|
||||
data class StakeKitApiError(
|
||||
val message: String?,
|
||||
val code: Int?,
|
||||
val methodName: 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 UnavailableDueToGeolocationError(
|
||||
val tags: List<String>,
|
||||
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()
|
||||
}
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
package com.tangem.features.staking.impl.analytics
|
||||
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
|
||||
|
||||
internal sealed class StakingAnalyticsEvents(
|
||||
sealed class StakingAnalyticsEvent(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent(
|
||||
|
|
@ -16,37 +17,27 @@ internal sealed class StakingAnalyticsEvents(
|
|||
|
||||
data class StakingInfoScreenOpened(
|
||||
val validatorsCount: Int,
|
||||
val token: String,
|
||||
) : StakingAnalyticsEvents(
|
||||
) : StakingAnalyticsEvent(
|
||||
event = "Staking Info Screen Opened",
|
||||
params = mapOf(
|
||||
"Validators Count" to validatorsCount.toString(),
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
),
|
||||
)
|
||||
|
||||
data class WhatIsStaking(val token: String) : StakingAnalyticsEvents(
|
||||
data object WhatIsStaking : StakingAnalyticsEvent(
|
||||
event = "Link - What Is Staking",
|
||||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
),
|
||||
)
|
||||
|
||||
data class AmountScreenOpened(val token: String) : StakingAnalyticsEvents(
|
||||
data object AmountScreenOpened : StakingAnalyticsEvent(
|
||||
event = "Amount Screen Opened",
|
||||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
),
|
||||
)
|
||||
|
||||
data class ConfirmationScreenOpened(
|
||||
val token: String,
|
||||
val validator: String,
|
||||
val action: StakingActionType,
|
||||
) : StakingAnalyticsEvents(
|
||||
) : StakingAnalyticsEvent(
|
||||
event = "Confirmation Screen Opened",
|
||||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
"Validator" to validator,
|
||||
"Action" to action.asAnalyticName,
|
||||
),
|
||||
|
|
@ -54,126 +45,108 @@ internal sealed class StakingAnalyticsEvents(
|
|||
|
||||
data class StakeInProgressScreenOpened(
|
||||
val validator: String,
|
||||
val token: String,
|
||||
val action: StakingActionType,
|
||||
) : StakingAnalyticsEvents(
|
||||
) : StakingAnalyticsEvent(
|
||||
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(
|
||||
data object RewardScreenOpened : StakingAnalyticsEvent(
|
||||
event = "Reward Screen Opened",
|
||||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
),
|
||||
)
|
||||
|
||||
data class AmountSelectCurrency(
|
||||
val token: String,
|
||||
val isAppCurrency: Boolean,
|
||||
) : StakingAnalyticsEvents(
|
||||
) : StakingAnalyticsEvent(
|
||||
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(
|
||||
data object ButtonMax : StakingAnalyticsEvent(
|
||||
event = "Button - Max",
|
||||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
),
|
||||
)
|
||||
|
||||
data class ButtonCancel(
|
||||
val source: StakeScreenSource,
|
||||
val token: String,
|
||||
) : StakingAnalyticsEvents(
|
||||
) : StakingAnalyticsEvent(
|
||||
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(
|
||||
) : StakingAnalyticsEvent(
|
||||
event = "Validator Chosen",
|
||||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
"Validator" to validator,
|
||||
),
|
||||
)
|
||||
|
||||
data class ButtonValidator(
|
||||
val source: StakeScreenSource,
|
||||
val token: String,
|
||||
) : StakingAnalyticsEvents(
|
||||
) : StakingAnalyticsEvent(
|
||||
event = "Button - Validator",
|
||||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
AnalyticsParam.SOURCE to source.name,
|
||||
),
|
||||
)
|
||||
|
||||
data class ButtonRewards(
|
||||
val token: String,
|
||||
) : StakingAnalyticsEvents(
|
||||
data object ButtonRewards : StakingAnalyticsEvent(
|
||||
event = "Button - Rewards",
|
||||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
),
|
||||
)
|
||||
|
||||
data class ButtonAction(
|
||||
val action: StakingActionType,
|
||||
val token: String,
|
||||
val validator: String,
|
||||
) : StakingAnalyticsEvents(
|
||||
) : StakingAnalyticsEvent(
|
||||
event = "Button - ${action.asAnalyticName}",
|
||||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
"Validator" to validator,
|
||||
),
|
||||
)
|
||||
|
||||
data object ButtonShare : StakingAnalyticsEvents(event = "Button - Share")
|
||||
data object ButtonShare : StakingAnalyticsEvent(event = "Button - Share")
|
||||
|
||||
data object ButtonExplore : StakingAnalyticsEvents(event = "Button - Explore")
|
||||
data object ButtonExplore : StakingAnalyticsEvent(event = "Button - Explore")
|
||||
|
||||
data class StakekitError(
|
||||
val token: String,
|
||||
val stakeKitError: StakingError,
|
||||
) : StakingAnalyticsEvents(
|
||||
data class StakeKitApiError(
|
||||
val stakingError: StakingError.StakeKitApiError,
|
||||
) : StakingAnalyticsEvent(
|
||||
event = "Errors",
|
||||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
AnalyticsParam.ERROR_TYPE to if (stakeKitError is StakingError.UnknownError) {
|
||||
stakeKitError.message ?: "Unknown"
|
||||
} else {
|
||||
stakeKitError.javaClass.simpleName
|
||||
},
|
||||
),
|
||||
params = buildMap {
|
||||
addIfValueIsNotNull(AnalyticsParam.ERROR_MESSAGE, stakingError.message)
|
||||
addIfValueIsNotNull(AnalyticsParam.ERROR_CODE, stakingError.code)
|
||||
addIfValueIsNotNull(AnalyticsParam.METHOD_NAME, stakingError.methodName)
|
||||
},
|
||||
)
|
||||
|
||||
data class TransactionError(
|
||||
val token: String,
|
||||
) : StakingAnalyticsEvents(
|
||||
data class StakeKitApiUnknownError(
|
||||
val stakeKitUnknownError: StakingError.StakeKitUnknownError,
|
||||
) : StakingAnalyticsEvent(
|
||||
event = "Errors",
|
||||
params = buildMap {
|
||||
addIfValueIsNotNull(AnalyticsParam.ERROR_DESCRIPTION, stakeKitUnknownError.jsonString)
|
||||
},
|
||||
)
|
||||
|
||||
fun MutableMap<String, String>.addIfValueIsNotNull(key: String, value: Any?) {
|
||||
if (value != null) {
|
||||
put(key, value.toString())
|
||||
}
|
||||
}
|
||||
|
||||
data object TransactionError : StakingAnalyticsEvent(
|
||||
event = "Error - Transaction Rejected",
|
||||
params = mapOf(AnalyticsParam.TOKEN_PARAM to token),
|
||||
)
|
||||
}
|
||||
|
||||
enum class StakeScreenSource {
|
||||
Info,
|
||||
Amount,
|
||||
Confirmation,
|
||||
Validators,
|
||||
Info, Amount, Confirmation, Validators,
|
||||
}
|
||||
|
|
@ -8,4 +8,5 @@ data class CryptoCurrencyCheck(
|
|||
val reserveAmount: BigDecimal?,
|
||||
val existentialDeposit: BigDecimal?,
|
||||
val utxoAmountLimit: UtxoAmountLimit?,
|
||||
val isAccountFunded: Boolean,
|
||||
)
|
||||
|
|
@ -4,10 +4,13 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
|||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
|
||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.math.BigDecimal
|
||||
|
||||
class GetCurrencyCheckUseCase(
|
||||
private val currencyChecksRepository: CurrencyChecksRepository,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
|
|
@ -15,27 +18,38 @@ class GetCurrencyCheckUseCase(
|
|||
currencyStatus: CryptoCurrencyStatus,
|
||||
amount: BigDecimal?,
|
||||
fee: BigDecimal?,
|
||||
recipientAddress: String? = null,
|
||||
): CryptoCurrencyCheck {
|
||||
val network = currencyStatus.currency.network
|
||||
val dustValue = currencyChecksRepository.getDustValue(userWalletId, network)
|
||||
val reserveAmount = currencyChecksRepository.getReserveAmount(userWalletId, network)
|
||||
val existentialDeposit = currencyChecksRepository.getExistentialDeposit(userWalletId, network)
|
||||
val utxoAmountLimit = if (amount != null && fee != null) {
|
||||
currencyChecksRepository.checkUtxoAmountLimit(
|
||||
userWalletId = userWalletId,
|
||||
network = network,
|
||||
amount = amount,
|
||||
fee = fee,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return withContext(dispatchers.io) {
|
||||
val network = currencyStatus.currency.network
|
||||
val dustValue = currencyChecksRepository.getDustValue(userWalletId, network)
|
||||
val reserveAmount = currencyChecksRepository.getReserveAmount(userWalletId, network)
|
||||
val existentialDeposit = currencyChecksRepository.getExistentialDeposit(userWalletId, network)
|
||||
val isAccountFunded = recipientAddress?.let {
|
||||
currencyChecksRepository.checkIfAccountFunded(
|
||||
userWalletId,
|
||||
network,
|
||||
recipientAddress,
|
||||
)
|
||||
} ?: false
|
||||
val utxoAmountLimit = if (amount != null && fee != null) {
|
||||
currencyChecksRepository.checkUtxoAmountLimit(
|
||||
userWalletId = userWalletId,
|
||||
network = network,
|
||||
amount = amount,
|
||||
fee = fee,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return CryptoCurrencyCheck(
|
||||
dustValue = dustValue,
|
||||
reserveAmount = reserveAmount,
|
||||
existentialDeposit = existentialDeposit,
|
||||
utxoAmountLimit = utxoAmountLimit,
|
||||
)
|
||||
CryptoCurrencyCheck(
|
||||
dustValue = dustValue,
|
||||
reserveAmount = reserveAmount,
|
||||
existentialDeposit = existentialDeposit,
|
||||
utxoAmountLimit = utxoAmountLimit,
|
||||
isAccountFunded = isAccountFunded,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ import kotlinx.coroutines.flow.map
|
|||
import java.math.BigDecimal
|
||||
|
||||
@Suppress("LongParameterList", "LargeClass")
|
||||
internal class SendNotificationFactory constructor(
|
||||
internal class SendNotificationFactory(
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val validateTransactionUseCase: ValidateTransactionUseCase,
|
||||
private val getCurrencyCheckUseCase: GetCurrencyCheckUseCase,
|
||||
|
|
@ -90,11 +90,14 @@ internal class SendNotificationFactory constructor(
|
|||
reduceAmountBy = reduceAmountBy,
|
||||
)
|
||||
val feeError = (feeState.feeSelectorState as? FeeSelectorState.Error)?.error
|
||||
|
||||
val recipientAddress = state.recipientState?.addressTextField?.value
|
||||
val currencyCheck = getCurrencyCheckUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currencyStatus = cryptoCurrencyStatus,
|
||||
amount = sendingAmount,
|
||||
fee = feeValue,
|
||||
recipientAddress = recipientAddress,
|
||||
)
|
||||
buildList {
|
||||
addErrorNotifications(
|
||||
|
|
@ -187,7 +190,7 @@ internal class SendNotificationFactory constructor(
|
|||
reserveAmount = currencyCheck.reserveAmount,
|
||||
sendingAmount = sendingAmount,
|
||||
cryptoCurrency = currency,
|
||||
isAccountFunded = false,
|
||||
isAccountFunded = currencyCheck.isAccountFunded,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<String, String>) {
|
||||
params[AnalyticsParam.TOKEN_PARAM] = tokenSymbol
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ID = "StakingParamsInterceptorId"
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -59,7 +57,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),
|
||||
),
|
||||
)
|
||||
|
|
@ -106,9 +102,8 @@ internal class StakingAnalyticSender(
|
|||
val validatorName = validatorState?.chosenValidator?.name ?: return
|
||||
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvents.ButtonAction(
|
||||
StakingAnalyticsEvent.ButtonAction(
|
||||
action = getStakingActionType(value),
|
||||
token = value.cryptoCurrencySymbol,
|
||||
validator = validatorName,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
@ -68,16 +68,12 @@ internal class StakingStateRouter(
|
|||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
}
|
||||
|
||||
if (result.isNullOrEmpty()) {
|
||||
onStakingFeeError(StakingError.UnknownError())
|
||||
onStakingFeeError(StakingError.DomainError("Error estimating fee"))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.SubmitHashData
|
||||
import com.tangem.domain.staking.model.stakekit.*
|
||||
|
|
@ -19,11 +18,7 @@ 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.FeeState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStateController
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
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.isComposePendingActions
|
||||
import com.tangem.utils.extensions.orZero
|
||||
|
|
@ -46,7 +41,6 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
|
||||
private val submitHashUseCase: SubmitHashUseCase,
|
||||
private val saveUnsubmittedHashUseCase: SaveUnsubmittedHashUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
@Assisted private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
@Assisted private val yield: Yield,
|
||||
|
|
@ -84,7 +78,7 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
)
|
||||
|
||||
if (fullTransactionsData.isNullOrEmpty()) {
|
||||
onConstructError(StakingError.UnknownError())
|
||||
onConstructError(StakingError.DomainError("fullTransactionsData is null or empty"))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -193,12 +187,6 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
type = action?.type,
|
||||
),
|
||||
).getOrElse {
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvents.StakekitError(
|
||||
token = state.cryptoCurrencySymbol,
|
||||
stakeKitError = it,
|
||||
),
|
||||
)
|
||||
onConstructError(it)
|
||||
return emptyList()
|
||||
}
|
||||
|
|
@ -243,13 +231,7 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
transactionHash = transactionHash,
|
||||
),
|
||||
)
|
||||
.onLeft { error ->
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvents.StakekitError(
|
||||
token = stateController.value.cryptoCurrencySymbol,
|
||||
stakeKitError = error,
|
||||
),
|
||||
)
|
||||
.onLeft {
|
||||
saveUnsubmittedHashUseCase.invoke(
|
||||
transactionId = transaction.id,
|
||||
transactionHash = transactionHash,
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -46,8 +47,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.*
|
||||
|
|
@ -73,6 +75,7 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import javax.inject.Inject
|
||||
|
|
@ -107,6 +110,7 @@ internal class StakingViewModel @Inject constructor(
|
|||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val getActionsUseCase: GetActionsUseCase,
|
||||
private val paramsInterceptorHolder: ParamsInterceptorHolder,
|
||||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel(), DefaultLifecycleObserver, StakingClickIntents {
|
||||
|
|
@ -205,6 +209,7 @@ internal class StakingViewModel @Inject constructor(
|
|||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
paramsInterceptorHolder.removeParamsInterceptor(StakingParamsInterceptor.ID)
|
||||
approvalJobHolder.cancel()
|
||||
feeJobHolder.cancel()
|
||||
sendTransactionJobHolder.cancel()
|
||||
|
|
@ -239,18 +244,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)
|
||||
},
|
||||
|
|
@ -278,12 +277,6 @@ internal class StakingViewModel @Inject constructor(
|
|||
transactionsInProgress.addAll(constructedTransactions)
|
||||
},
|
||||
onConstructError = { error ->
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvents.StakekitError(
|
||||
token = value.cryptoCurrencySymbol,
|
||||
stakeKitError = error,
|
||||
),
|
||||
)
|
||||
stakingEventFactory.createStakingErrorAlert(error)
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
},
|
||||
|
|
@ -293,7 +286,7 @@ internal class StakingViewModel @Inject constructor(
|
|||
stateController.update(SetConfirmationStateCompletedTransformer(txUrl))
|
||||
},
|
||||
onSendError = { error ->
|
||||
analyticsEventHandler.send(StakingAnalyticsEvents.TransactionError(value.cryptoCurrencySymbol))
|
||||
analyticsEventHandler.send(StakingAnalyticsEvent.TransactionError)
|
||||
stakingEventFactory.createSendTransactionErrorAlert(error)
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
},
|
||||
|
|
@ -339,7 +332,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)
|
||||
}
|
||||
|
||||
|
|
@ -381,22 +374,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()
|
||||
|
|
@ -404,9 +396,8 @@ 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(
|
||||
|
|
@ -418,9 +409,7 @@ internal class StakingViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
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
|
||||
|
|
@ -428,9 +417,8 @@ internal class StakingViewModel @Inject constructor(
|
|||
onActiveStake(rewards.first())
|
||||
} else {
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvents.ButtonValidator(
|
||||
StakingAnalyticsEvent.ButtonValidator(
|
||||
source = StakeScreenSource.Info,
|
||||
token = value.cryptoCurrencySymbol,
|
||||
),
|
||||
)
|
||||
stateController.update {
|
||||
|
|
@ -470,9 +458,8 @@ internal class StakingViewModel @Inject constructor(
|
|||
|
||||
override fun onActiveStakeAnalytic() {
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvents.ButtonValidator(
|
||||
StakingAnalyticsEvent.ButtonValidator(
|
||||
source = StakeScreenSource.Info,
|
||||
token = value.cryptoCurrencySymbol,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -522,7 +509,8 @@ internal class StakingViewModel @Inject constructor(
|
|||
userWalletId = userWalletId,
|
||||
).fold(
|
||||
ifLeft = { error ->
|
||||
analyticsEventHandler.send(StakingAnalyticsEvents.TransactionError(value.cryptoCurrencySymbol))
|
||||
Timber.e(error.toString())
|
||||
analyticsEventHandler.send(StakingAnalyticsEvent.TransactionError)
|
||||
stateController.update(
|
||||
SetConfirmationStateAssentApprovalTransformer(
|
||||
appCurrencyProvider = Provider { appCurrency },
|
||||
|
|
@ -543,7 +531,8 @@ internal class StakingViewModel @Inject constructor(
|
|||
network = tokenCryptoCurrency.network,
|
||||
).fold(
|
||||
ifLeft = { error ->
|
||||
analyticsEventHandler.send(StakingAnalyticsEvents.TransactionError(value.cryptoCurrencySymbol))
|
||||
Timber.e(error.toString())
|
||||
analyticsEventHandler.send(StakingAnalyticsEvent.TransactionError)
|
||||
stateController.update(
|
||||
SetConfirmationStateAssentApprovalTransformer(
|
||||
appCurrencyProvider = Provider { appCurrency },
|
||||
|
|
@ -673,7 +662,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
|
||||
|
|
@ -687,7 +676,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)
|
||||
|
|
@ -769,10 +758,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,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ markdownComposeView = "0.5.4"
|
|||
# endregion Other libraries
|
||||
|
||||
# region Tangem
|
||||
tangemBlockchainSdk = "develop-836"
|
||||
tangemBlockchainSdk = "develop-841"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-391"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue