Updated on 2026-08-14

This commit is contained in:
Tangem 2025-11-05 14:28:04 +03:00
commit f5b50fcbdd
88 changed files with 959 additions and 1080 deletions

View file

@ -22,7 +22,6 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.core.net.toUri
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import arrow.core.getOrElse
@ -44,11 +43,8 @@ import com.tangem.domain.settings.SetGoogleServicesAvailabilityUseCase
import com.tangem.domain.settings.ShouldInitiallyAskPermissionUseCase
import com.tangem.domain.settings.repositories.SettingsRepository
import com.tangem.domain.staking.SendUnsubmittedHashesUseCase
import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.usecase.ClearAllHotWalletContextualUnlockUseCase
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
import com.tangem.features.hotwallet.HotWalletFeatureToggles
import com.tangem.features.tangempay.TangemPayFeatureToggles
import com.tangem.features.tester.api.TesterMenuLauncher
@ -115,12 +111,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
@Inject
lateinit var sendUnsubmittedHashesUseCase: SendUnsubmittedHashesUseCase
@Inject
lateinit var getPolkadotCheckHasResetUseCase: GetPolkadotCheckHasResetUseCase
@Inject
lateinit var getPolkadotCheckHasImmortalUseCase: GetPolkadotCheckHasImmortalUseCase
@Inject
lateinit var analyticsEventsHandler: AnalyticsEventHandler
@ -228,7 +218,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
initContent()
observePolkadotAccountHealthCheck()
sendStakingUnsubmittedHashes()
checkGoogleServicesAvailability()
@ -436,27 +425,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
}
}
private fun observePolkadotAccountHealthCheck() {
lifecycleScope.launch {
getPolkadotCheckHasResetUseCase()
.flowWithLifecycle(lifecycle, minActiveState = Lifecycle.State.CREATED)
.distinctUntilChanged()
.collect {
analyticsEventsHandler.send(WalletScreenAnalyticsEvent.Token.PolkadotAccountReset(it.second))
}
}
lifecycleScope.launch {
getPolkadotCheckHasImmortalUseCase()
.flowWithLifecycle(lifecycle, minActiveState = Lifecycle.State.CREATED)
.distinctUntilChanged()
.collect { (_, hasImmortalTransaction) ->
analyticsEventsHandler.send(
WalletScreenAnalyticsEvent.Token.PolkadotImmortalTransactions(hasImmortalTransaction),
)
}
}
}
private fun sendStakingUnsubmittedHashes() {
lifecycleScope.launch {
sendUnsubmittedHashesUseCase.invoke()

View file

@ -15,6 +15,7 @@ import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
import com.tangem.crypto.bip39.Wordlist
import com.tangem.data.card.sdk.CardSdkOwner
import com.tangem.data.card.sdk.CardSdkProvider
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.api.common.config.ApiConfig
import com.tangem.datasource.api.common.config.ApiEnvironmentConfig
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
@ -28,6 +29,7 @@ import com.tangem.sdk.nfc.AndroidNfcAvailabilityProvider
import com.tangem.sdk.nfc.NfcManager
import com.tangem.sdk.storage.create
import com.tangem.tap.foregroundActivityObserver
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.info.AppInfoProvider
import com.tangem.utils.version.AppVersionProvider
@ -48,6 +50,7 @@ internal class DefaultCardSdkProvider @Inject constructor(
private val apiConfigsManager: ApiConfigsManager,
appVersionProvider: AppVersionProvider,
appInfoProvider: AppInfoProvider,
authProvider: AuthProvider,
) : CardSdkProvider, CardSdkOwner {
private val observer = Observer()
@ -68,13 +71,16 @@ internal class DefaultCardSdkProvider @Inject constructor(
},
)
val apiEnvironment = Provider {
apiConfigsManager.getEnvironmentConfig(ApiConfig.ID.TangemTech).environment
}
val platformHeaders = RequestHeader.AppVersionPlatformHeaders(
appVersionProvider = appVersionProvider,
appInfoProvider = appInfoProvider,
)
val apiKeyHeader = RequestHeader.TangemApiKeyHeader(authProvider, apiEnvironment)
TangemApiServiceSettings.addInterceptors(
AddHeadersInterceptor(
requestHeader = RequestHeader.AppVersionPlatformHeaders(
appVersionProvider = appVersionProvider,
appInfoProvider = appInfoProvider,
),
),
AddHeadersInterceptor(platformHeaders.values + apiKeyHeader.values),
)
}

View file

@ -6,10 +6,7 @@ import com.tangem.domain.card.ScanCardUseCase
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.express.ExpressServiceFetcher
import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.sdk.api.TangemSdkManager
import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository
@ -83,20 +80,4 @@ internal object ActivityModule {
userWalletProvider = { getSelectedWalletUseCase.sync().getOrNull() },
)
}
@Provides
@Singleton
fun provideGetPolkadotCheckHasResetUseCase(
polkadotAccountHealthCheckRepository: PolkadotAccountHealthCheckRepository,
): GetPolkadotCheckHasResetUseCase {
return GetPolkadotCheckHasResetUseCase(polkadotAccountHealthCheckRepository)
}
@Provides
@Singleton
fun provideGetPolkadotCheckHasImmortalUseCase(
polkadotAccountHealthCheckRepository: PolkadotAccountHealthCheckRepository,
): GetPolkadotCheckHasImmortalUseCase {
return GetPolkadotCheckHasImmortalUseCase(polkadotAccountHealthCheckRepository)
}
}

View file

@ -1,6 +1,5 @@
package com.tangem.tap.di.domain
import com.tangem.domain.wallets.derivations.DerivationsRepository
import com.tangem.domain.managetokens.*
import com.tangem.domain.managetokens.repository.CustomTokensRepository
import com.tangem.domain.managetokens.repository.ManageTokensRepository
@ -10,11 +9,14 @@ import com.tangem.domain.staking.StakingIdFactory
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.derivations.DerivationsRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import javax.inject.Singleton
@Module
@ -74,6 +76,7 @@ internal object ManageTokensDomainModule {
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
stakingIdFactory: StakingIdFactory,
dispatchers: CoroutineDispatcherProvider,
): SaveManagedTokensUseCase {
return SaveManagedTokensUseCase(
customTokensRepository = customTokensRepository,
@ -84,6 +87,7 @@ internal object ManageTokensDomainModule {
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
stakingIdFactory = stakingIdFactory,
parallelUpdatingScope = CoroutineScope(SupervisorJob() + dispatchers.default),
)
}

View file

@ -15,10 +15,13 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.wallets.derivations.DerivationsRepository
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.features.hotwallet.HotWalletFeatureToggles
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import javax.inject.Singleton
@Module
@ -67,6 +70,7 @@ object MarketsDomainModule {
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
stakingIdFactory: StakingIdFactory,
dispatchers: CoroutineDispatcherProvider,
): SaveMarketTokensUseCase {
return SaveMarketTokensUseCase(
derivationsRepository = derivationsRepository,
@ -76,6 +80,7 @@ object MarketsDomainModule {
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
stakingIdFactory = stakingIdFactory,
parallelUpdatingScope = CoroutineScope(SupervisorJob() + dispatchers.default),
)
}

View file

@ -294,14 +294,6 @@ internal object TokensDomainModule {
return IsAmountSubtractAvailableUseCase(currenciesRepository, dispatchers)
}
@Provides
@Singleton
fun provideRunPolkadotAccountHealthCheckUseCase(
repository: PolkadotAccountHealthCheckRepository,
): RunPolkadotAccountHealthCheckUseCase {
return RunPolkadotAccountHealthCheckUseCase(repository)
}
@Provides
@Singleton
fun provideGetNetworkStatusesUseCase(networksRepository: NetworksRepository): GetNetworkAddressesUseCase {

View file

@ -19,7 +19,7 @@ import com.tangem.domain.card.common.TapWorkarounds.isNotSupportedInThatRelease
import com.tangem.domain.card.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.card.common.TapWorkarounds.isTangemTwins
import com.tangem.domain.card.common.TapWorkarounds.isVisa
import com.tangem.domain.common.TwinsHelper
import com.tangem.domain.card.common.TwinsHelper
import com.tangem.domain.wallets.derivations.derivationStyleProvider
import com.tangem.domain.card.common.visa.VisaUtilities
import com.tangem.domain.card.configs.CardConfig

View file

@ -5,7 +5,7 @@ import com.tangem.common.card.EllipticCurve
import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.CompletionCallback
import com.tangem.domain.common.TwinsHelper
import com.tangem.domain.card.common.TwinsHelper
import com.tangem.operations.attestation.AttestationTask
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.operations.wallet.CreateWalletTask

View file

@ -8,7 +8,7 @@ import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.CompletionCallback
import com.tangem.common.extensions.hexToBytes
import com.tangem.domain.common.TwinsHelper
import com.tangem.domain.card.common.TwinsHelper
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.operations.wallet.CreateWalletTask
import com.tangem.operations.wallet.PurgeWalletCommand

View file

@ -1,78 +0,0 @@
package com.tangem.tap.domain.twins
import com.tangem.Message
import com.tangem.common.CompletionResult
import com.tangem.common.KeyPair
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toHexString
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.tap.common.extensions.inject
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
class TwinCardsManager(card: CardDTO) {
private val issuersConfigStorage by lazy(mode = LazyThreadSafetyMode.NONE) {
store.inject(DaggerGraphState::issuersConfigStorage)
}
private val firstCardId: String = card.cardId
private val publicKey: String = card.issuer.publicKey.toHexString()
private var currentCardPublicKey: String? = null
private var secondCardPublicKey: String? = null
suspend fun createFirstWallet(message: Message): CompletionResult<CreateWalletResponse> {
val response = tangemSdkManager.createFirstTwinWallet(cardId = firstCardId, initialMessage = message)
if (response is CompletionResult.Success) {
currentCardPublicKey = response.data.wallet.publicKey.toHexString()
}
return response
}
suspend fun createSecondWallet(
initialMessage: Message,
preparingMessage: Message,
creatingWalletMessage: Message,
): CompletionResult<CreateWalletResponse> {
val response = tangemSdkManager.createSecondTwinWallet(
firstPublicKey = requireNotNull(currentCardPublicKey),
firstCardId = firstCardId,
issuerKeys = getIssuerKeys(),
preparingMessage = preparingMessage,
creatingWalletMessage = creatingWalletMessage,
initialMessage = initialMessage,
)
if (response is CompletionResult.Success) {
secondCardPublicKey = response.data.wallet.publicKey.toHexString()
}
return response
}
suspend fun complete(message: Message): CompletionResult<ScanResponse> {
val response = tangemSdkManager.finalizeTwin(
secondCardPublicKey = requireNotNull(secondCardPublicKey).hexToBytes(),
issuerKeyPair = getIssuerKeys(),
cardId = firstCardId,
initialMessage = message,
)
return response
}
private suspend fun getIssuerKeys(): KeyPair {
val issuer = issuersConfigStorage.getConfig().first { it.publicKey == publicKey }
return KeyPair(
publicKey = issuer.publicKey.hexToBytes(),
privateKey = issuer.privateKey.hexToBytes(),
)
}
}

View file

@ -1,174 +0,0 @@
package com.tangem.tap.domain.twins
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.animation.PropertyValuesHolder
import android.view.View
import androidx.core.animation.doOnEnd
import com.tangem.common.extensions.VoidCallback
import com.tangem.domain.common.TwinCardNumber
import com.tangem.sdk.ui.widget.leapfrogWidget.LeapView
import com.tangem.sdk.ui.widget.leapfrogWidget.LeapViewState
import com.tangem.sdk.ui.widget.leapfrogWidget.LeapfrogWidget
/**
[REDACTED_AUTHOR]
*/
class TwinsCardWidget(
val leapfrogWidget: LeapfrogWidget,
private val deviceScaleFactor: Float = 1f,
val getTopOfAnchorViewForActivateState: () -> Float,
) {
var state: TwinCardsWidgetState? = null
private set
private val animationDuration = 300L
init {
if (leapfrogWidget.getViewsCount() != 2) throw UnsupportedOperationException()
}
fun toWelcome(animate: Boolean = true, onEnd: VoidCallback = {}) {
if (state == TwinCardsWidgetState.Welcome) return
state = TwinCardsWidgetState.Welcome
val animator = createAnimator(animate)
animator.playTogether(
createAnimator(TwinCardNumber.First, createWelcomeProperties(TwinCardNumber.First)),
createAnimator(TwinCardNumber.Second, createWelcomeProperties(TwinCardNumber.Second)),
)
animator.doOnEnd { onEnd() }
leapfrogWidget.fold(animate) { animator.start() }
}
fun toLeapfrog(animate: Boolean = true, onEnd: VoidCallback = {}) {
if (state == TwinCardsWidgetState.Leapfrog) return
state = TwinCardsWidgetState.Leapfrog
val animator = createAnimator(animate)
animator.playTogether(
createAnimator(TwinCardNumber.First, createLeapfrogProperties(TwinCardNumber.First)),
createAnimator(TwinCardNumber.Second, createLeapfrogProperties(TwinCardNumber.Second)),
)
animator.doOnEnd {
leapfrogWidget.initViews()
leapfrogWidget.unfold(animate, onEnd)
}
animator.start()
}
fun toActivate(animate: Boolean = true, onEnd: VoidCallback = {}) {
if (state == TwinCardsWidgetState.Activate) return
state = TwinCardsWidgetState.Activate
val animator = createAnimator(animate)
animator.playTogether(
createAnimator(TwinCardNumber.First, createActivateProperties(TwinCardNumber.First)),
createAnimator(TwinCardNumber.Second, createActivateProperties(TwinCardNumber.Second)),
)
animator.doOnEnd { onEnd() }
animator.start()
}
private fun createAnimator(animate: Boolean): AnimatorSet {
return AnimatorSet().apply {
duration = if (animate) animationDuration else 0
}
}
private fun createAnimator(cardNumber: TwinCardNumber, properties: TwinsCardProperties): ObjectAnimator {
val view = getLeapViewByCardNumber(cardNumber).view
val animator = ObjectAnimator.ofPropertyValuesHolder(view, *properties.createValuesHolders().toTypedArray())
view.elevation = properties.elevation
return animator
}
@Suppress("MagicNumber")
private fun createWelcomeProperties(cardNumber: TwinCardNumber): TwinsCardProperties {
return when (cardNumber) {
TwinCardNumber.First -> {
TwinsCardProperties(
xTranslation = -120f * deviceScaleFactor,
yTranslation = -220f * deviceScaleFactor,
rotation = -3f,
elevation = 1f,
scale = deviceScaleFactor,
)
}
TwinCardNumber.Second -> {
TwinsCardProperties(
xTranslation = 170f * deviceScaleFactor,
yTranslation = 170f * deviceScaleFactor,
rotation = -3f,
elevation = 0f,
scale = deviceScaleFactor,
)
}
}
}
private fun createLeapfrogProperties(cardNumber: TwinCardNumber): TwinsCardProperties {
val twinProperties = TwinsCardProperties.from(getLeapViewByCardNumber(cardNumber).state)
return twinProperties.copy(
xTranslation = 0f,
yTranslation = 0f,
rotation = 0f,
scale = 1f,
)
}
@Suppress("MagicNumber")
private fun createActivateProperties(cardNumber: TwinCardNumber): TwinsCardProperties {
val topOfAnchorView = getTopOfAnchorViewForActivateState()
val twinProperties = TwinsCardProperties.from(getLeapViewByCardNumber(cardNumber).state)
return twinProperties.copy(
xTranslation = twinProperties.xTranslation,
yTranslation = twinProperties.yTranslation - topOfAnchorView,
rotation = 0f,
scale = (twinProperties.scale - 0.5f) * deviceScaleFactor,
)
}
private fun getLeapViewByCardNumber(cardNumber: TwinCardNumber): LeapView {
return when (cardNumber) {
TwinCardNumber.First -> leapfrogWidget.getViewByPosition(0)
TwinCardNumber.Second -> leapfrogWidget.getViewByPosition(1)
}
}
}
enum class TwinCardsWidgetState {
Welcome, Leapfrog, Activate
}
private data class TwinsCardProperties(
val xTranslation: Float = 0f,
val yTranslation: Float = 0f,
val rotation: Float = 0f,
val elevation: Float = 0f,
val scale: Float = 1.1f,
) {
fun createValuesHolders(): List<PropertyValuesHolder> {
return listOf(
PropertyValuesHolder.ofFloat(View.TRANSLATION_X, xTranslation),
PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, yTranslation),
PropertyValuesHolder.ofFloat(View.ROTATION, rotation),
PropertyValuesHolder.ofFloat(View.SCALE_X, scale),
PropertyValuesHolder.ofFloat(View.SCALE_Y, scale),
)
}
companion object {
fun from(leapViewState: LeapViewState): TwinsCardProperties {
val leapViewProperties = leapViewState.properties
return TwinsCardProperties(
yTranslation = leapViewProperties.yTranslation,
elevation = leapViewProperties.elevationEnd,
scale = leapViewProperties.scale,
)
}
}
}

View file

@ -1,7 +1,7 @@
package com.tangem.tap.domain.twins
import com.tangem.common.core.TangemError
import com.tangem.domain.common.TwinCardNumber
import com.tangem.domain.card.common.TwinCardNumber
import com.tangem.tap.tangemSdkManager
import com.tangem.wallet.R

View file

@ -2,14 +2,19 @@ package com.tangem.tap.network.auth
import com.tangem.common.extensions.toHexString
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.api.common.config.ApiEnvironment
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.utils.Provider
import com.tangem.utils.ProviderSuspend
internal class DefaultAuthProvider(
private val userWalletsListManager: UserWalletsListManager,
private val userWalletsListRepository: UserWalletsListRepository,
private val shouldUseNewListRepository: Boolean = false,
private val environmentConfigStorage: EnvironmentConfigStorage,
) : AuthProvider {
override suspend fun getCardPublicKey(): String {
@ -38,6 +43,20 @@ internal class DefaultAuthProvider(
}
}
override fun getApiKey(apiEnvironment: Provider<ApiEnvironment>): ProviderSuspend<String> {
return ProviderSuspend {
when (apiEnvironment.invoke()) {
ApiEnvironment.MOCK,
ApiEnvironment.DEV,
ApiEnvironment.DEV_2,
ApiEnvironment.DEV_3,
-> environmentConfigStorage.getConfigSync().tangemApiKeyDev
ApiEnvironment.STAGE -> environmentConfigStorage.getConfigSync().tangemApiKeyStage
ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().tangemApiKey
} ?: error("No tangem tech api config provided")
}
}
private suspend fun getWallets(): List<UserWallet> {
return if (shouldUseNewListRepository) {
userWalletsListRepository.userWalletsSync()

View file

@ -28,11 +28,13 @@ internal class AuthModule {
userWalletsListManager: UserWalletsListManager,
userWalletsListRepository: UserWalletsListRepository,
hotWalletFeatureToggles: HotWalletFeatureToggles,
environmentConfigStorage: EnvironmentConfigStorage,
): AuthProvider {
return DefaultAuthProvider(
userWalletsListManager = userWalletsListManager,
userWalletsListRepository = userWalletsListRepository,
shouldUseNewListRepository = hotWalletFeatureToggles.isHotWalletEnabled,
environmentConfigStorage = environmentConfigStorage,
)
}

View file

@ -1,5 +1,6 @@
package com.tangem.common.ui.tokens
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.ui.R
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
@ -21,6 +22,7 @@ import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.currency.yieldSupplyKey
import com.tangem.domain.models.staking.YieldBalance
import com.tangem.domain.staking.model.isStakingSupported
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.staking.utils.getTotalWithRewardsStakingBalance
import com.tangem.lib.crypto.BlockchainUtils
@ -211,15 +213,22 @@ class TokenItemStateConverter(
}
if (stakingApyMap.isNotEmpty()) {
val (stakingRate, hasStaked) = findStakingRate(
val stakingInfo = findStakingRate(
currencyStatus = cryptoCurrencyStatus,
stakingApyMap = stakingApyMap,
)
if (stakingRate != null) {
val rewardTypeRes = when (stakingInfo.rewardType) {
Yield.RewardType.APR -> R.string.staking_apr_earn_badge
Yield.RewardType.UNKNOWN,
Yield.RewardType.APY,
null,
-> R.string.yield_module_earn_badge
}
if (stakingInfo.rate != null) {
return resourceReference(
R.string.yield_module_earn_badge,
wrappedList(stakingRate.format { percent(withPercentSign = false) }),
) to hasStaked
rewardTypeRes,
wrappedList(stakingInfo.rate.format { percent(withPercentSign = false) }),
) to stakingInfo.isActive
}
}
@ -229,21 +238,46 @@ class TokenItemStateConverter(
private fun findStakingRate(
currencyStatus: CryptoCurrencyStatus,
stakingApyMap: Map<String, List<Yield.Validator>>,
): Pair<BigDecimal?, Boolean> {
): StakingLocalInfo {
val stakingKey = currencyStatus.currency.stakingKey()
val validators = stakingApyMap[stakingKey] ?: return null to false
val validators = stakingApyMap[stakingKey]
?: return StakingLocalInfo(rate = null, isActive = false, rewardType = null)
val yieldBalance = currencyStatus.value.yieldBalance
val hasStakedBalance = yieldBalance is YieldBalance.Data
val rate = if (hasStakedBalance) {
val rateInfo: Pair<BigDecimal, Yield.RewardType?>? = if (hasStakedBalance) {
val validatorsByAddress = validators.associateBy { it.address }
yieldBalance.balance.items
.mapNotNull { it.validatorAddress }
.firstNotNullOfOrNull { address -> validatorsByAddress[address]?.rewardInfo?.rate }
?: validators.mapNotNull { it.rewardInfo?.rate }.maxOrNull()
.firstNotNullOfOrNull { address ->
val validator = validatorsByAddress[address]
validator?.rewardInfo?.rate?.let { rate ->
rate to validator.rewardInfo?.type
}
}
?: validators
.filter { it.preferred }
.mapNotNull { validator ->
validator.rewardInfo?.rate?.let { rate -> rate to validator.rewardInfo?.type }
}
.maxByOrNull { it.first }
} else {
validators.mapNotNull { it.rewardInfo?.rate }.maxOrNull()
validators
.filter { it.preferred }
.mapNotNull { validator ->
validator.rewardInfo?.rate?.let { rate ->
rate to validator.rewardInfo?.type
}
}
.maxByOrNull { it.first }
}
return rate to hasStakedBalance
return StakingLocalInfo(
rate = rateInfo?.first,
isActive = hasStakedBalance,
rewardType = rateInfo?.second,
)
}
private fun createSubtitleState(
@ -353,7 +387,21 @@ class TokenItemStateConverter(
fun CryptoCurrencyStatus.Value.isFlickering(): Boolean = sources.total == StatusSource.CACHE
private fun CryptoCurrency.stakingKey(): String {
return "${network.backendId}_$symbol"
if (this is CryptoCurrency.Coin && !network.isStakingSupported) return ""
if (network.isStakingSupported && this !is CryptoCurrency.Coin) {
val isPolygonTokenOnEthereum = this is CryptoCurrency.Token &&
this.network.id.rawId.value == Blockchain.Ethereum.id &&
this.symbol == Blockchain.Polygon.currency
if (!isPolygonTokenOnEthereum) return ""
}
return "${id.rawCurrencyId}_$symbol"
}
}
private data class StakingLocalInfo(
val rate: BigDecimal?,
val isActive: Boolean,
val rewardType: Yield.RewardType?,
)
}

View file

@ -132,6 +132,12 @@ sealed class AnalyticsParam {
override val token: String,
override val feeType: FeeType,
) : TxSentFrom("Send&Swap"), TxData
data class Earning(
override val blockchain: String,
override val token: String,
override val feeType: FeeType,
) : TxSentFrom("Earning"), TxData
}
sealed interface TxData {

View file

@ -1,5 +1,9 @@
package com.tangem.datasource.api.common
import com.tangem.datasource.api.common.config.ApiEnvironment
import com.tangem.utils.Provider
import com.tangem.utils.ProviderSuspend
/**
* Provides auth for tangemTech API
*/
@ -12,6 +16,8 @@ interface AuthProvider {
suspend fun getCardId(): String
fun getApiKey(apiEnvironment: Provider<ApiEnvironment>): ProviderSuspend<String>
/**
* Returns map where keys(cardId) associated with cardPublicKey
*/

View file

@ -2,15 +2,13 @@ package com.tangem.datasource.api.common.config
import com.tangem.datasource.BuildConfig
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.utils.RequestHeader
import com.tangem.utils.ProviderSuspend
import com.tangem.utils.Provider
import com.tangem.utils.info.AppInfoProvider
import com.tangem.utils.version.AppVersionProvider
/** TangemTech [ApiConfig] */
internal class TangemTech(
private val environmentConfigStorage: EnvironmentConfigStorage,
private val appVersionProvider: AppVersionProvider,
private val authProvider: AuthProvider,
private val appInfoProvider: AppInfoProvider,
@ -63,20 +61,8 @@ internal class TangemTech(
)
private fun createHeaders(apiEnvironment: ApiEnvironment) = buildMap {
put(key = "api-key", value = ProviderSuspend { getApiKey(apiEnvironment) })
putAll(from = RequestHeader.TangemApiKeyHeader(authProvider, Provider { apiEnvironment }).values)
putAll(from = RequestHeader.AppVersionPlatformHeaders(appVersionProvider, appInfoProvider).values)
putAll(from = RequestHeader.AuthenticationHeader(authProvider).values)
}
private fun getApiKey(apiEnvironment: ApiEnvironment): String {
return when (apiEnvironment) {
ApiEnvironment.MOCK,
ApiEnvironment.DEV,
ApiEnvironment.DEV_2,
ApiEnvironment.DEV_3,
-> environmentConfigStorage.getConfigSync().tangemApiKeyDev
ApiEnvironment.STAGE -> environmentConfigStorage.getConfigSync().tangemApiKeyStage
ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().tangemApiKey
} ?: error("No tangem tech api config provided")
}
}

View file

@ -10,8 +10,9 @@ data class YieldSupplyMarketTokenDto(
@Json(name = "tokenSymbol") val tokenSymbol: String? = null,
@Json(name = "tokenName") val tokenName: String? = null,
@Json(name = "apy") val apy: BigDecimal? = null,
@Json(name = "decimals") val decimals: Int? = null,
@Json(name = "isActive") val isActive: Boolean? = null,
@Json(name = "chainId") val chainId: Int? = null,
@Json(name = "maxFeeNative") val maxFeeNative: String? = null,
@Json(name = "maxFeeUSD") val maxFeeUSD: String? = null,
@Json(name = "maxFeeNative") val maxFeeNative: BigDecimal? = null,
@Json(name = "maxFeeUSD") val maxFeeUSD: BigDecimal? = null,
)

View file

@ -42,12 +42,10 @@ internal object ApiConfigsModule {
@Provides
@IntoSet
fun provideTangemTechConfig(
environmentConfigStorage: EnvironmentConfigStorage,
appVersionProvider: AppVersionProvider,
authProvider: AuthProvider,
appInfoProvider: AppInfoProvider,
): ApiConfig = TangemTech(
environmentConfigStorage = environmentConfigStorage,
appVersionProvider = appVersionProvider,
authProvider = authProvider,
appInfoProvider = appInfoProvider,

View file

@ -62,16 +62,6 @@ object PreferencesKeys {
val APP_LOGS_KEY by lazy { stringPreferencesKey(name = "app_logs") }
val POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX_KEY by lazy {
stringPreferencesKey(name = "POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX")
}
val POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS_KEY by lazy {
stringPreferencesKey(name = "POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS")
}
val POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS_KEY by lazy {
stringPreferencesKey(name = "POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS")
}
val SEND_TAP_HELP_PREVIEW_KEY by lazy { booleanPreferencesKey(name = "sendTapHelpPreview") }
val WAS_APPLICATION_STOPPED_KEY by lazy { booleanPreferencesKey(name = "applicationStopped") }

View file

@ -1,5 +1,6 @@
package com.tangem.datasource.utils
import com.tangem.utils.ProviderSuspend
import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
import okhttp3.Response
@ -12,21 +13,17 @@ import okhttp3.Response
[REDACTED_AUTHOR]
*/
class AddHeadersInterceptor(
private val requestHeaders: Set<RequestHeader>,
private val requestHeaders: Map<String, ProviderSuspend<String>>,
) : Interceptor {
constructor(requestHeader: RequestHeader) : this(requestHeaders = setOf(requestHeader))
override fun intercept(chain: Interceptor.Chain): Response {
val requestBuilder = chain.request().newBuilder()
requestHeaders
.flatMap { it.values.toList() }
.forEach { (name, valueProvider) ->
val value = runBlocking { valueProvider() }
requestHeaders.forEach { (name, valueProvider) ->
val value = runBlocking { valueProvider() }
requestBuilder.addHeader(name = name, value = value)
}
requestBuilder.addHeader(name = name, value = value)
}
val request = requestBuilder.build()

View file

@ -5,13 +5,6 @@ import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
import okhttp3.OkHttpClient
/** Extension for adding headers [requestHeaders] to every [OkHttpClient] request */
internal fun OkHttpClient.Builder.addHeaders(vararg requestHeaders: RequestHeader): OkHttpClient.Builder {
return addInterceptor(
interceptor = AddHeadersInterceptor(requestHeaders = requestHeaders.toSet()),
)
}
/** Extension for adding headers [requestHeaders] to every [OkHttpClient] request */
internal fun OkHttpClient.Builder.addHeaders(
requestHeaders: Map<String, ProviderSuspend<String>>,

View file

@ -2,7 +2,9 @@ package com.tangem.datasource.utils
import android.os.Build
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.api.common.config.ApiEnvironment
import com.tangem.datasource.utils.RequestHeader.CacheControlHeader.checkHeaderValueOrEmpty
import com.tangem.utils.Provider
import com.tangem.utils.ProviderSuspend
import com.tangem.utils.info.AppInfoProvider
import com.tangem.utils.version.AppVersionProvider
@ -40,6 +42,13 @@ sealed class RequestHeader(vararg pairs: Pair<String, ProviderSuspend<String>>)
"device" to ProviderSuspend { "${Build.MANUFACTURER} ${Build.MODEL}".checkHeaderValueOrEmpty() },
)
/**
* Use ONLY for tangemApi (not express or yields)
*/
class TangemApiKeyHeader(authProvider: AuthProvider, apiEnvironment: Provider<ApiEnvironment>) : RequestHeader(
"api-key" to authProvider.getApiKey(apiEnvironment),
)
/**
* Use it to avoid crash in okhttp headers
*/

View file

@ -1,7 +1,12 @@
package com.tangem.datasource.api.common.config
import com.google.common.truth.Truth
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.utils.ProviderSuspend
import io.mockk.clearMocks
import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import timber.log.Timber
@ -12,6 +17,17 @@ import timber.log.Timber
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ApiConfigTest {
private val appAuthProvider = mockk<AuthProvider>()
private val apiKeyProvider = mockk<ProviderSuspend<String>>()
@BeforeEach
fun setup() {
clearMocks(
appAuthProvider,
)
every { appAuthProvider.getApiKey(any()) } returns apiKeyProvider
}
@Test
fun `all baseUrls ends with slash`() {
// Arrange
@ -41,15 +57,14 @@ class ApiConfigTest {
YieldSupply(
environmentConfigStorage = mockk(),
appVersionProvider = mockk(),
authProvider = mockk(),
authProvider = appAuthProvider,
appInfoProvider = mockk(),
)
}
ApiConfig.ID.TangemTech -> {
TangemTech(
environmentConfigStorage = mockk(),
appVersionProvider = mockk(),
authProvider = mockk(),
authProvider = appAuthProvider,
appInfoProvider = mockk(),
)
}

View file

@ -12,6 +12,7 @@ import com.tangem.datasource.api.common.config.ApiConfig.Companion.INTERNAL_BUIL
import com.tangem.datasource.api.common.config.ApiConfig.Companion.MOCKED_BUILD_TYPE
import com.tangem.datasource.api.common.config.ApiConfig.Companion.RELEASE_BUILD_TYPE
import com.tangem.datasource.api.common.config.managers.MockEnvironmentConfigStorage.Companion.BLOCK_AID_API_KEY
import com.tangem.datasource.api.common.config.managers.MockEnvironmentConfigStorage.Companion.TANGEM_API_KEY
import com.tangem.lib.auth.ExpressAuthProvider
import com.tangem.lib.auth.StakeKitAuthProvider
import com.tangem.utils.ProviderSuspend
@ -40,8 +41,9 @@ internal class ProdApiConfigsManagerTest {
private val stakeKitAuthProvider = mockk<StakeKitAuthProvider>()
private val appAuthProvider = mockk<AuthProvider>()
private val appInfoProvider = mockk<AppInfoProvider>()
private val tangemApiKeyProvider = mockk<ProviderSuspend<String>>()
private val manager = ProdApiConfigsManager(apiConfigs = createApiConfigs())
private lateinit var manager: ProdApiConfigsManager
@BeforeEach
fun setup() {
@ -56,9 +58,14 @@ internal class ProdApiConfigsManagerTest {
every { appVersionProvider.versionName } returns VERSION_NAME
every { expressAuthProvider.getSessionId() } returns EXPRESS_SESSION_ID
every { stakeKitAuthProvider.getApiKey() } returns STAKE_KIT_API_KEY
every { appAuthProvider.getApiKey(any()) } returns tangemApiKeyProvider
coEvery { tangemApiKeyProvider.invoke() } returns TANGEM_API_KEY
coEvery { appAuthProvider.getCardId() } returns APP_CARD_ID
coEvery { appAuthProvider.getCardPublicKey() } returns APP_CARD_PUBLIC_KEY
every { appInfoProvider.osVersion } returns "Android 16"
manager = ProdApiConfigsManager(apiConfigs = createApiConfigs())
}
@ParameterizedTest
@ -94,7 +101,6 @@ internal class ProdApiConfigsManagerTest {
}
ApiConfig.ID.TangemTech -> {
TangemTech(
environmentConfigStorage = environmentConfigStorage,
appVersionProvider = appVersionProvider,
authProvider = appAuthProvider,
appInfoProvider = appInfoProvider,
@ -177,7 +183,7 @@ internal class ProdApiConfigsManagerTest {
environment = ApiEnvironment.PROD,
baseUrl = "https://api.tangem.org/",
headers = mapOf(
"api-key" to ProviderSuspend { MockEnvironmentConfigStorage.TANGEM_API_KEY },
"api-key" to ProviderSuspend { TANGEM_API_KEY },
"card_id" to ProviderSuspend { APP_CARD_ID },
"card_public_key" to ProviderSuspend { APP_CARD_PUBLIC_KEY },
"version" to ProviderSuspend { VERSION_NAME },

View file

@ -7,9 +7,9 @@
<string name="access_code_check_warining_delete">Falscher Zugangscode. Deine mobile Wallet wird nach %s weiteren Fehlversuchen gelöscht.</string>
<string name="access_code_check_warining_lock">Falscher Zugangscode. Die App wird nach %s weiteren Fehlversuchen gesperrt.</string>
<string name="access_code_check_warining_wait">Falscher Zugangscode.\nBitte warte %s Sekunden und versuche es erneut.</string>
<string name="access_code_confirm_description">Bestätige Deinen zuvor eingegebenen Code, um fortzufahren</string>
<string name="access_code_confirm_description">Bestätige Deinen Zugangscode, um fortzufahren.</string>
<string name="access_code_confirm_title">Zugangscode erneut eingeben</string>
<string name="access_code_create_description">Lege einen %s -stelligen Zugangscode fest, um Deine Wallet zu entsperren.</string>
<string name="access_code_create_description">Erstelle einen %s-stelliger Zugangscode, um Deine Wallet zu entsperren.</string>
<string name="access_code_create_title">Zugangscode erstellen</string>
<string name="access_code_navtitle">Zugangscode</string>
<string name="account_add_limit_dialog_description">Du kannst nicht mehr erstellen als %1$s Konto/Konten. Archiviere eines, um es neu hinzuzufügen.</string>
@ -20,13 +20,20 @@
<string name="account_archived_recover_dialog_description">Du bist dabei, dich zu erholen \"%1$s”.</string>
<string name="account_archived_recover_dialog_title">Konto wiederherstellen</string>
<string name="account_archived_recover_error_message">Du hast das Limit von 20 aktiven Konten bereits überschritten. Archiviere eines, um es wiederherzustellen.</string>
<string name="account_archived_recover_error_title">Konto kann nicht wiederhergestellt werden</string>
<string name="account_archived_title">Archiviert</string>
<string name="account_could_not_archive">Das Konto konnte nicht archiviert werden. Bitte versuche es später erneut.</string>
<string name="account_could_not_archive_referral_program_message">Dieses Konto nimmt am Empfehlungsprogramm teil.</string>
<string name="account_could_not_archive_referral_program_title">Dieses Konto kann nicht archiviert werden.</string>
<string name="account_could_not_create">Wir konnten kein Konto erstellen. Bitte versuche es später erneut.</string>
<string name="account_create_success_message">Konto erstellt</string>
<string name="account_details_archive">Archivkonto</string>
<string name="account_details_archive_action">Archiv</string>
<string name="account_details_archive_description">Du archivierst dieses Konto, kannst es aber jederzeit entarchivieren.</string>
<string name="account_details_archiving">Archivierung...</string>
<string name="account_details_title">Konto</string>
<string name="account_edit_success_message">Konto gespeichert</string>
<string name="account_for_rewards">Prämien berücksichtigen</string>
<string name="account_form_account_index">Kontonummer %s wird zur Adressableitung verwendet.</string>
<string name="account_form_create_button">Konto hinzufügen</string>
<string name="account_form_edit_button">Speichern</string>
@ -37,6 +44,9 @@
<string name="account_form_title_create">Konto hinzufügen</string>
<string name="account_form_title_edit">Konto bearbeiten</string>
<string name="account_label_tokens_info">%1$s in %2$s</string>
<string name="account_main_account_title">Hauptkonto</string>
<string name="account_recover_limit_dialog_description">Du hast das Limit von %1$s aktiven Konten bereits überschritten. Archiviere eines zur Wiederherstellung</string>
<string name="account_recover_limit_dialog_title">Konto kann nicht wiederhergestellt werden</string>
<string name="account_recover_success_message">Konto wiederhergestellt</string>
<string name="account_reorder_description">Tippe lange auf ein Konto, um die Konten neu anzuordnen</string>
<string name="account_unsaved_dialog_action_first">Weiter bearbeiten</string>
@ -78,7 +88,7 @@
<string name="alert_manage_tokens_unsupported_message">Tokens im %1$s -Netzwerk werden von dieser Karte oder Ring aufgrund einer Firmware-Einschränkung nicht unterstützt.</string>
<string name="alert_troubleshooting_scan_card_title">Hast du Probleme beim Scannen deiner Karte oder Ring?</string>
<string name="alert_unsupported_card">Diese Karte oder Ring ist für die Zusammenarbeit mit Tangem nicht geeignet</string>
<string name="app_settings_biometrics_footer">Verwenden %1$s, um Deine Wallet schnell und sicher zu entsperren und alle sensiblen Aktionen zu autorisieren, wie z. B. das Unterschreiben von Transaktionen. Für Hardware-Wallets benötigst Du weiterhin eine Karte zum signieren.</string>
<string name="app_settings_biometrics_footer">Verwende die %1$s um Deine Wallet zu entsperren und sensible Aktionen wie das Signieren von Transaktionen zu bestätigen. Bei Hardware-Wallets ist zum Signieren weiterhin eine Karte oder ein Ring erforderlich.</string>
<string name="app_settings_default_fee">Standardgebühr</string>
<string name="app_settings_default_fee_footer">Aktiviere die Option Standardgebühr, um die Transaktionsgebühren automatisch festzulegen und die Gebührenseite beim Senden von Geldern zu überspringen. Du kannst bei Bedarf jederzeit zu dieser Seite zurückkehren.</string>
<string name="app_settings_enable_biometrics_description">Gehe zu den Einstellungen, um die biometrische Authentifizierung in der Tangem-App zu aktivieren</string>
@ -89,7 +99,7 @@
<string name="app_settings_off_saved_wallet_alert_message">Durch das Entfernen der gespeicherten Geräte werden alle gespeicherten Wallets und deren Zugangscodes aus der App gelöscht.</string>
<string name="app_settings_on_require_access_code_alert_message">Dadurch werden alle gespeicherten Wallet-Zugangscodes gelöscht. Für jede weitere Interaktion mit dem Wallet ist die Eingabe des Zugangscodes erforderlich.</string>
<string name="app_settings_require_access_code">Zugangscode erforderlich</string>
<string name="app_settings_require_access_code_footer">Mit dieser Option wird die biometrische Authentifizierung für vertrauliche Aktionen deaktiviert. Du musst Deinen Zugangscode jedes Mal eingeben, z. B. wenn Du eine Transaktion unterzeichnest.</string>
<string name="app_settings_require_access_code_footer">Diese Option deaktiviert die biometrische Authentifizierung für sensible Vorgänge. Du musst Deinen Zugangscode jedes Mal eingeben, wenn Du eine Transaktion signierst.</string>
<string name="app_settings_saved_access_codes">Zugangscode speichern</string>
<string name="app_settings_saved_access_codes_footer">Bei Interaktionen mit deiner Karte oder Ring wird anstelle des Zugangscodes eine biometrische Authentifizierung abgefragt.</string>
<string name="app_settings_saved_wallet">Behalte die Wallet in der App</string>
@ -110,15 +120,15 @@
<string name="backup_complete_description">Du hast Deine Wallet erfolgreich gesichert.</string>
<string name="backup_complete_seed_description">Diese Wörter können bei Verlust nicht wiederhergestellt werden. Bewahre diese an einem sicheren Ort auf.</string>
<string name="backup_complete_title">Sicherung abgeschlossen</string>
<string name="backup_info_description">Deine geheime Wiederherstellungsphrase ist ein fester Satz von %s Zufällige Wörter, die für den Zugriff auf und die Wiederherstellung Deiner Wallet verwendet werden.</string>
<string name="backup_info_keep_description">Diese Wörter können bei Verlust nicht wiederhergestellt werden. Bewahre diese an einem sicheren Ort auf.</string>
<string name="backup_info_description">Deine geheime Wiederherstellungsphrase ist eine feste Folge von %s zufälligen Wörtern, mit denen Du auf Deiner Wallet zugreifefst und sie wiederherstellen kannst.</string>
<string name="backup_info_keep_description">Diese Worte sind unwiederbringlich verloren. Bewahre diese gut auf.</string>
<string name="backup_info_keep_title">Sicher aufbewahren</string>
<string name="backup_info_save_description">Bewahre diese %s Wörter an einem sicheren Ort auf , z. B. in einem Passwort-Manager, und teile diese niemals mit Dritten.</string>
<string name="backup_info_save_description">Speicher diese %s Wörter an einem sicheren Ort und gebe diese niemals an andere weiter.</string>
<string name="backup_info_save_title">Keine Wiederherstellung möglich</string>
<string name="backup_info_title">Wiederherstellungsphrase</string>
<string name="backup_seed_caution">Gebe diese Wörter niemals weiter. Jeder, der sie erfährt, kann Deine gesamten Kryptowährungen stehlen. Tangem wird Dich niemals danach fragen. Die folgenden %s Wörter sind die Wiederherstellungsphrase Deiner Wallets. Mit dieser Phrase kannst Du Deine Wallet wiederherstellen, falls Du Dein Gerät verlierst.</string>
<string name="backup_seed_description">Schreibe diese %s Wörter der Reihe nach auf und bewahre sie sicher und vertraulich auf</string>
<string name="backup_seed_responsibility">Die volle Verantwortung für die Sicherheit und Sicherung der Wallet und der Wiederherstellungsphrase liegt beim Benutzer, nicht bei Tangem.</string>
<string name="backup_seed_description">Schreibe diese Wörter %s in numerischer Reihenfolge auf und bewahren diese sicher und vertraulich auf.</string>
<string name="backup_seed_responsibility">Du bist vollumfänglich für die Sicherung und Datensicherung Deiner Wallet und Deine Wiederherstellungsphrase verantwortlich.</string>
<string name="backup_seed_title">Wiederherstellungsphrase</string>
<string name="balance_hidden_description">Um deine Kontostände ein- oder auszublenden, flippe einfach das Display deines Geräts nach unten, oder schalte es in den Einstellungen aus.</string>
<string name="balance_hidden_do_not_show_button">Nicht mehr anzeigen</string>
@ -132,7 +142,7 @@
<string name="biometric_unavailable_warning">Du hast die biometrische Authentifizierung auf deinem Telefon deaktiviert und kannst keine Wallets in der App speichern. Um Wallets zu speichern, aktiviere bitte die biometrische Authentifizierung in deinen Telefoneinstellungen.</string>
<string name="bitcoin_promo_activation_error">Bei der Bearbeitung Deines Aktionscodes ist ein Fehler aufgetreten. Bitte versuche es später noch einmal.</string>
<string name="bitcoin_promo_activation_error_title">Fehler bei der Aktivierung</string>
<string name="bitcoin_promo_activation_success">Ihr Aktionscode wurde erfolgreich aktiviert. Eine Belohnung wird innerhalb von 14 Tagen auf Ihr Konto gutgeschrieben.</string>
<string name="bitcoin_promo_activation_success">Dein Gutscheincode wurde erfolgreich aktiviert. Die Prämie wird deinem Bitcoin-Konto innerhalb von 14 Tagen gutgeschrieben.</string>
<string name="bitcoin_promo_activation_success_title">Promo-Code aktiviert</string>
<string name="bitcoin_promo_already_activated">Dieser Aktionscode wurde bereits verwendet und kann nicht erneut aktiviert werden.</string>
<string name="bitcoin_promo_already_activated_title">Code nicht verfügbar</string>
@ -150,6 +160,13 @@
<item quantity="one">Token</item>
<item quantity="other">Tokens</item>
</plurals>
<string name="card_reset_alert_continue_message">Bitte setze das nächste Gerät zurück, um fortzufahren.</string>
<string name="card_reset_alert_continue_title">Wallet zurückgesetzt</string>
<string name="card_reset_alert_finish_message">Alle Tangem-Geräte wurden zurückgesetzt. Du kannst nun mit dem Upgrade Deiner Wallet fortfahren.</string>
<string name="card_reset_alert_finish_ok_button">Erneut aktualisieren</string>
<string name="card_reset_alert_finish_title">Zurücksetzen abgeschlossen</string>
<string name="card_reset_alert_incomplete_message">Du hast nicht all Deine Tangem-Geräte zurückgesetzt.</string>
<string name="card_reset_alert_incomplete_title">Du hast nicht alle Deine Tangem-Geräte zurückgesetzt.</string>
<string name="card_settings_access_code_recovery_disabled_description">Deaktiviere diese Option, wenn du nicht möchtest, dass diese Karte oder Ring zum Zurücksetzen von Zugangscodes auf anderen Karten oder Ringe in dieser Wallets verwendet wird. Bitte beachte, dass du dann auch den Zugangscode auf dieser Karte oder Ring nicht zurücksetzen kannst.</string>
<string name="card_settings_access_code_recovery_enabled_description">Ermöglicht die Verwendung dieser Karte oder Ring zum Zurücksetzen des Zugangscodes auf anderen Karten oder Ringe in dieser Brieftasche</string>
<string name="card_settings_access_code_recovery_title">Zugangspin resetten</string>
@ -175,11 +192,13 @@
<string name="cardano_max_amount_has_token_title">Nicht genug ADA</string>
<string name="common_accept">Akzeptieren</string>
<string name="common_access_denied">Zugang verweigert</string>
<string name="common_account">Konto</string>
<string name="common_accounts">Konten</string>
<string name="common_activate">Aktivieren</string>
<string name="common_add">Hinzufügen</string>
<string name="common_add_to_portfolio">Zum Portfolio hinzufügen</string>
<string name="common_add_token">Token hinzufügen</string>
<string name="common_added">Hinzugefügt</string>
<string name="common_address">Vertragsadresse</string>
<string name="common_all">Alle</string>
<string name="common_allow">Erlauben</string>
@ -239,6 +258,7 @@
<string name="common_enable">Aktivieren</string>
<string name="common_enabled">Aktiviert</string>
<string name="common_error">Fehler</string>
<string name="common_estimated_fee">Netzwerkdienstgebühr</string>
<string name="common_exchange">Umtausch</string>
<string name="common_explore">Erkunden</string>
<string name="common_explore_transaction_history">Transaktionsverlauf einsehen</string>
@ -250,10 +270,12 @@
<string name="common_fee_selector_option_slow">Langsam</string>
<string name="common_fee_selector_title">Gebühren</string>
<string name="common_finish">Beenden</string>
<string name="common_forget">Entfernen</string>
<string name="common_free">Kostenlos</string>
<string name="common_from">Vom</string>
<string name="common_generate_addresses">Adressen synchronisieren</string>
<string name="common_get_started">Erste Schritte</string>
<string name="common_get_token">Token erhalten</string>
<string name="common_go_to_provider">Zum Anbieter gehen</string>
<string name="common_go_to_token">Zum Token</string>
<string name="common_got_it">Verstanden</string>
@ -266,6 +288,7 @@
<string name="common_left">%1$s übrig</string>
<string name="common_legacy_bitcoin_address">Legacy Bitcoin</string>
<string name="common_locked">Gesperrt</string>
<string name="common_locked_wallets">Gesperrte Wallet</string>
<string name="common_main_network">Hauptnetz</string>
<string name="common_month">monat</string>
<string name="common_network_fee_title">Netzgebühr</string>
@ -293,10 +316,12 @@
<string name="common_range_with_space">%1$s — %2$s</string>
<string name="common_read_more">Weiterlesen</string>
<string name="common_receive">Empfangen</string>
<string name="common_recommended">Empfohlen</string>
<string name="common_reject">Ablehnen</string>
<string name="common_reload">Neu laden</string>
<string name="common_rename">Umbenennen</string>
<string name="common_required">Erforderlich</string>
<string name="common_reset">Zurücksetzen</string>
<string name="common_save">Speichern</string>
<string name="common_save_changes">Änderungen speichern</string>
<string name="common_search">Suchen</string>
@ -316,6 +341,7 @@
<string name="common_sign">Signieren</string>
<string name="common_sign_and_send">Signieren und senden</string>
<string name="common_skip">Überspringen</string>
<string name="common_something_went_wrong">Etwas ist schiefgelaufen.</string>
<string name="common_stake">Staken</string>
<string name="common_staking">Staking</string>
<string name="common_start">Start</string>
@ -350,6 +376,8 @@
<string name="common_yes">Ja</string>
<string name="contract_address_copied_message">Vertragsadresse kopiert!</string>
<string name="currency_subtitle_expanded">Verfügbare Netzwerke</string>
<string name="custom_token_another_account_dialog_description">Die Ableitung Deines Tokens entspricht der Ableitung von %1$s. Dein Token wird diesem Konto gutgeschrieben.</string>
<string name="custom_token_another_account_dialog_title">Die Herleitung stammt aus einem anderen Bericht.</string>
<string name="custom_token_contract_address_input_title">Vertragsadresse</string>
<string name="custom_token_creation_error_invalid_contract_address">Vertragsadresse ist ungültig</string>
<string name="custom_token_creation_error_network_not_selected">Bitte wähle das Netzwerk</string>
@ -412,6 +440,7 @@
<string name="email_subject_wc_error">WalletConnect-Fehler</string>
<string name="error_wrong_wallet_tapped">Du hast eine Karte oder Ring aus einer anderen Wallet verwendet. Tippe auf die Karte oder Ring, die dieser Wallet zugeordnet ist.</string>
<string name="eth_gas_required_exceeds_allowance">Nicht genug Geld für die Transaktion. Bitte lade dein Konto auf.</string>
<string name="exchange_token_description">Tausche einen beliebigen Vermögenswert in deinem Portfolio gegen diesen Token.</string>
<string name="exchange_tokens_available_tokens_header">Meine Token</string>
<string name="exchange_tokens_empty_tokens">Du hast noch keine Token hinzugefügt. Füge Token über den Markt zum Tausch hinzu</string>
<string name="exchange_tokens_unavailable_tokens_header">Kann nicht gegen %s ausgetauscht werden</string>
@ -467,6 +496,7 @@
<string name="express_provider">Anbieter</string>
<string name="express_provider_best_rate">Bester Preis</string>
<string name="express_provider_fca_warning_list">Warnliste der FCA</string>
<string name="express_provider_great_rate">Beste Wahl</string>
<string name="express_provider_in_fca_warning_list">Anbieter in FCA-Warnliste</string>
<string name="express_provider_max_amount">Verfügbar bis zu %s</string>
<string name="express_provider_min_amount">Erhältlich bei %s</string>
@ -502,13 +532,20 @@
<string name="generic_error_code">Es ist ein Fehler aufgetreten. Code: %s.</string>
<string name="generic_requires_memo_error">Memo erforderlich</string>
<string name="give_permission_current_transaction">Nur diese</string>
<string name="give_permission_policy_type_footer">Gib das Genehmigungslimit für das ausgewählte Token an</string>
<string name="give_permission_policy_type_footer">Mit Deiner Zustimmung erlaubst Du dem Smart Contract, Deine Token in zukünftigen Transaktionen zu verwenden.</string>
<string name="give_permission_rows_amount">Betrag %s</string>
<string name="give_permission_staking_footer">Die Genehmigungsfunktion ist erforderlich, um einer anderen Adresse die Berechtigung zur Verwendung einer bestimmten Menge Ihrer Token zu erteilen. Standardmäßig können Smart Contracts nicht auf deine Token zugreifen, es sei denn, du stimmen zu. Indem du deine Token \"freischaltest\", autorisierst du den StakeKit Smart Contract, sie zu verwenden. Die Miner des Netzwerks erhalten eine Gasgebühr (von dir bezahlt), um diese Aktion in der Blockchain aufzuzeichnen. Du kannst deine Token einsetzen, nachdem du die Genehmigung erteilt hast.</string>
<string name="give_permission_staking_subtitle">Um fortzufahren, musst du Polygon Smart Contract erlauben, deine %s zu verwenden</string>
<string name="give_permission_swap_subtitle" formatted="false">Um fortzufahren, erteile %1s Smart Contracts die Berechtigung, dein zu %2s verwenden.</string>
<string name="give_permission_title">Erlaubnis erteilen</string>
<string name="give_permission_unlimited">Unbegrenzt</string>
<string name="hardware_wallet_backup_feature_description">Dein Backup wird mit 2 oder 3 Tangem-Karten erstellt. Bewahre diese an separaten &amp; sicheren Orten auf, um sie vor Verlust oder Beschädigung zu schützen es ist keine Seed-Phrase erforderlich.</string>
<string name="hardware_wallet_backup_feature_title">Backup mit mehreren Karten</string>
<string name="hardware_wallet_create_title">Tangem Wallet hinzufügen</string>
<string name="hardware_wallet_key_feature_description">Dein privater Schlüssel wird direkt in der Tangem-Karte generiert und verlässt diese nie.</string>
<string name="hardware_wallet_key_feature_title">Schlüsselgenerierung</string>
<string name="hardware_wallet_security_feature_description">Alle kryptografischen Vorgänge finden innerhalb des sicheren Chips statt, der gegen Klonen und physische Manipulation zertifiziert ist.</string>
<string name="hardware_wallet_security_feature_title">Sicherheit auf Hardwareebene</string>
<string name="home_button_add_existing_wallet">Vorhandene Wallet hinzufügen</string>
<string name="home_button_create_new_wallet">Neues Wallet erstellen</string>
<string name="home_button_order">Karte oder Ring bestellen</string>
@ -518,42 +555,67 @@
<string name="hot_crypto_token_network">Im %s Netzwerk</string>
<string name="hw_access_code_create_alert_title">Willst Du den Vorgang zur Erstellung des Zugangscodes wirklich beenden?</string>
<string name="hw_activation_need_backup">Jetzt sichern</string>
<string name="hw_activation_need_description">Um die Einrichtung abzuschließen, sicher Deine Wallet und sicher den App-Zugriff mit einem Access Code.</string>
<string name="hw_activation_need_description">Um die Einrichtung abzuschließen, sicher Deine Wallet und schütze die App mit einem Zugangscode.</string>
<string name="hw_activation_need_finish">Jetzt beenden</string>
<string name="hw_activation_need_title">Wallet-Aktivierung abschließen</string>
<string name="hw_activation_need_warning_description">Um das Setup abzuschließen, sicher den App-Zugriff mit Access Code.</string>
<string name="hw_activation_need_title">Wallet-Einrichtung abschließen</string>
<string name="hw_activation_need_warning_description">Schließe die Einrichtung ab, indem Du die App mit einem Zugangscode sicherst.</string>
<string name="hw_backup_alert_description">Wenn dies der Fall ist, musst Du von vorne beginnen.</string>
<string name="hw_backup_alert_title">Bist Du sicher, dass Du den Aktivierungsprozess beenden willst?</string>
<string name="hw_backup_alert_title">Möchtest Du den Aktivierungsprozess wirklich abbrechen?</string>
<string name="hw_backup_banner_description">Hält Deine Kryptowährungen sicher und offline. Schlank wie eine Kreditkarte, sicherer als ein Banktresor.</string>
<string name="hw_backup_close_description">Wenn dies der Fall ist, musst Du von vorne beginnen.</string>
<string name="hw_backup_google_drive_description">Vorhandene Wallet über Google Drive-Backup wiederherstellen</string>
<string name="hw_backup_google_drive_title">Google Drive-Backup</string>
<string name="hw_backup_hardware_description">Verbesser Deine Sicherheit sofort mit einer erstklassigen Hardware-Wallet von Tangem.</string>
<string name="hw_backup_hardware_create_description">Erstelle eine neue, sichere Wallet und übertrage Deine Gelder, um zusätzlichen Schutz zu gewährleisten.</string>
<string name="hw_backup_hardware_create_title">Neue Wallet erstellen</string>
<string name="hw_backup_hardware_description">Erhöhe Deine Sicherheit mit der überlegenen Hardware-Wallet von Tangem.</string>
<string name="hw_backup_hardware_title">Hardware-Wallet</string>
<string name="hw_backup_hardware_upgrade_description">Übertrage Deine aktuelle Wallet in die Tangem Wallet.</string>
<string name="hw_backup_hardware_upgrade_title">Aktualisiere Deine aktuelle Wallet</string>
<string name="hw_backup_need_action">Gehe zum Backup</string>
<string name="hw_backup_need_description">Um Deine Wallet mit einem Zugangscode zu sichern, führe zuerst die Sicherung durch.</string>
<string name="hw_backup_need_title">Sicherung zuerst beenden</string>
<string name="hw_backup_seed_description">Physische Karten, die Deine Kryptowährung sicher offline speichern.</string>
<string name="hw_backup_need_description">Bitte sicher Deine Wallet, bevor Du einen Zugangscode erstellst.</string>
<string name="hw_backup_need_title">Zuerst die Sicherung abschließen</string>
<string name="hw_backup_section_other_title">Andere Methoden</string>
<string name="hw_backup_seed_description">Physische Geräte, die Deine privaten Schlüssel sicher offline speichern.</string>
<string name="hw_backup_seed_title">Wiederherstellungs-Phrase</string>
<string name="hw_backup_to_upgrade_description">Um Deine Wallet auf Hardware umzustellen, erstelle vorher ein Backup.</string>
<string name="hw_create_keys_title">Schlüssel werden in der App gespeichert</string>
<string name="hw_create_seed_title">Sicherung der Seed-Phrase</string>
<string name="hw_create_title">Mobile Wallet erstellen</string>
<string name="hw_import_existing_wallet">Vorhandene Wallet importieren</string>
<string name="hw_import_seed_phrase_already_imported">Diese Wiederherstellungsphrase wurde bereits importiert</string>
<string name="hw_mobile_wallet">Mobile Wallet</string>
<string name="hw_remove_wallet_action_forget_title">Wallet dauerhaft entfernen</string>
<string name="hw_remove_wallet_attention_description">Diese Wallet wird dauerhaft von Deinem Gerät entfernt.</string>
<string name="hw_remove_wallet_confirmation_title">Bist du dir sicher, dass du das tun willst?</string>
<string name="hw_remove_wallet_nav_title">Wallet dauerhaft entfernen</string>
<string name="hw_remove_wallet_notification_action_backup_go">Zum Backup wechseln</string>
<string name="hw_remove_wallet_notification_action_backup_view">Backup anzeigen</string>
<string name="hw_remove_wallet_notification_action_forget">Entferne Deine Wallet für immer!</string>
<string name="hw_remove_wallet_notification_action_forget_anyway">Trotzdem entfernen!</string>
<string name="hw_remove_wallet_notification_description_has_backup">Für diese Wallet existiert ein Backup. Überprüfe dieses bitte, bevor Du sie entfernst, um sicherzustellen, dass Du sie später wiederherstellen kannst.</string>
<string name="hw_remove_wallet_notification_description_without_backup">Wenn Du diese Wallet ohne Backup entfernst, verlierst Du dauerhaft den Zugriff auf Deine Assets.</string>
<string name="hw_remove_wallet_notification_title">Diese Wallet dauerhaft entfernen?</string>
<string name="hw_remove_wallet_warning_access">Mir ist bewusst, dass ich den Zugriff auf meine Wallet verliere kann, wenn ich sie vor der Entfernung nicht gesichert habe.</string>
<string name="hw_remove_wallet_warning_device">Mir ist bewusst, dass durch das Entfernen meiner Wallet diese nicht gelöscht, sondern lediglich von meinem Gerät entfernt wird.</string>
<string name="hw_upgrade_backup_description">Es wird keine Seed-Phrase mehr benötigt Deine Tangem-Karte oder Dein Tangem-Ring wird zu Deinem sicheren Backup.</string>
<string name="hw_upgrade_backup_title">Backup mit Tangem</string>
<string name="hw_upgrade_error_card_already_has_wallet">Ein Upgrade ist nicht möglich. Auf diesem Gerät ist bereits eine Wallet vorhanden.</string>
<string name="hw_upgrade_error_card_key_import">Wähle ein anderes Gerät. Dieses Gerät kann für das Upgrade nicht verwendet werden.</string>
<string name="hw_upgrade_error_wallet2_card_required">Bei der Operation ist ein Fehler aufgetreten.</string>
<string name="hw_upgrade_funds_access_description">Dein Geld bleibt während des gesamten Prozesses sicher und vollständig zugänglich</string>
<string name="hw_upgrade_funds_access_title">Zugang zu Geldern</string>
<string name="hw_upgrade_general_security_description">Alle privaten Wallet-Daten werden aus der mobilen App entfernt und nur sicher auf Deinem Tangem-Gerät gespeichert</string>
<string name="hw_upgrade_general_security_description">Die Daten Deiner Wallet werden aus der App gelöscht und auf Deinem Tangem-Gerät gespeichert</string>
<string name="hw_upgrade_general_security_title">Allgemeine Sicherheit</string>
<string name="hw_upgrade_key_migration_description">Private Schlüssel werden von der App auf Deine Tangem-Karte oder Deinen Tangem-Ring verschoben</string>
<string name="hw_upgrade_key_migration_description">Die privaten Schlüssel werden von der App auf Ihr Tangem-Gerät übertragen.</string>
<string name="hw_upgrade_key_migration_title">Schlüsselmigration</string>
<string name="hw_upgrade_scan_device">Gerät scannen</string>
<string name="hw_upgrade_start_action">Upgrade starten</string>
<string name="hw_upgrade_start_description">Du bist dabei, Deine Wallet auf Tangem Wallet zu aktualisieren. Dies wird Dein Vermögen mit cold-storage sicher verwahren.</string>
<string name="hw_upgrade_start_description">Du stehst kurz vor dem Upgrade auf unsere Hardware-Wallet. Damit werden Deine Vermögenswerte sicher in Offline-Speichern aufbewahrt.</string>
<string name="hw_upgrade_start_title">Tangem Wallet</string>
<string name="hw_upgrade_title">Upgrade auf Hardware Wallet</string>
<string name="hw_upgrade_to_cold_banner_description">Bewahren Deine Kryptowährungen sicher auf - mit der erstklassigen Hardware-Wallet von Tangem.</string>
<string name="hw_upgrade_to_cold_banner_title">Wallet mit einem Hardware-Backup aufrüsten</string>
<string name="information_generated_with_ai">Diese Informationen wurden mithilfe von KI generiert.\nTippe hier, wenn Du Fehler finden.</string>
<string name="hw_upgrade_to_cold_banner_description">Schütze Deine Kryptowährungen mit Tangems erstklassiger Hardware-Wallet.</string>
<string name="hw_upgrade_to_cold_banner_title">Rüste Deine Wallet auf Hardware-Sicherheit auf.</string>
<string name="information_generated_with_ai">Diese Informationen wurden mithilfe von KI generiert.\nTippe hier, wenn Du Fehler findest.</string>
<string name="initial_message_change_access_code_body">Um den Zugangscode zu ändern, halte die Karte oder Ring wie oben gezeigt an das Gerät und entferne sie erst am Ende des Vorgangs.</string>
<string name="initial_message_change_passcode_body">Um den Passcode zu ändern, halte die Karte oder Ring wie oben gezeigt an das Gerät und entferne sie erst am Ende des Vorgangs.</string>
<string name="initial_message_create_wallet_body">Um die Wallet zu erstellen, halte die Karte oder Ring wie oben gezeigt an das Gerät und entferne sie erst am Ende des Vorgangs.</string>
@ -599,6 +661,7 @@
<string name="manage_tokens_unavailable_description">Der ausgewählte Token ist derzeit nicht für Aktionen innerhalb der Krypto-Wallet verfügbar. Aber keine Sorge, du kannst dein Interesse bekunden, indem du den Token hochstufen.</string>
<string name="manage_tokens_unavailable_vote">Hochstimmen</string>
<string name="manage_tokens_wallet_support_only_one_network_title">Das Wallet unterstützt nicht mehr als ein Netzwerk</string>
<string name="markets_about_coin_header">Über diesen Coin</string>
<string name="markets_add_to_my_portfolio_description">Um dieses Asset zu kaufen, zu tauschen oder zu erhalten, füge diesen Deinem Portfolio hinzu</string>
<string name="markets_add_to_my_portfolio_unavailable_description">Dieses Asset wird derzeit in der Wallet nicht unterstützt.</string>
<string name="markets_add_to_my_portfolio_unavailable_for_wallet_description">Dieses Asset ist für dieses Wallet nicht verfügbar</string>
@ -634,6 +697,7 @@
<string name="markets_sort_by_trending_title">Beliebt</string>
<string name="markets_staking_banner_description_placeholder">Staking ist der einfachste Weg, um Belohnungen für Deine Kryptowährung zu erhalten. %s</string>
<string name="markets_staking_banner_title">Verdiene bis zu %s APY</string>
<string name="markets_token_added">Token hinzugefügt</string>
<string name="markets_token_details_about_token_title">Über %s</string>
<plurals name="markets_token_details_amount_exchanges">
<item quantity="one">%d börse</item>
@ -779,7 +843,7 @@
<string name="onboarding_add_tokens">Token hinzufügen</string>
<string name="onboarding_alert_message_not_max_backup_cards_added">Du hast eine Backup-Karte oder einen Backup-Ring hinzugefügt. Nach Abschluss des Backup-Vorgangs kannst Du keine weiteren Backup-Geräte hinzufügen. Wenn Du eine weitere Karte oder einen weiteren Ring hast, fügen diesen dem Backup jetzt hinzu. Möchtest Du den Backup-Vorgang fortsetzen?</string>
<string name="onboarding_backup_exit_warning">Der Sicherungsvorgang ist teilweise abgeschlossen. Du kannst ihn jetzt nicht beenden.</string>
<string name="onboarding_bottom_sheet_passphrase_description">Die Passphrase ist eine fortschrittliche Sicherheitsfunktion, die von Krypto-Wallets verwendet wird. Sie fügt ein zusätzliches Wort oder eine Phrase deiner Wahl zu der bereits bestehenden Wiederherstellungsphrase hinzu, um einen brandneuen Satz von Adressen zu erzeugen.</string>
<string name="onboarding_bottom_sheet_passphrase_description">Eine Passphrase ist eine optionale Sicherheitsfunktion, die Deiner Wiederherstellungsphrase ein Wort oder eine Phrase hinzufügt und so einen neuen Satz von Wallet-Adressen für zusätzlichen Schutz erstellt.</string>
<string name="onboarding_button_add_backup_card">Hinzufügen einer Sicherungskarte oder Ring</string>
<string name="onboarding_button_backup_card">Karte oder Ring scannen</string>
<string name="onboarding_button_backup_card_format">Scanne die Karte oder Ring Nr. %d</string>
@ -807,6 +871,7 @@
<string name="onboarding_linking_error_card_with_wallets">Für die Karte oder Ring, die du hinzufügen möchtest, wurde bereits eine andere Wallets erstellt. Wenn du Guthaben auf dieser Wallets hast, hebe es bitte ab, setze diese Karte oder Ring zurück und füge sie als Backup hinzu.</string>
<string name="onboarding_navbar_save_wallet">Sicher deine Wallet</string>
<string name="onboarding_navbar_title_creating_backup">Backups anlegen</string>
<string name="onboarding_navbar_upgrade_wallet_biometrics">Biometrische Daten</string>
<string name="onboarding_seed_button_read_more">Lese mehr über die Seed-Phrase</string>
<plurals name="onboarding_seed_generate_message_words_count">
<item quantity="one"></item>
@ -868,6 +933,7 @@
<string name="onramp_currency_other">Andere Währungen</string>
<string name="onramp_currency_popular">Beliebte Fiats</string>
<string name="onramp_currency_search">Suche nach Währung</string>
<string name="onramp_fetching_best_rates">Die besten Preise erzielen...</string>
<string name="onramp_instant_status">Sofort</string>
<string name="onramp_legal">Durch die Nutzung der Onramp-Funktionalität stimmst Du den %1$s und %2$s des Anbieters zu.</string>
<string name="onramp_legal_text">Der Service wird von einem externen Anbieter bereitgestellt. \n Tangem übernimmt keine Verantwortung.</string>
@ -894,7 +960,12 @@
<string name="onramp_settings_residence_description">Bitte wähle das richtige Land aus, um korrekte Zahlungsoptionen und Dienstleistungen zu gewährleisten.</string>
<string name="onramp_settings_title">Einstellungen</string>
<string name="onramp_statuses_view_footer">Du kannst diesen Bildschirm schließen und den Transaktionsstatus auf dem Bildschirm mit den Token-Details überprüfen.</string>
<plurals name="onramp_timing_days">
<item quantity="one">bis zu %d Tag</item>
<item quantity="other">bis zu %d Tagen</item>
</plurals>
<string name="onramp_timing_minutes">%s min</string>
<string name="onramp_title_available_from">Erhältlich ab</string>
<string name="onramp_title_you_get">Du erhältst</string>
<string name="onramp_tos_external_providers">Der Service wird von einem externen Anbieter bereitgestellt. \n Tangem übernimmt keine Verantwortung.</string>
<string name="onramp_transaction_status_footer_text">Du kannst diesen Bildschirm schließen und den Transaktionsstatus auf dem Bildschirm mit den Token-Details überprüfen.</string>
@ -959,6 +1030,10 @@
<string name="reset_card_to_factory_condition_2">Mir ist klar, dass ich diese Karte oder Ring nicht verwenden kann, um meinen Zugangscode auf den anderen Karten oder Ringe der aktuellen Wallet wiederherzustellen</string>
<string name="reset_card_with_backup_to_factory_message">Durch das Zurücksetzen auf Werkseinstellungen wird die Wallet vollständig von der ausgewählten Karte oder Ring gelöscht. Du kannst die aktuelle Wallet nicht wiederherstellen oder die Karte oder Ring verwenden, um den Zugangscode wiederherzustellen.</string>
<string name="reset_card_without_backup_to_factory_message">Beim Zurücksetzen auf die Werkseinstellungen wird die Wallet der ausgewählten Karte oder Ring vollständig gelöscht und aus der App entfernt. Es ist nicht möglich, die aktuelle Wallet wiederherzustellen.</string>
<string name="reset_cards_dialog_complete_description">Alle Tangem-Geräte wurden zurückgesetzt.</string>
<string name="reset_cards_dialog_first_description">Bei der Aktivierung ist ein Fehler aufgetreten. Bitte setze die Karten nacheinander zurück.</string>
<string name="reset_cards_dialog_first_title">Kartenprüfung fehlgeschlagen</string>
<string name="reset_cards_dialog_next_device_description">Bitte setze das nächste Gerät zurück, um fortzufahren.</string>
<string name="ring_promo_text">Ringbesitzer erhalten bis zum 15.11. 3 provisionsfreie Swaps auf Changelly!</string>
<string name="ring_promo_title">Jetzt mit 0 % Gebühren tauschen!</string>
<string name="save_user_wallet_agreement_access_description">Melde dich bei der App an und überprüfe dein Guthaben, ohne die Karte oder Ring zu scannen</string>
@ -1083,11 +1158,11 @@
<string name="send_with_swap_change_token_alert_message">Bist Du sicher, dass Du den Empfangstoken ändern möchtest? Dadurch werden Dein zuvor eingegebenen Daten zurückgesetzt.</string>
<string name="send_with_swap_change_token_alert_title">Token ändern</string>
<string name="send_with_swap_confirm_title">Tauschen und senden</string>
<string name="send_with_swap_convert_token_alert_message">Mit der Konvertierung fortfahren? Dadurch werden Deine vorherigen Daten gelöscht.</string>
<string name="send_with_swap_convert_token_alert_message">Mit dem Datentausch fortfahren? Dadurch werden Deine vorherigen Daten gelöscht.</string>
<string name="send_with_swap_convert_token_alert_title">Konvertierung bestätigen</string>
<string name="send_with_swap_correct_recipient_network_notification_message">Das Senden einer anderen Währung führt zu deren unwiderruflichem Verlust.</string>
<string name="send_with_swap_correct_recipient_network_notification_title">Wähle das richtige Empfängernetzwerk</string>
<string name="send_with_swap_notification_text">Sende uns ein Token, und wir konvertieren es unterwegs. Dein Empfänger erhält genau das, was er braucht nahtlos.</string>
<string name="send_with_swap_notification_text">Wähle einen beliebige Token aus, den Du bekommen möchtest. Dein Empfänger erhält genau das, was Du ausgewählt hast nahtlos.</string>
<string name="send_with_swap_recipient_amount_success_title">Der Empfänger erhält</string>
<string name="send_with_swap_recipient_amount_text">An den Empfänger</string>
<string name="send_with_swap_recipient_amount_title">Zu erhaltender Betrag</string>
@ -1102,11 +1177,12 @@
<string name="settings_wallet_name_title">Name</string>
<string name="stake_token_description">Lass deinen Token für dich arbeiten</string>
<string name="staking_account_initialization_footer">Eine Netzwerkgebühr ist eine kleine Zahlung, die erforderlich ist, um Deine Transaktion auf der Blockchain zu verarbeiten und zu bestätigen.</string>
<string name="staking_account_initialization_message">Um mit dem Staking zu beginnen, muss Dein TON-Konto mit einer Selbsttransaktion von 1 TON aktiviert werden. Das Guthaben verbleibt in Deiner Wallet dieser Schritt aktiviert Dein Konto lediglich für das Staking.</string>
<string name="staking_account_initialization_message">Um mit dem Staking zu beginnen, muss Dein TON-Konto mit einer Transaktion von 1 TON aktiviert werden. Das Guthaben verbleibt auf Deinem Konto, dieser Schritt dient lediglichder aktivierung für das Staking.</string>
<string name="staking_account_initialization_title">Kontoaktivierung</string>
<string name="staking_amount_requirement_error">Die Anzahl der zu stakenden Krypros muss mindesten %s betragen</string>
<string name="staking_amount_tron_integer_error">Der Stakingbetrag wird aufgrund der Netzwerkregeln auf %1$s TRX aufgerundet.</string>
<string name="staking_amount_tron_integer_error_unstaking">Der Betrag der unstaked wird, wird aufgrund der Netzwerkregeln auf %1$s TRX gerundet.</string>
<string name="staking_apr_earn_badge">Effektiver Jahreszins %1$s%%</string>
<string name="staking_claim_unstaked">Nicht gestakte beanspruche</string>
<string name="staking_details_account_fee">Gebühr für das Staking-Konto</string>
<string name="staking_details_account_fee_info">Ein Staking-Konto ist ein spezielles Konto, auf dem eingesetzte SOL-Token gespeichert werden. Es wird erstellt, indem Sie Ihre Token an einen Validator delegieren, um an der Transaktionsvalidierung teilzunehmen und Belohnungen zu erhalten. Für die Einrichtung des Staking-Kontos wird eine geringe Gebühr erhoben, die nach Abschluss des Stakings zurückerstattet wird.</string>
@ -1167,10 +1243,10 @@
<string name="staking_notification_new_validator_funds_transfer">Wenn Du im %1$s -Netzwerk mit einem neuen Validator stakest, werden alle zuvor eingesetzten Gelder automatisch an diesen Validator übertragen.</string>
<string name="staking_notification_restake_rewards_text">Reinvestiert Deine verdienten Prämien in Deinen Einsatzbetrag und erhöht so den potenziellen Gewinn.</string>
<string name="staking_notification_restake_text">Mit Restake kannst Du Dein Guthaben von einem Validator zu einem anderen verschieben, ohne dass Du den Stake aufheben musst.</string>
<string name="staking_notification_stake_entire_balance_text">Du bist dabei, Dein gesamtes Guthaben zu staken. Wir empfehlen, einen kleinen Betrag übrig zu lassen, um die Netzwerkgebühren für die Aufhebung des Stakes oder das Einfordern von Prämien abzudecken.</string>
<string name="staking_notification_ton_account_initialization_message">Um mit dem Staking zu beginnen, muss Dein TON-Konto mit einer Selbsttransaktion von 1 TON aktiviert werden. Das Guthaben verbleibt in Deiner Wallet dieser Schritt aktiviert Dein Konto lediglich für das Staking.</string>
<string name="staking_notification_stake_entire_balance_text">Wenn Du Dein gesamtes Guthaben einsetzt, musst Du beim Aufheben der Einsätze eine Netzwerkgebühr entrichten. Wir empfehlen, einen kleinen Betrag in Deiner Wallet zu belassen, um die Netzwerkgebühren zu decken.</string>
<string name="staking_notification_ton_account_initialization_message">Um mit dem Staking zu beginnen, musst Du zuerst Dein TON-Konto aktivieren.</string>
<string name="staking_notification_ton_account_initialization_title">Kontoaktivierung</string>
<string name="staking_notification_ton_activate_account">Um mit dem Staking bei TON zu beginnen, führe zunächst eine ausgehende Transaktion in beliebiger Höhe durch dadurch wird Deine Wallet aktiviert.</string>
<string name="staking_notification_ton_activate_account">Um mit dem Staking in TON zu beginnen, sende zunächst eine kleine Transaktion an Deine eigene Adresse dadurch wird Deine Wallet aktiviert.</string>
<string name="staking_notification_ton_extra_reserve_info">Für den Abschluss der Transaktion können zusätzlich zur Netzwerkgebühr bis zu 0,2 TON erforderlich sein. Nicht genutzte Beträge werden zurückerstattet.</string>
<string name="staking_notification_ton_extra_reserve_is_required">Für diesen Vorgang sind zusätzlich zur Netzwerkgebühr 0,2 TON erforderlich. Bitte lade Dein Guthaben auf.</string>
<string name="staking_notification_ton_extra_reserve_title">TON-Reserve erforderlich</string>
@ -1275,10 +1351,48 @@
<string name="swapping_to_title">Du erhältst</string>
<string name="swapping_token_list_title">Token auswählen</string>
<string name="swapping_token_not_available">Nicht verfügbar</string>
<string name="tangem_pay_deposit">Einzahlung</string>
<string name="tangem_pay_dispute">Streitfall</string>
<string name="tangem_pay_explore_transaction">Transaktion erkunden</string>
<string name="tangem_pay_fee_subtitle">Servicegebühren</string>
<string name="tangem_pay_fee_title">Gebühr</string>
<string name="tangem_pay_freeze_card_alert_body">Schütze Dein Geld, falls Deine Karte verloren geht oder gestohlen wird. Du kannst die Sperre jederzeit aufheben.</string>
<string name="tangem_pay_freeze_card_alert_title">Karte sperren lassen?</string>
<string name="tangem_pay_freeze_card_freeze">Einfrieren</string>
<string name="tangem_pay_get_help">Hilfe erhalten</string>
<string name="tangem_pay_status_completed">Abgeschlossen</string>
<string name="tangem_pay_status_declined">Abgelehnt</string>
<string name="tangem_pay_status_pending">Ausstehend</string>
<string name="tangem_pay_transaction_declined_notification_text">Die Bank hat diese Transaktionsanfrage abgelehnt.</string>
<string name="tangem_pay_transaction_fee_notification_text">Diese Gebühr dient zur Deckung der Kosten für die Abwicklung Deiner Überweisung.</string>
<string name="tangem_pay_withdrawal">Abhebung</string>
<string name="tangempay_card_details_add_funds">Guthaben hinzufügen</string>
<string name="tangempay_card_details_add_funds_subtitle">Aufladeoptionen</string>
<string name="tangempay_card_details_change_pin">PIN ändern</string>
<string name="tangempay_card_details_change_pin_success_description">Die Karte ist vollständig für Zahlungen bereit.</string>
<string name="tangempay_card_details_change_pin_success_title">PIN-Code erstellt</string>
<string name="tangempay_card_details_error_text">Daten konnten nicht geladen werden. Versuche es später noch einmal.</string>
<string name="tangempay_card_details_freeze_card">Karte einfrieren</string>
<string name="tangempay_card_details_hide_text">Verstecken</string>
<string name="tangempay_card_details_open_wallet_button">Google Wallet öffnen</string>
<string name="tangempay_card_details_open_wallet_notification_subtitle">Richte Tangem Pay mit wenigen Klicks ein und bezahlen mit Google Pay.</string>
<string name="tangempay_card_details_open_wallet_notification_title">Karte zu Google Pay hinzufügen</string>
<string name="tangempay_card_details_open_wallet_step_1">Google Wallet öffnen</string>
<string name="tangempay_card_details_open_wallet_step_2">Tippe auf „Karte hinzufügen“.</string>
<string name="tangempay_card_details_open_wallet_step_3">Gebe die Kartendaten manuell ein</string>
<string name="tangempay_card_details_open_wallet_step_4">Verifiziere die Karte mit dem Einmalpasswort (OPT), das an Dein Gerät gesendet wird.</string>
<string name="tangempay_card_details_open_wallet_step_5">Alles erledigt! Deine Karte ist einsatzbereit.</string>
<string name="tangempay_card_details_open_wallet_title">Karte zu Google Pay hinzufügen</string>
<string name="tangempay_card_details_receive_description">Teile Deine Adresse mit oder zeig den QR-Code.</string>
<string name="tangempay_card_details_receive_error_description">Es wurden technische Probleme festgestellt. Bitte versuche es später erneut oder kontaktiere den Support.</string>
<string name="tangempay_card_details_receive_error_title">Empfangen ist jetzt nicht verfügbar</string>
<string name="tangempay_card_details_reveal_text">Aufdecken</string>
<string name="tangempay_card_details_swap_description">Tausche beliebige Vermögenswerte in Deinem Portfolio gegen eine Karte.</string>
<string name="tangempay_card_details_title">Kartendetails</string>
<string name="tangempay_issue_card_notification_title">Konto erstellen und Karte ausstellen</string>
<string name="tangempay_kyc_card_ready_notification_title">Tangem Pay</string>
<string name="tangempay_kyc_in_progress_notification_button">Status anzeigen</string>
<string name="tangempay_kyc_in_progress_notification_title">KYC für Tangem Pay in Arbeit</string>
<string name="tangempay_onboarding_get_card_button_text">Karte erhalten</string>
<string name="tangempay_onboarding_pay_description">Füge es Deiner Wallet hinzu und bezahle überall mit Deinem Smartphone.</string>
<string name="tangempay_onboarding_pay_title">Apple Pay &amp; Google Pay</string>
@ -1304,6 +1418,7 @@
<string name="token_button_unavailability_reason_pending_transaction_send">Die Geldsendung wird verfügbar, sobald die ausstehende(n) Transaktion(en) im Netzwerk %s abgeschlossen ist/sind.</string>
<string name="token_button_unavailability_reason_sell_unavailable">Der Verkauf von %s wird von aktuellen Anbietern nicht unterstützt, aber wir arbeiten daran, weitere Optionen hinzuzufügen.</string>
<string name="token_button_unavailability_reason_staking_unavailable">Staking %s wird von aktuellen Anbietern nicht unterstützt, aber wir arbeiten daran, weitere Optionen hinzuzufügen.</string>
<string name="token_button_unavailability_reason_yield_supply_approval">Die Genehmigung wurde widerrufen. Dein Guthaben befindet sich weiterhin im Ertragsmodus. Um Aktionen durchzuführen, wechsel bitte in den Ertragsmodus und erteilen die Berechtigung erneut.</string>
<string name="token_details_generate_xpub">Generiere XPUB</string>
<string name="token_details_hide_alert_hide">Ausblenden</string>
<string name="token_details_hide_alert_message">Du bist dabei, dieses Token vom Hauptbildschirm auszublenden. Du kannst es jederzeit über die Seite „Token verwalten“ wieder hinzufügen.</string>
@ -1367,6 +1482,7 @@
<string name="user_push_notification_banner_subtitle">Aktiviere Push-Benachrichtigungen und wir benachrichtigen Dich sofort, wenn Gelder eintreffen</string>
<string name="user_push_notification_banner_title">Verpasse keine Transaktion</string>
<string name="user_wallet_list_add_button">Neues Wallet hinzufügen</string>
<string name="user_wallet_list_delete_hw_prompt">Wenn Du diese Wallet ohne vorheriges Backup löschst, verlierst Du dauerhaft den Zugriff auf Dein Guthaben.</string>
<string name="user_wallet_list_delete_prompt">Möchtest Du diese Wallet wirklich entfernen?</string>
<string name="user_wallet_list_error_unable_to_unlock">Es ist ein Fehler aufgetreten, bitte scanne deine Karte oder Ring, um sich anzumelden</string>
<string name="user_wallet_list_error_wallet_already_saved">Dieses Wallet wurde bereits gespeichert, du kannst ein weiteres hinzufügen</string>
@ -1382,15 +1498,19 @@
</plurals>
<string name="visa_main_balances_and_limits">Guthaben und Limits</string>
<string name="visa_onboarding_access_code_navigation_title">Zugangscode</string>
<string name="visa_onboarding_account_activation_navigation_title">Aktivierung des Kontos</string>
<string name="visa_onboarding_approve_wallet_selector_notification_message">Bitte wähle die Wallet aus, mit der Du den Registrierungsprozess gestartet hast, um die Transaktion zur Erstellung Deines Kontos auf der Blockchain zu signieren</string>
<string name="visa_onboarding_close_alert_message">Möchtest Du den Vorgang wirklich beenden? Du kannst später dort fortfahren, wo Du aufgehört hast.</string>
<string name="visa_onboarding_in_progress_description">Das wird nicht lange dauern. Wir richten gerade Dein Konto ein.</string>
<string name="visa_onboarding_in_progress_issuer_description">Das wird nicht lange dauern. Wir schließen die Aktivierung ab.</string>
<string name="visa_onboarding_in_progress_title">Alles wird vorbereitet!</string>
<string name="visa_onboarding_other_wallet">Andere Wallet</string>
<string name="visa_onboarding_pin_code_title">PIN-Code erstellen</string>
<string name="visa_onboarding_pin_not_accepted">PIN wurde nicht akzeptiert. Versuche es erneut oder verwende einen anderen Code.</string>
<string name="visa_onboarding_pin_validation_error_message">Ungültige PIN: Sequenzen oder Wiederholungen vermeiden</string>
<string name="visa_onboarding_success_screen_description">Schon kann es losgehen!</string>
<string name="visa_onboarding_tangem_approve_description">Halte die Tangem-Karte bereit und tippe diese um zum Genehmigen.</string>
<string name="visa_onboarding_tangem_approve_title">Tangem Wallet vorbereiten</string>
<string name="visa_onboarding_wallet_connect_description">Du kannst Deine Verbindung \n auf der Website des Drittanbieters \n herstellen und zurück zur Tangem-App gelangen</string>
<string name="visa_onboarding_wallet_connect_title">Zur Website gehen</string>
<string name="visa_onboarding_wallet_list_header">Wallet wählen</string>
@ -1402,6 +1522,13 @@
<string name="visa_unlock_notification_button">Freischalten</string>
<string name="visa_unlock_notification_subtitle">Scanne Deine Karte, um den Zugriff freizuschalten</string>
<string name="visa_unlock_notification_title">Benötigte Freischaltung</string>
<string name="wallet_add_common_title">Wähle aus, wie Du Deine Wallet hinzufügen möchtest.</string>
<string name="wallet_add_hardware_description">Scanne Deine Tangem-Karte oder Deinen Tangem-Ring, um sie wiederherzustellen oder aus einer anderen Wallet zu importieren.</string>
<string name="wallet_add_hardware_info_create">Hardware-Wallet erstellen</string>
<string name="wallet_add_hardware_purchase">Möchtest Du eine Tangem-Wallet kaufen?</string>
<string name="wallet_add_import_seed_phrase">Seed-Phrase importieren</string>
<string name="wallet_add_mobile_description">Stell Deine Wallet auf Deinem Smartphone wieder her oder importieren diese aus einer anderen App praktisch, aber weniger sicher als eine Tangem-Karte.</string>
<string name="wallet_add_support_title">Was soll man wählen?</string>
<string name="wallet_balance_blockchain_unreachable_try_later">Blockchain ist nicht erreichbar. Versuche es später nochmal</string>
<string name="wallet_balance_missing_derivation">Karte oder Ring scannen</string>
<string name="wallet_been_activated_message">Dieses Wallet wurde bereits früher aktiviert. \n Wenn dies nicht von Dir durchgeführt wurde, wende Dich bitte an den Support. \n Tangem verkauft niemals Wallets zusammen mit vorgenerierten Zugangscodes.</string>
@ -1422,6 +1549,8 @@
<string name="wallet_connect_error_wrong_card_selected">Falsche Karte oder Ring in der Tangem App ausgewählt</string>
<string name="wallet_connect_failed_to_build_tx">Transaktion aus Dapp-Daten konnte nicht erstellt werden. Code: %s</string>
<string name="wallet_connect_generic_error_with_code">Es ist ein unbekannter Fehler aufgetreten. Fehlercode: %d. Wenn das Problem weiterhin besteht, wende dich bitte an unseren Support</string>
<string name="wallet_connect_multiple_transactions">Mehrteilige Transaktion</string>
<string name="wallet_connect_multiple_transactions_description">Zur erfolgreichen Abwicklung wird Deine Transaktion in mehrere Teile aufgeteilt. Du musst Deine Karte mehrmals ans smartphone halten, um sie abzuschließen.</string>
<string name="wallet_connect_no_sessions_message">Keine geöffneten WalletConnect-Sitzungen</string>
<string name="wallet_connect_no_sessions_title">Hoppla. Keine Sitzungen.</string>
<string name="wallet_connect_pairing_error">WalletConnect-Sitzung konnte nicht gekoppelt werden: %1$s</string>
@ -1433,29 +1562,32 @@
<string name="wallet_connect_scanner_error_not_valid_card">Mit dieser Karte oder Ring kann keine WalletConnect-Sitzung hergestellt werden</string>
<string name="wallet_connect_scanner_error_unsupported_network">Dieses Netzwerk wird nicht unterstützt. Bitte wähle ein anderes Netzwerk.</string>
<string name="wallet_connect_select_network">Netzwerk auswählen</string>
<string name="wallet_connect_sending_multiple_explanation">Die Transaktion wird verarbeitet. Bitte halte Deine Karte mehrmals an, um sie abzuschließen.</string>
<string name="wallet_connect_sending_multiple_tx">Transaktion läuft</string>
<string name="wallet_connect_sessions_title">WalletConnect-Sitzungen</string>
<string name="wallet_connect_subtitle">Mit dApps verbinden</string>
<string name="wallet_connect_title">WalletConnect</string>
<string name="wallet_connect_toast_awaiting_session_proposal">Das Herstellen der Verbindung kann einige Sekunden dauern</string>
<string name="wallet_create_common_title">Tangem-Wallet erstellen</string>
<string name="wallet_create_hardware_badge">Von %s</string>
<string name="wallet_create_hardware_description">Kaufe eine Tangem Wallet physische Karten, die Deine Kryptowährungen sicher offline speichern.</string>
<string name="wallet_create_hardware_description">Kaufe eine Tangem Wallet ein physisches Gerät, das Deine privaten Schlüssel sicher offline speichert.</string>
<string name="wallet_create_hardware_title">Hardware-Wallet</string>
<string name="wallet_create_mobile_description">Eine sichere Wallet wird in Sekundenschnelle auf Deinem Telefon erstellt.</string>
<string name="wallet_create_mobile_description">Erstelle in Sekundenschnelle eine sichere Wallet auf Deinem Smartphone.</string>
<string name="wallet_create_mobile_title">Mobile Wallet</string>
<string name="wallet_create_nav_info_title">Was soll ich wählen?</string>
<string name="wallet_create_scan_question">Besitzt Du bereits eine Tangem Wallet?</string>
<string name="wallet_create_nav_info_title">Was auswählen?</string>
<string name="wallet_create_scan_question">Verwendest Du bereits eine Tangem-Wallet?</string>
<string name="wallet_create_scan_title">Jetzt scannen</string>
<string name="wallet_create_title">Wähle, wie Du Deine Wallet erstellen möchten</string>
<string name="wallet_create_title">Wähle eine Methode zur Einrichtung Deiner Wallet.</string>
<string name="wallet_import_buy_question">Möchtest Du eine Tangem-Wallet kaufen?</string>
<string name="wallet_import_buy_title">Jetzt kaufen</string>
<string name="wallet_import_google_drive_description">Eine vorhandene Wallet wiederherstellen, die Deinem Google Drive-Backup gespeichert ist</string>
<string name="wallet_import_google_drive_description">Stelle Deine bestehende Wallet über ein Google Drive-Backup wieder her.</string>
<string name="wallet_import_google_drive_title">Importieren aus Google Drive</string>
<string name="wallet_import_navtitle">Vorhandenes Wallet hinzufügen</string>
<string name="wallet_import_scan_description">Physische Karten, die Deine Kryptowährung sicher offline speichern.</string>
<string name="wallet_import_scan_title">Scanne eine Tangem-Wallet</string>
<string name="wallet_import_seed_description">Deine Seed-Phrase, um Deine Wallet wiederherzustellen</string>
<string name="wallet_import_seed_description">Importiere eine bestehende Wallet mit Deiner Wiederherstellungsphrase.</string>
<string name="wallet_import_seed_navtitle">Wallet importieren</string>
<string name="wallet_import_seed_title">Importieren einer Wiederherstellungsphrase</string>
<string name="wallet_import_seed_title">Wiederherstellungsphrase eingeben</string>
<string name="wallet_import_success_description">Du hast Deine Wallet erfolgreich gesichert.</string>
<string name="wallet_import_success_navtitle">Wallet importieren</string>
<string name="wallet_import_success_title">Import abgeschlossen</string>
@ -1468,7 +1600,7 @@
<string name="wallet_promo_banner_button_title">Jetzt mit 10 % Rabatt kaufen</string>
<string name="wallet_promo_banner_description">Greife auf 13.000+ Kryptowährungen zu. Kaufe, verkaufe, tausche und stake Sie mit einem einzigen Fingertipp.\nVerbinde bis zu drei Karten für ein Backup.</string>
<string name="wallet_promo_banner_title">Entdecke die Tangem Wallet</string>
<string name="wallet_settings_access_code_description">Geheimcode zum Schutz dieser Wallet. Wird für Anmeldung und Signaturen verwendet.</string>
<string name="wallet_settings_access_code_description">Dieser geheime Code schützt Deine Wallet und wird zum Einloggen und Signieren von Transaktionen verwendet.</string>
<string name="wallet_settings_access_code_title">Zugangscode festlegen/ändern</string>
<string name="wallet_settings_change_access_code_title">Zugangscode ändern</string>
<string name="wallet_settings_push_notifications_description">Bleib stets über eingehende Wallet-Transaktionen und Tangem-Updates auf dem Laufenden.</string>
@ -1648,7 +1780,7 @@
<string name="wc_no_wallet_changes_detected">Keine Wallet-Änderungen erkannt</string>
<string name="wc_notification_security_risk_subtitle">Es wurden potenzielle Risiken oder bösartiges Verhalten erkannt. Das Verbinden oder Signieren von Transaktionen kann zum Verlust von Geldern führen.</string>
<string name="wc_notification_security_risk_title">Bekanntes Sicherheitsrisiko</string>
<string name="wc_qr_scan_hint">Öffne die Web3-App und wähle die Option WalletConnect</string>
<string name="wc_qr_scan_hint">Öffne die Web3-App und wähle die Option WalletConnect.</string>
<string name="wc_request_from">Anfrage von</string>
<string name="wc_send_anyway">Trotzdem signieren</string>
<string name="wc_signature_type">Art der Signatur</string>
@ -1663,6 +1795,20 @@
<string name="wc_uri_already_used_title">URI bereits verwendet</string>
<string name="wc_wallet_connect">WalletConnect</string>
<string name="wc_warning_transaction">Verdächtige Transaktion</string>
<string name="welcome_create_wallet_already_have">Besitzt Du bereits eine Tangem Wallet?</string>
<string name="welcome_create_wallet_feature_assets">Tausende von Vermögenswerten</string>
<string name="welcome_create_wallet_feature_class">Erstklassige Hardware-Wallet</string>
<string name="welcome_create_wallet_feature_delivery">Schnelle Lieferung</string>
<string name="welcome_create_wallet_feature_one_tap">Mit einem Fingertipp starten</string>
<string name="welcome_create_wallet_feature_seamless">Nahtlos und sicher</string>
<string name="welcome_create_wallet_feature_use">Einfach zu bedienen</string>
<string name="welcome_create_wallet_hardware_description">Erstelle eine Hardware-Wallet mit Tangem. Schlank wie eine Bankkarte, sicher wie ein Banktresor.</string>
<string name="welcome_create_wallet_mobile_description">Erstelle oder importiere eine Software-Wallet</string>
<string name="welcome_create_wallet_mobile_description_full">Erstelle oder importiere eine Software-Wallet auf Deinem Telefon </string>
<string name="welcome_create_wallet_mobile_title">Beginne mit Mobile Wallet</string>
<string name="welcome_create_wallet_other_method">Andere Methode</string>
<string name="welcome_create_wallet_use_hardware_description">Tangem Hardware Wallet verwenden</string>
<string name="welcome_create_wallet_use_hardware_title">Mehr erfahren &amp; kaufen</string>
<string name="welcome_interrupted_backup_alert_discard">Verwerfen</string>
<string name="welcome_interrupted_backup_alert_message">Du hast eine unterbrochene Sicherung. Möchtest du diese fortsetzen?</string>
<string name="welcome_interrupted_backup_alert_resume">Ja, fortsetzen</string>
@ -1679,7 +1825,7 @@
<string name="xtz_withdrawal_message_warning">Damit Sie beim nächsten Aufladen Ihrer Brieftasche keine erhöhte Provision zahlen, soll der Betrag um %s XTZ reduziert werden</string>
<string name="yield_module_alert_description">Wenn der Yield-Modus aktiviert ist, gehen alle zukünftigen Einzahlungen an diese Adresse an Aave. Du kannst über Dein Guthaben weiterhin frei verfügen.</string>
<string name="yield_module_alert_title">Deine %s wird an Aave übermittelt</string>
<string name="yield_module_amount_not_transfered_to_aave_title">Die Bereitstellung von %1$s %2$s für Aave steht aus</string>
<string name="yield_module_amount_not_transfered_to_aave_title">Die Lieferung von %1$s %2$s an Aave steht noch aus.</string>
<string name="yield_module_approve_needed_notification_cta">Genehmigen</string>
<string name="yield_module_approve_needed_notification_description">Die Genehmigung Deines Tokens wurde widerrufen. Erteilen diese erneut, um die Servicefunktionalität fortzusetzen.</string>
<string name="yield_module_approve_needed_notification_title">Genehmigung erforderlich</string>
@ -1689,14 +1835,14 @@
<string name="yield_module_balance_info_sheet_subtitle">Deine Gelder werden derzeit dem Aave-Protokoll bereitgestellt, Du kannst sie jedoch jederzeit verwalten.</string>
<string name="yield_module_balance_info_sheet_title">Deine%s ist in Aave hinterlegt</string>
<string name="yield_module_chart_loading_error">Chart konnte nicht geladen werden...</string>
<string name="yield_module_deposit_error_notification_title">Der erhaltene Betrag %1$s %2$s wurde nicht auf Aave eingezahlt.</string>
<string name="yield_module_deposit_error_notification_title">Das Bereitstellen von %1$s %2$s bei Aave steht aus.</string>
<string name="yield_module_earn_badge">APY %1$s%%</string>
<string name="yield_module_earn_sheet_available_title">Verfügbar</string>
<string name="yield_module_earn_sheet_current_apy_title">Aktueller effektiver Jahreszins</string>
<string name="yield_module_earn_sheet_fee_description">Beim Aufladen zum Ausleihen wird eine Netzwerkgebühr von maximal %1$s vom Guthaben abgezogen.</string>
<string name="yield_module_earn_sheet_high_fee_description">Die Netzwerkgebühr ist derzeit zu hoch, um die Kreditvergabe durchzuführen. Die Mittel werden bereitgestellt, sobald sie auf %1$s oder darunter fallen. </string>
<string name="yield_module_earn_sheet_high_fee_description">Die Netzwerkgebühr ist derzeit zu hoch für die Kreditvergabe. Die Auszahlung erfolgt, sobald sie auf %1$s oder darunter sinkt.</string>
<string name="yield_module_earn_sheet_my_funds_title">Meine Mittel</string>
<string name="yield_module_earn_sheet_provider_description">Dein %1$s ist nun bei Aave hinterlegt und bringt Zinsen ein. Du besitzt einen %2$s-Token, der Dein Guthaben repräsentiert und mit der Zeit wächst. Wenn Du mehr Geld einzahlst, wird dieses an Aave weitergeleitet, um Zinsen abzüglich einer Transaktionsgebühr zu erwirtschaften.</string>
<string name="yield_module_earn_sheet_provider_description">Deine %1$s sind nun bei Aave angelegt und erwirtschaften Rendite. Du besitzt %2$s -Token, die Dein Guthaben repräsentieren und automatisch Rendite generieren. Bei jeder Aufladung wird Dein Aave-Konto zusätzliches Guthaben gutgeschrieben, um weitere Rendite zu erzielen (abzüglich Gebühren).</string>
<string name="yield_module_earn_sheet_title">Ertragsmodus</string>
<string name="yield_module_earn_sheet_total_earnings_title">Gesamtverdienst</string>
<string name="yield_module_earn_sheet_transfers_title">Übertragungen zu Aave</string>
@ -1704,10 +1850,10 @@
<string name="yield_module_fee_policy_sheet_current_fee_note">Dies ist die aktuelle Liefergebühr auf %s. Die tatsächlichen Kosten werden auf der Registerkarte \"Aktivierung\" angezeigt.</string>
<string name="yield_module_fee_policy_sheet_current_fee_title">Aktuelle Gebühr</string>
<string name="yield_module_fee_policy_sheet_description">Alle zukünftigen %s-Einzahlungen werden automatisch an Aave geliefert, wobei die Transaktionsgebühr abgezogen wird.</string>
<string name="yield_module_fee_policy_sheet_fee_note">Bei jeder zukünftigen Aufladung wird eine Netzwerkgebühr von ungefähr %1$s (%2$s) abgezogen, die Ihr Limit von %3$s (%4$s) nicht überschreitet.</string>
<string name="yield_module_fee_policy_sheet_fee_note">Von jeder zukünftigen Aufladung wird eine ungefähre Netzwerkgebühr von %1$s ( %2$s ) abgezogen, die Dein Limit von %3$s ( %4$s ) nicht überschreiten wird.</string>
<string name="yield_module_fee_policy_sheet_max_fee_note">Wenn die Netzwerkgebühren über die maximale Gebühr steigen, wird die Transaktion erst durchgeführt, wenn diese sinken. Du kannst dieses Limit später ändern.</string>
<string name="yield_module_fee_policy_sheet_max_fee_title">Maximale Gebühr</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">Der Mindestbetrag wird aus der aktuellen Netzwerkgebühr berechnet, um sicherzustellen, dass er 4%% nicht überschreitet, was den Mindestbetrag %1$s (%2$s) ergibt.</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">Der Mindestbetrag wird auf Grundlage der aktuellen Netzwerkgebühr berechnet, sodass er 4%% des Aufladebetrags nicht überschreitet, was einen Mindestbetrag von %1$s (%2$s) ergibt.</string>
<string name="yield_module_fee_policy_sheet_min_amount_title">Mindestaufladung</string>
<string name="yield_module_fee_policy_sheet_title">Gebührenpolitik</string>
<string name="yield_module_fee_policy_tangem_service_fee_title">Tangem erhebt außerdem eine Servicegebühr von 15% auf den erzielten Ertrag.</string>
@ -1722,7 +1868,7 @@
<string name="yield_module_promo_screen_cash_out_subtitle">Senden, tauschen oder verkaufen Deine Gelder sofort, wann immer Du willst.</string>
<string name="yield_module_promo_screen_cash_out_title">Jederzeit Zugriff auf Dein Geld</string>
<string name="yield_module_promo_screen_how_it_works_button_title">Wie funktioniert das?</string>
<string name="yield_module_promo_screen_self_custodial_subtitle">Aave ist ein dezentrales Protokoll, das einen Gesamtwert von über 61 Milliarden US-Dollar verwaltet.</string>
<string name="yield_module_promo_screen_self_custodial_subtitle">Aave ist ein dezentrales Protokoll, das ein Gesamtvermögen von über 61 Milliarden Dollar verwaltet.</string>
<string name="yield_module_promo_screen_self_custodial_title">Dezentral und selbstverwahrend</string>
<string name="yield_module_promo_screen_terms_disclaimer">Durch die Nutzung dieses Dienstes erklärst Du Dich mit provider\n%1$s und %2$s einverstanden</string>
<string name="yield_module_promo_screen_title">Mit Aave verbinden</string>
@ -1734,25 +1880,28 @@
<string name="yield_module_rate_info_sheet_powered_by">Unterstützt durch</string>
<string name="yield_module_rate_info_sheet_title">Der Zinssatz ist variabel</string>
<string name="yield_module_receive_sheet_description">Wenn Du dein Guthaben auflädst, wird es automatisch an Aave weitergeleitet, um Zinsen zu verdienen. zur Deckung der Transaktionsgebühr wird ein Betrag von %s abgezogen.</string>
<string name="yield_module_start_earning">Beginn des Verdienstes</string>
<string name="yield_module_start_earning">Vermögenswerte liefern</string>
<string name="yield_module_start_earning_sheet_description">Dein %s wird an Aave übermittelt, bleibt aber verwaltbar.</string>
<string name="yield_module_start_earning_sheet_fee_policy">Siehe Gebührenrichtlinie</string>
<string name="yield_module_start_earning_sheet_next_deposits">Deine nächste Aufladung wird automatisch an Aave weitergeleitet.</string>
<string name="yield_module_status_active">Aktiv</string>
<string name="yield_module_status_paused">Pausiert</string>
<string name="yield_module_stop_earning">Deaktiviere den Yield-Modus</string>
<string name="yield_module_stop_earning_sheet_description">Wenn Du diese Option deaktivierst, wird Dein Geld von Aave auf %s in Deiner Wallet abgehoben und es werden keine Belohnungen mehr verdient.</string>
<string name="yield_module_stop_earning_sheet_description">Wenn Du diese Option deaktivierst, werden Deine Vermögenswerte von Aave abgezogen, in Deiner Wallet wieder in %s umgewandelt und die Zinsgutschrift gestoppt.</string>
<string name="yield_module_stop_earning_sheet_fee_note">Die Netzwerkgebühr wird von dem Betrag, den Du abhebst, abgezogen.</string>
<string name="yield_module_stop_earning_sheet_title">Deaktiviere den Yield-Modus</string>
<string name="yield_module_supply">Angebot</string>
<string name="yield_module_supply_apr">Effektiver Jahreszins für Versorgung</string>
<string name="yield_module_token_details_earn_notification_apy">Effektiver Jahreszins</string>
<string name="yield_module_token_details_earn_notification_description">Zinsen fallen automatisch an</string>
<string name="yield_module_token_details_earn_notification_description">Die Zinsen fallen automatisch an.</string>
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_subtitle">Zinsen fallen automatisch an</string>
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">Ertragsmodus</string>
<string name="yield_module_token_details_earn_notification_processing">Bearbeitung Deiner Einzahlung</string>
<string name="yield_module_token_details_earn_notification_title">Ertragsmodus</string>
<string name="yield_module_transfer_mode_automatic">Automatisch</string>
<string name="yield_module_unable_to_cover_fee_description">Einzahlung von %1$s %2$s zur Deckung der Netzwerkgebühr für Transaktionen</string>
<string name="yield_module_unable_to_cover_fee_title">Die Gebühr %s kann nicht gedeckt werden</string>
<string name="yield_module_unavailable_subtitle">Der Stakingservice ist derzeit nicht verfügbar. Bitte versuche es später erneut.</string>
<string name="yield_module_unavailable_title">Einnahmen nicht verfügbar</string>
<string name="yield_module_unavailable_subtitle">Der Yield-Modus ist momentan nicht verfügbar. Bitte versuche es später erneut.</string>
<string name="yield_module_unavailable_title">Ausweichmodus nicht verfügbar</string>
<string name="yield_supply_chart_loading_error">Chart konnte nicht geladen werden...</string>
</resources>

View file

@ -194,6 +194,7 @@
<string name="common_fee_selector_title">Velocidad y tarifa</string>
<string name="common_finish">Finalizar</string>
<string name="common_generate_addresses">Sincronizar direcciones</string>
<string name="common_get_started">Comenzar</string>
<string name="common_go_to_provider">Ir al proveedor</string>
<string name="common_go_to_token">Ir al token</string>
<string name="common_got_it">Entendido</string>
@ -396,6 +397,7 @@
<string name="express_provider">Proveedor</string>
<string name="express_provider_best_rate">Mejor tarifa</string>
<string name="express_provider_fca_warning_list">Lista de advertencias de la FCA</string>
<string name="express_provider_great_rate">Mejor opción</string>
<string name="express_provider_in_fca_warning_list">Proveedor en la lista de advertencias de la FCA</string>
<string name="express_provider_max_amount">Disponible hasta %s</string>
<string name="express_provider_min_amount">Disponible desde %s</string>
@ -780,6 +782,7 @@
<string name="organize_tokens_sort_by_balance">Por saldo</string>
<string name="organize_tokens_title">Organizar tokens</string>
<string name="organize_tokens_ungroup">Desagrupar</string>
<string name="provider_name_support">Soporte de %s</string>
<string name="push_notifications_more_info">Más información</string>
<string name="push_notifications_permission_alert_description">Puede activar las Notificaciones para Tangem en Ajustes.</string>
<string name="push_notifications_permission_alert_negative_button">Activar más tarde</string>
@ -973,6 +976,7 @@
<string name="settings_forget_wallet_footer">Esto eliminará la wallet de la aplicación. La wallet en sí puede\nañadirse de nuevo.</string>
<string name="settings_wallet_name_title">Nombre</string>
<string name="stake_token_description">Haga que su token trabaje para Ud.</string>
<string name="staking_account_initialization_message">Para comenzar a hacer staking, debe activar su cuenta TON con una auto-transacción de 1 TON. Los fondos permanecerán en su billetera; este paso solo es necesario para habilitar su cuenta para staking.</string>
<string name="staking_amount_requirement_error">La cantidad del staking debe ser al menos %s</string>
<string name="staking_amount_tron_integer_error">La cantidad de staking se redondeará a %1$s TRX debido a las reglas de la red.</string>
<string name="staking_amount_tron_integer_error_unstaking">La cantidad de unstaking se redondeará a %1$s TRX debido a las reglas de la red.</string>
@ -981,6 +985,7 @@
<string name="staking_details_account_fee_info">Una cuenta de staking es una cuenta especial donde se almacenan los tokens SOL de staking. Se crea cuando delegas sus tokens a un validador para participar en la validación de transacciones y ganar recompensas. Se cobra una pequeña tarifa por crear la cuenta de staking, que se devuelve una vez que se completa el staking.</string>
<string name="staking_details_annual_percentage_rate">Porcentaje de rendimiento anual</string>
<string name="staking_details_annual_percentage_rate_info">El porcentaje de rendimiento anual que podrá ganar como participante en el staking.</string>
<string name="staking_details_annual_percentage_yield_info">APY muestra el porcentaje de rendimiento anual del validador en función de su rendimiento</string>
<string name="staking_details_apr">APR</string>
<string name="staking_details_apy">APY</string>
<string name="staking_details_auto_claiming_rewards_daily_text">Las recompensas se acumulan automáticamente en su saldo de staking diariamente.</string>
@ -1037,6 +1042,7 @@
<string name="staking_notification_restake_rewards_text">Reinvierta las recompensas obtenidas en el monto apostado, aumentando las ganancias potenciales.</string>
<string name="staking_notification_restake_text">La opción de volver a staking le permite mover sus fondos de un validador a otro sin necesidad de retirarlos.</string>
<string name="staking_notification_stake_entire_balance_text">Está a punto de hacer staking con todo su saldo. Recomendamos dejar una pequeña cantidad para cubrir las tarifas de red para hacer unstaking o reclamar recompensas.</string>
<string name="staking_notification_ton_account_initialization_message">Para empezar a hacer staking, primero debes activar tu cuenta de TON.</string>
<string name="staking_notification_ton_activate_account">Para empezar a hacer staking en TON, realice primero una transacción de salida de cualquier importe - esto activará su billetera.</string>
<string name="staking_notification_ton_extra_reserve_info">Es posible que se requieran hasta 0.2 TON además de la tarifa de red para completar la transacción. Cualquier cantidad no utilizada será reembolsada.</string>
<string name="staking_notification_ton_extra_reserve_is_required">Se requieren 0.2 TON para realizar esta operación, además de la tarifa de red. Por favor, recargue su saldo.</string>
@ -1156,6 +1162,7 @@
<string name="token_button_unavailability_reason_pending_transaction_send">El envío de fondos estará disponible una vez que se complete(n) la(s) transacción(es) pendiente(s) en la red %s</string>
<string name="token_button_unavailability_reason_sell_unavailable">Vender %s no es compatible con los proveedores actuales, pero estamos trabajando para agregar más opciones.</string>
<string name="token_button_unavailability_reason_staking_unavailable">El staking de %s no es compatible con los proveedores actuales, pero estamos trabajando para agregar más opciones.</string>
<string name="token_button_unavailability_reason_yield_supply_approval">Se ha revocado la aprobación. Sus fondos permanecen en modo de rendimiento. Para realizar acciones, vuelva al modo de rendimiento y otorgue el permiso nuevamente.</string>
<string name="token_details_generate_xpub">Generar XPUB</string>
<string name="token_details_hide_alert_hide">Ocultar</string>
<string name="token_details_hide_alert_message">Está a punto de ocultar este token de la pantalla principal. Puede volver a agregarlo en cualquier momento a través de la página de gestión de tokens.</string>
@ -1490,7 +1497,7 @@
<string name="yield_module_balance_info_sheet_subtitle">Sus fondos se suministran actualmente al protocolo Aave, pero puede gestionarlos en cualquier momento.</string>
<string name="yield_module_balance_info_sheet_title">Su %s está depositado en Aave</string>
<string name="yield_module_chart_loading_error">No se puede cargar el gráfico...</string>
<string name="yield_module_deposit_error_notification_title">La cantidad recibida, %1$s %2$s no fue suministrada a Aave.</string>
<string name="yield_module_deposit_error_notification_title">El suministro de %1$s %2$s a Aave está pendiente.</string>
<string name="yield_module_earn_badge">APY %1$s%%</string>
<string name="yield_module_earn_sheet_available_title">Disponible</string>
<string name="yield_module_earn_sheet_current_apy_title">APY actual</string>
@ -1508,7 +1515,7 @@
<string name="yield_module_fee_policy_sheet_fee_note">Se deducirá una comisión de red aproximada de %1$s (%2$s) de cada recarga futura, y no superará su límite de %3$s (%4$s).</string>
<string name="yield_module_fee_policy_sheet_max_fee_note">Si las tarifas de red superan la tarifa máxima, la transacción no se realizará hasta que disminuyan. Puede cambiar este límite más adelante.</string>
<string name="yield_module_fee_policy_sheet_max_fee_title">Tarifa máxima</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">El monto mínimo se calcula a partir de la tarifa de red actual para garantizar que no exceda 4%%, lo que hace que el mínimo sea %1$s (%2$s).</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">El monto mínimo se calcula en función de la comisión de la red actual para que no supere el 4%% del importe de la recarga, lo que hace que el mínimo sea %1$s (%2$s).</string>
<string name="yield_module_fee_policy_sheet_min_amount_title">Recarga mínima</string>
<string name="yield_module_fee_policy_sheet_title">Política de tarifas</string>
<string name="yield_module_fee_policy_tangem_service_fee_title">Tangem también cobra una comisión de servicio del 15% sobre el rendimiento obtenido.</string>
@ -1541,9 +1548,11 @@
<string name="yield_module_start_earning_sheet_next_deposits">Sus próximas recargas se suministrarán automáticamente a Aave.</string>
<string name="yield_module_status_active">Activo</string>
<string name="yield_module_status_paused">En pausa</string>
<string name="yield_module_stop_earning">Desactivar el modo de rendimiento</string>
<string name="yield_module_stop_earning">Desactivación del modo de rendimiento</string>
<string name="yield_module_stop_earning_sheet_description">Al desactivar esto, retirará sus fondos de Aave a %s en su billetera y dejará de ganar recompensas.</string>
<string name="yield_module_stop_earning_sheet_fee_note">La comisión de red se deducirá del importe que retire.</string>
<string name="yield_module_stop_earning_sheet_title">Desactivar el modo de rendimiento</string>
<string name="yield_module_supply">Suministrar</string>
<string name="yield_module_supply_apr">Suministro APY</string>
<string name="yield_module_token_details_earn_notification_apy">APY</string>
<string name="yield_module_token_details_earn_notification_description">Los intereses se devengan automáticamente</string>
@ -1555,5 +1564,6 @@
<string name="yield_module_unable_to_cover_fee_description">Deposite algo de %1$s %2$s para cubrir la tarifa de red para las transacciones</string>
<string name="yield_module_unable_to_cover_fee_title">No se puede cubrir la tarifa %s</string>
<string name="yield_module_unavailable_subtitle">El servicio de intereses no está disponible en este momento. Vuelva a intentarlo más tarde.</string>
<string name="yield_module_unavailable_title">Ganancias no disponibles</string>
<string name="yield_module_unavailable_title">Modo de rendimiento no disponible</string>
<string name="yield_supply_chart_loading_error">No se puede cargar el gráfico...</string>
</resources>

View file

@ -172,6 +172,7 @@
<string name="common_fee_selector_title">Vitesse et frais</string>
<string name="common_finish">Terminer</string>
<string name="common_generate_addresses">Synchroniser les adresses</string>
<string name="common_get_started">Commencer</string>
<string name="common_go_to_provider">Aller au fournisseur</string>
<string name="common_go_to_token">Aller au jeton</string>
<string name="common_got_it">Compris</string>
@ -372,6 +373,7 @@
<string name="express_provider">Fournisseur</string>
<string name="express_provider_best_rate">Meilleur taux</string>
<string name="express_provider_fca_warning_list">Liste davertissement de la FCA</string>
<string name="express_provider_great_rate">Meilleur choix</string>
<string name="express_provider_max_amount">Disponible jusqu\'à %s</string>
<string name="express_provider_min_amount">Disponible à partir de %s</string>
<string name="express_provider_not_available">Indisponible pour cette paire</string>
@ -753,6 +755,7 @@
<string name="organize_tokens_sort_by_balance">Par solde</string>
<string name="organize_tokens_title">Organiser les jetons</string>
<string name="organize_tokens_ungroup">Dégrouper</string>
<string name="provider_name_support">Assistance %s</string>
<string name="push_notifications_more_info">Plus d\'infos</string>
<string name="push_notifications_permission_alert_description">Vous pouvez activer les notifications pour Tangem dans les paramètres.</string>
<string name="push_notifications_permission_alert_negative_button">Activer plus tard</string>
@ -947,6 +950,7 @@
<string name="settings_forget_wallet_footer">Cela supprimera le portefeuille de l\'application. Le portefeuille lui-même peut être ajouté à nouveau.</string>
<string name="settings_wallet_name_title">Nom</string>
<string name="stake_token_description">Faites travailler votre jeton pour vous</string>
<string name="staking_account_initialization_message">Pour commencer à staker, votre compte TON doit être activé avec une transaction de 1 TON. Les fonds restent sur votre compte, car cette étape sert uniquement à l\'activer pour le staking.</string>
<string name="staking_amount_requirement_error">Le montant à staker doit être au moins %s</string>
<string name="staking_amount_tron_integer_error">Le montant du staking sera arrondi à %1$s TRX en raison des règles du réseau.</string>
<string name="staking_amount_tron_integer_error_unstaking">Le montant d\'annulation du staking sera arrondi à %1$s TRX en raison des règles du réseau.</string>
@ -1011,6 +1015,7 @@
<string name="staking_notification_restake_rewards_text">Réinvestissez vos récompenses gagnées dans le montant que vous avez staké, augmentant ainsi vos gains potentiels.</string>
<string name="staking_notification_restake_text">L\'option de restaker vous permet de déplacer vos fonds d\'un validateur à un autre sans avoir besoin de les déstaker.</string>
<string name="staking_notification_stake_entire_balance_text">Vous êtes sur le point de staker l\'intégralité de votre solde. Nous vous recommandons de laisser un petit montant pour couvrir les frais de réseau pour unstaking ou la réclamation des récompenses.</string>
<string name="staking_notification_ton_account_initialization_message">Pour commencer le staking, vous devez dabord activer votre compte TON</string>
<string name="staking_notification_ton_activate_account">Pour commencer à staker TON, effectuez d\'abord une transaction sortante de n\'importe quel montant — cela activera votre portefeuille.</string>
<string name="staking_notification_ton_extra_reserve_info">Jusqu\'à 0,2 TON peuvent être requis en plus des frais de réseau pour terminer la transaction. Tout montant non utilisé sera remboursé.</string>
<string name="staking_notification_ton_extra_reserve_is_required">0,2 TON requis pour effectuer cette opération, en plus des frais de réseau. Veuillez recharger votre solde.</string>
@ -1469,7 +1474,7 @@
<string name="yield_module_balance_info_sheet_subtitle">Vos fonds sont actuellement affectés au protocole Aave, mais vous pouvez les gérer à tout moment.</string>
<string name="yield_module_balance_info_sheet_title">Vos %s sont déposés dans Aave.</string>
<string name="yield_module_chart_loading_error">Impossible de charger le graphique...</string>
<string name="yield_module_deposit_error_notification_title">Le montant reçu, %1$s %2$s, n\'a pas été fourni à Aave.</string>
<string name="yield_module_deposit_error_notification_title">Lapprovisionnement de %1$s %2$s sur Aave est en attente.</string>
<string name="yield_module_earn_badge">APY %1$s%%</string>
<string name="yield_module_earn_sheet_available_title">Disponible</string>
<string name="yield_module_earn_sheet_current_apy_title">APY actuel</string>
@ -1487,7 +1492,7 @@
<string name="yield_module_fee_policy_sheet_fee_note">Des frais de réseau d\'environ %1$s (%2$s) seront déduits de chaque recharge future, sans dépasser votre limite de %3$s (%4$s).</string>
<string name="yield_module_fee_policy_sheet_max_fee_note">Si les frais de réseau dépassent le montant maximal, la transaction ne sera pas effectuée tant qu\'ils n\'auront pas diminué. Vous pouvez modifier cette limite ultérieurement.</string>
<string name="yield_module_fee_policy_sheet_max_fee_title">Frais maximaux</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">Le montant minimum est calculé à partir des frais de réseau actuels afin de garantir qu\'il ne dépasse pas 4 %%, ce qui donne un minimum de %1$s (%2$s).</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">Le montant minimum est calculé en fonction des frais réseau actuels afin de ne pas dépasser 4%% du montant du rechargement, ce qui donne un minimum de %1$s (%2$s).</string>
<string name="yield_module_fee_policy_sheet_min_amount_title">Recharge minimale</string>
<string name="yield_module_fee_policy_sheet_title">Politique tarifaire</string>
<string name="yield_module_fee_policy_tangem_service_fee_title">Tangem prélève également des frais de service de 15% sur les revenus générés.</string>
@ -1520,9 +1525,10 @@
<string name="yield_module_start_earning_sheet_next_deposits">Vos prochains dépôts seront automatiquement transférés vers Aave.</string>
<string name="yield_module_status_active">Actif</string>
<string name="yield_module_status_paused">En pause</string>
<string name="yield_module_stop_earning">Désactiver le mode rendement</string>
<string name="yield_module_stop_earning">Désactivation du mode de rendement</string>
<string name="yield_module_stop_earning_sheet_description">En désactivant cela, vos fonds seront retirés d\'Aave vers %s dans votre portefeuille et vous ne gagnerez plus de récompenses.</string>
<string name="yield_module_stop_earning_sheet_fee_note">Les frais de réseau seront déduits du montant que vous retirez.</string>
<string name="yield_module_stop_earning_sheet_title">Désactiver le mode rendement</string>
<string name="yield_module_supply_apr">Rendement annuel brut (APY)</string>
<string name="yield_module_token_details_earn_notification_apy">APY</string>
<string name="yield_module_token_details_earn_notification_description">Les intérêts sont cumulés automatiquement.</string>

View file

@ -488,7 +488,7 @@
<string name="express_provider">プロバイダー</string>
<string name="express_provider_best_rate">ベストレート</string>
<string name="express_provider_fca_warning_list">FCA警告リスト</string>
<string name="express_provider_great_rate">ベストチョイス</string>
<string name="express_provider_great_rate">最適な選択</string>
<string name="express_provider_in_fca_warning_list">FCA警告リストに掲載されたプロバイダー</string>
<string name="express_provider_max_amount">最大 %s まで使用可能</string>
<string name="express_provider_min_amount">%s 以上で利用可能</string>
@ -531,6 +531,13 @@
<string name="give_permission_swap_subtitle" formatted="false">続行するには、%1sスマートコントラクトに%2sを使用する権限を付与してください</string>
<string name="give_permission_title">許可を与える</string>
<string name="give_permission_unlimited">無制限</string>
<string name="hardware_wallet_backup_feature_description">バックアップは2枚または3枚のTangemカードを使って作成されます。紛失や破損に備えて、それぞれ別々の安全な場所に保管してください—シードフレーズは不要です。</string>
<string name="hardware_wallet_backup_feature_title">複数のカードでバックアップ</string>
<string name="hardware_wallet_create_title">Tangemウォレットを追加</string>
<string name="hardware_wallet_key_feature_description">あなたの秘密鍵はTangemカード内部で直接生成され、決してカードの外に出ることはありません。</string>
<string name="hardware_wallet_key_feature_title">鍵生成</string>
<string name="hardware_wallet_security_feature_description">すべての暗号処理は、複製や物理的な改ざんに対する認証を受けたセキュアチップ内で行われます。</string>
<string name="hardware_wallet_security_feature_title">ハードウェアレベルのセキュリティ</string>
<string name="home_button_add_existing_wallet">既存のウォレットを追加</string>
<string name="home_button_create_new_wallet">新しいウォレットを作成する</string>
<string name="home_button_order">Tangemを注文</string>
@ -569,6 +576,21 @@
<string name="hw_import_existing_wallet">既存のウォレットをインポートする</string>
<string name="hw_import_seed_phrase_already_imported">このリカバリーフレーズはすでにインポートされています。</string>
<string name="hw_mobile_wallet">モバイルウォレット</string>
<string name="hw_remove_wallet_action_forget_title">ウォレット削除</string>
<string name="hw_remove_wallet_attention_description">このウォレットはデバイスから完全に削除されます。</string>
<string name="hw_remove_wallet_confirmation_title">本当にこれを実行しますか?</string>
<string name="hw_remove_wallet_nav_title">ウォレット削除</string>
<string name="hw_remove_wallet_notification_action_backup_go">バックアップへ移動</string>
<string name="hw_remove_wallet_notification_action_backup_view">バックアップを表示</string>
<string name="hw_remove_wallet_notification_action_forget">ウォレット削除</string>
<string name="hw_remove_wallet_notification_action_forget_anyway">とにかく削除する</string>
<string name="hw_remove_wallet_notification_description_has_backup">このウォレットにはバックアップが存在します。後で復元できるように、削除する前に内容を確認してください。</string>
<string name="hw_remove_wallet_notification_description_without_backup">バックアップなしでこのウォレットを削除すると、資金へのアクセスを永久に失います。</string>
<string name="hw_remove_wallet_notification_title">このウォレットを削除しますか?</string>
<string name="hw_remove_wallet_warning_access">ウォレットの削除前にバックアップをしていなければ、アクセスを失う可能性があることを理解しています。</string>
<string name="hw_remove_wallet_warning_device">ウォレットを削除しても中身自体が消えるわけではなく、単にこのデバイスから表示が消えるだけであることを理解しています。</string>
<string name="hw_upgrade_backup_description">もはやシードフレーズは不要——Tangemカードやリングがそのままあなたの安全なバックアップになります。</string>
<string name="hw_upgrade_backup_title">Tangemでバックアップ</string>
<string name="hw_upgrade_error_card_already_has_wallet">アップグレードできません。このデバイスにはすでにウォレットが存在します。</string>
<string name="hw_upgrade_error_card_key_import">別のデバイスを選択してください。このデバイスはアップグレードに使用できません。</string>
<string name="hw_upgrade_error_wallet2_card_required">操作中にエラーが発生しました。</string>
@ -1203,7 +1225,7 @@
<string name="staking_notification_restake_rewards_text">獲得した報酬をステーキングに再投資し、潜在的な収益を増やします。</string>
<string name="staking_notification_restake_text">再ステーキングを使うと、ステーキングを解除することなく、あるバリデータから別のバリデータに資金を移動できます。</string>
<string name="staking_notification_stake_entire_balance_text">ウォレットの残高をすべてステーキングすると、ステーキング解除時にネットワーク手数料の支払いが必要になります。そのため、少額をウォレットに残しておくことをおすすめします。</string>
<string name="staking_notification_ton_account_initialization_message">ステーキングを始めるには、TONアカウントを1 TONの自己取引で有効化する必要があります。資金はウォレット内にそのまま残り、この手順でステーキング用にアカウントを有効化できます</string>
<string name="staking_notification_ton_account_initialization_message">ステーキングを開始するには、まずTONアカウントを有効化してください</string>
<string name="staking_notification_ton_account_initialization_title">アカウントの有効化</string>
<string name="staking_notification_ton_activate_account">TONのステーキングを開始するには、まず自分のアドレスに少額の取引を送信します。これによりウォレットが有効になります。</string>
<string name="staking_notification_ton_extra_reserve_info">取引を完了するには、ネットワーク手数料に加えて最大0.2TONが必要になる場合があります。未使用分は返金されます。</string>
@ -1315,6 +1337,9 @@
<string name="tangem_pay_explore_transaction">取引を表示</string>
<string name="tangem_pay_fee_subtitle">サービス手数料</string>
<string name="tangem_pay_fee_title">手数料</string>
<string name="tangem_pay_freeze_card_alert_body">カードを紛失したり盗まれたりしても、資金を安全に保てます。一時停止はいつでも解除できます。</string>
<string name="tangem_pay_freeze_card_alert_title">カードを一時停止しますか?</string>
<string name="tangem_pay_freeze_card_freeze">一時停止</string>
<string name="tangem_pay_get_help">サポートを受ける</string>
<string name="tangem_pay_status_completed">完了</string>
<string name="tangem_pay_status_declined">拒否</string>
@ -1322,6 +1347,8 @@
<string name="tangem_pay_transaction_declined_notification_text">銀行がこの取引リクエストを拒否しました。</string>
<string name="tangem_pay_transaction_fee_notification_text">この手数料は、送金処理にかかるコストをカバーするためのものです。</string>
<string name="tangem_pay_withdrawal">出金</string>
<string name="tangempay_card_details_add_funds">資金を追加</string>
<string name="tangempay_card_details_add_funds_subtitle">入金オプション</string>
<string name="tangempay_card_details_change_pin">PINを変更する</string>
<string name="tangempay_card_details_change_pin_success_description">カードは支払いの準備が整いました。</string>
<string name="tangempay_card_details_change_pin_success_title">PINコードを作成しました</string>
@ -1337,9 +1364,11 @@
<string name="tangempay_card_details_open_wallet_step_4">お使いの端末に送信されたワンタイムパスワードOTPでカードを認証してください。</string>
<string name="tangempay_card_details_open_wallet_step_5">準備完了!カードはすぐに使用できます。</string>
<string name="tangempay_card_details_open_wallet_title">Google Payにカードを追加する</string>
<string name="tangempay_card_details_receive_description">アドレスを共有するか、QRコードを表示してください。</string>
<string name="tangempay_card_details_receive_error_description">技術的な問題が検出されました。しばらくしてからもう一度お試しいただくか、サポートにお問い合わせください。</string>
<string name="tangempay_card_details_receive_error_title">現在、受け取りは利用できません</string>
<string name="tangempay_card_details_reveal_text">表示</string>
<string name="tangempay_card_details_swap_description">ポートフォリオ内のあらゆる資産をカードと交換</string>
<string name="tangempay_card_details_title">カードの詳細</string>
<string name="tangempay_issue_card_notification_title">アカウントを作成してカードを発行</string>
<string name="tangempay_kyc_card_ready_notification_title">Tangem Pay</string>
@ -1776,7 +1805,7 @@
<string name="yield_module_balance_info_sheet_subtitle">あなたの資金は現在Aaveプロトコルに預けられていますが、いつでも自由に管理できます。</string>
<string name="yield_module_balance_info_sheet_title">あなたの%sはAaveに預けられています</string>
<string name="yield_module_chart_loading_error">チャートを読み込めません・・</string>
<string name="yield_module_deposit_error_notification_title">受け取った金額%1$s %2$sはAaveに入金されませんでした</string>
<string name="yield_module_deposit_error_notification_title">Aaveへの%1$s %2$sの供給は保留中です</string>
<string name="yield_module_earn_badge">年利%1$s%%</string>
<string name="yield_module_earn_sheet_available_title">利用可能</string>
<string name="yield_module_earn_sheet_current_apy_title">現在のAPY</string>
@ -1794,7 +1823,7 @@
<string name="yield_module_fee_policy_sheet_fee_note">今後のチャージごとに、おおよそ%1$s%2$sのネットワーク手数料が差し引かれますが、上限の%3$s%4$sを超えることはありません。</string>
<string name="yield_module_fee_policy_sheet_max_fee_note">ネットワーク手数料が上限手数料を超えた場合、手数料が下がるまで取引は成立しません。この制限は後で変更できます。</string>
<string name="yield_module_fee_policy_sheet_max_fee_title">最大手数料</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">最小金額は現在のネットワーク手数料に基づいて計算されており、手数料が4を超えないように設定されています。そのため、最小金額は%1$s%2$sとなります。</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">最小金額は、ネットワーク手数料がチャージ額の4を超えないように現在の手数料に基づいて計算されます。その結果、最小金額は%1$s%2$sとなります。</string>
<string name="yield_module_fee_policy_sheet_min_amount_title">最低入金額</string>
<string name="yield_module_fee_policy_sheet_title">手数料ポリシー</string>
<string name="yield_module_fee_policy_tangem_service_fee_title">Tangemはまた、得られた利回りに対して15%のサービス手数料を差し引きます。</string>
@ -1830,10 +1859,11 @@
<string name="yield_module_stop_earning">利回りモードを無効にする</string>
<string name="yield_module_stop_earning_sheet_description">これをオフにすると、Aaveから資産が引き出され、ウォレット内の%sに変換され、利回りの発生が停止します。</string>
<string name="yield_module_stop_earning_sheet_fee_note">出金金額からネットワーク手数料が差し引かれます。</string>
<string name="yield_module_stop_earning_sheet_title">利回りモードを無効にする</string>
<string name="yield_module_supply">供給</string>
<string name="yield_module_supply_apr">供給APY</string>
<string name="yield_module_token_details_earn_notification_apy">APY</string>
<string name="yield_module_token_details_earn_notification_description">利息は自動的に発生します</string>
<string name="yield_module_token_details_earn_notification_description">利息は自動的に発生します</string>
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_subtitle">利息は自動的に発生します</string>
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">利回りモード</string>
<string name="yield_module_token_details_earn_notification_processing">入金の処理中</string>

View file

@ -5,6 +5,7 @@
<string name="account_archived_recover_error_title">Невозможно восстановить аккаунт</string>
<string name="account_details_archive_action">Архив</string>
<string name="account_details_archive_description">Вы архивируете свой аккаунт, но в любое время можете вернуть его обратно</string>
<string name="account_details_archiving">Архивация...</string>
<string name="account_form_name_already_exist_error_description">Имя аккаунта уже существует</string>
<string name="account_form_placeholder_edit_account">Аккаунт</string>
<string name="account_form_placeholder_new_account">Новый аккаунт</string>
@ -96,6 +97,9 @@
<item quantity="many">%d устройств</item>
<item quantity="other">%d устройств</item>
</plurals>
<string name="card_reset_alert_continue_message">Пожалуйста, сбросьте следующее устройство, чтобы продолжить.</string>
<string name="card_reset_alert_continue_title">Сброс кошелька</string>
<string name="card_reset_alert_finish_title">Сброс завершен</string>
<string name="card_settings_access_code_recovery_disabled_description">Отключите эту опцию, если не хотите, чтобы эта карта использовалась для сброса кодов доступа на другие карты этого кошелька. Обратите внимание, сброс кода также не будет доступен на этой карте.</string>
<string name="card_settings_access_code_recovery_enabled_description">Использовать эту карту для сброса кода доступа на других картах в этом кошельке</string>
<string name="card_settings_access_code_recovery_title">Восстановление доступа</string>
@ -121,6 +125,7 @@
<string name="cardano_max_amount_has_token_title">Недостаточно ADA</string>
<string name="common_accept">Принять</string>
<string name="common_access_denied">Доступ запрещен</string>
<string name="common_account">Аккаунт</string>
<string name="common_activate">Активировать</string>
<string name="common_add">Добавить</string>
<string name="common_add_to_portfolio">Добавить в портфель</string>
@ -232,6 +237,7 @@
<string name="common_reject">Отклонить</string>
<string name="common_reload">Перезагрузить</string>
<string name="common_rename">Переименовать</string>
<string name="common_reset">Сброс</string>
<string name="common_save">Сохранить</string>
<string name="common_save_changes">Сохранить изменения</string>
<string name="common_search">Поиск</string>
@ -856,6 +862,7 @@
<string name="organize_tokens_sort_by_balance">По балансу</string>
<string name="organize_tokens_title">Упорядочить токены</string>
<string name="organize_tokens_ungroup">Список</string>
<string name="provider_name_support">Поддержка %s</string>
<string name="push_notifications_more_info">Подробнее</string>
<string name="push_notifications_permission_alert_description">Вы можете включить нотификации в настройках</string>
<string name="push_notifications_permission_alert_negative_button">Включить позже</string>
@ -1117,7 +1124,7 @@
<string name="staking_notification_restake_rewards_text">Реинвестируйте свои заработанные награды в вашу застейканную сумму, увеличивая потенциальный доход</string>
<string name="staking_notification_restake_text">Рестейк позволяет вам переместить средства из одного валидатора в другого без необходимости выхода из стейкинга.</string>
<string name="staking_notification_stake_entire_balance_text">Вы собираетесь застейкать весь баланс, рекомендуем оставить небольшую сумму для оплаты комиссии сети при выходе из стейкинга или получении награды.</string>
<string name="staking_notification_ton_account_initialization_message">Чтобы начать стейкинг, ваш TON-аккаунт должен быть активирован транзакцией самому себе на 1 TON. Средства остаются в вашем кошельке — этот шаг лишь активирует ваш аккаунт для участия в стейкинге.</string>
<string name="staking_notification_ton_account_initialization_message">Чтобы начать стейкинг, сначала активируйте свой TON-аккаунт.</string>
<string name="staking_notification_ton_account_initialization_title">Активация аккаунта</string>
<string name="staking_notification_ton_activate_account">Чтобы начать стейкинг в TON, сначала отправьте небольшую транзакцию на свой же адрес — это активирует ваш кошелёк.</string>
<string name="staking_notification_ton_extra_reserve_info">До 0.2 TON может потребоваться сверх сетевой комиссии для завершения транзакции. Неиспользованная часть будет возвращена.</string>
@ -1311,7 +1318,9 @@
<string name="user_wallet_list_rename_popup_title">Переименование кошелька</string>
<string name="user_wallet_list_unlock_all">Разблокировать все</string>
<string name="user_wallet_list_unlock_all_with">Разблокировать все с %s</string>
<string name="visa_onboarding_account_activation_navigation_title">Активация аккаунта</string>
<string name="visa_onboarding_pin_not_accepted">ПИН не принят. Попробуйте ещё раз или введите другой код.</string>
<string name="wallet_add_support_title">Что выбрать?</string>
<string name="wallet_balance_blockchain_unreachable_try_later">Блокчейн недоступен. Попробуйте позже.</string>
<string name="wallet_balance_missing_derivation">Отсканируйте карту или кольцо</string>
<string name="wallet_been_activated_message">Этот кошелек уже был активирован ранее.\nЕсли это сделали не вы, свяжитесь со службой поддержки.\nTangem никогда не продает кошелек вместе с предустановленным кодом доступа.</string>
@ -1577,6 +1586,7 @@
<string name="xtz_withdrawal_message_warning">Чтобы не платить повышенную комиссию при следующем пополнении кошелька, уменьшите сумму на %s XTZ</string>
<string name="yield_module_alert_description">При активном режиме доходности все будущие депозиты на этот адрес будут направляться в Aave. Вы по-прежнему можете свободно управлять своими средствами.</string>
<string name="yield_module_alert_title">Ваш %s внесён в Aave</string>
<string name="yield_module_amount_not_transfered_to_aave_title">Отправка %1$s %2$s в Aave находится в ожидании</string>
<string name="yield_module_approve_needed_notification_cta">Выдать разрешение</string>
<string name="yield_module_approve_needed_notification_description">Разрешение для вашего токена было отозвано. Выдайте его снова, чтобы продолжить работу сервиса.</string>
<string name="yield_module_approve_needed_notification_title">Необходимо разрешение</string>
@ -1586,21 +1596,25 @@
<string name="yield_module_balance_info_sheet_subtitle">Ваши средства в данный момент размещены в протоколе Aave, но вы можете воспользоваться ими в любое время.</string>
<string name="yield_module_balance_info_sheet_title">Ваш %s внесён в Aave</string>
<string name="yield_module_chart_loading_error">Невозможно загрузить график</string>
<string name="yield_module_deposit_error_notification_title">Полученная сумма, %1$s %2$s, не была зачислена на Aave.</string>
<string name="yield_module_deposit_error_notification_title">Отправка %1$s %2$s на Aave ожидает выполнения.</string>
<string name="yield_module_earn_badge">APY %1$s%%</string>
<string name="yield_module_earn_sheet_available_title">Доступно</string>
<string name="yield_module_earn_sheet_current_apy_title">Текущий APY</string>
<string name="yield_module_earn_sheet_fee_description">При пополнении в режиме доходности с баланса будет удержана комиссия сети, не превышающая %1$s.</string>
<string name="yield_module_earn_sheet_high_fee_description">Сейчас комиссия сети слишком высока для выполнения операции. Средства будут отправлены, как только она снизится до %1$s или ниже.</string>
<string name="yield_module_earn_sheet_my_funds_title">Мои средства</string>
<string name="yield_module_earn_sheet_provider_description">Ваши %1$s теперь внесён в Aave и приносит проценты. У вас есть токен %2$s, который отражает ваш баланс и со временем увеличивается. При пополнении средства автоматически направляются в Aave для получения процентов за вычетом комиссии за транзакцию.</string>
<string name="yield_module_earn_sheet_title">Режим доходности</string>
<string name="yield_module_earn_sheet_total_earnings_title">Итоговый доход</string>
<string name="yield_module_earn_sheet_transfers_title">Переводы в Aave</string>
<string name="yield_module_explore_sheet_explore_aave_button_title">Изучите Aave</string>
<string name="yield_module_fee_policy_sheet_current_fee_note">Это текущая комиссия в сети %s.</string>
<string name="yield_module_fee_policy_sheet_current_fee_title">Текущая комиссия</string>
<string name="yield_module_fee_policy_sheet_description">Все следующие пополнения %s автоматически поступят в Aave с удержанием комиссии за транзакцию.</string>
<string name="yield_module_fee_policy_sheet_fee_note">Примерная комиссия сети в размере %1$s (%2$s) будет удерживаться с каждого будущего пополнения и не превысит ваш лимит %3$s (%4$s).</string>
<string name="yield_module_fee_policy_sheet_max_fee_note">Если комиссия сети превысит максимальный лимит, транзакция не будет выполнена до тех пор, пока комиссия не снизится. Вы сможете изменить этот лимит позже.</string>
<string name="yield_module_fee_policy_sheet_max_fee_title">Максимальная комиссия</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">Это минимальный депозит, который можно отправить в Aave. Чтобы депозиты оставались прибыльными, мы не обрабатываем их, когда комиссия сети превышает %1$s%2$sот суммы.</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">Минимальная сумма рассчитывается исходя из текущей комиссии сети, чтобы она не превышала 4%% от суммы пополнения, что составляет минимум %1$s (%2$s).</string>
<string name="yield_module_fee_policy_sheet_min_amount_title">Минимальный депозит</string>
<string name="yield_module_fee_policy_sheet_title">Политика комиссий</string>
<string name="yield_module_fee_policy_tangem_service_fee_title">Tangem взимает комиссию за обслуживание в размере 15% от полученного дохода.</string>
@ -1615,11 +1629,11 @@
<string name="yield_module_promo_screen_cash_out_subtitle">Отправляйте, обменивайте или продавайте свои средства мгновенно, когда захотите.</string>
<string name="yield_module_promo_screen_cash_out_title">Мгновенный вывод средств</string>
<string name="yield_module_promo_screen_how_it_works_button_title">Как это работает?</string>
<string name="yield_module_promo_screen_self_custodial_subtitle">Aave — это децентрализованный протокол, управляющий активами на сумму более 61 миллиарда долларов США.</string>
<string name="yield_module_promo_screen_self_custodial_subtitle">Aave — децентрализованный протокол, управляющий активами на сумму более $61 млрд.</string>
<string name="yield_module_promo_screen_self_custodial_title">Децентрализованный и некастодиальный</string>
<string name="yield_module_promo_screen_terms_disclaimer">Используя сервис, вы соглашаетесь с условиями провайдера %1$s и %2$s</string>
<string name="yield_module_promo_screen_title">Подключить Aave</string>
<string name="yield_module_promo_screen_variable_rate_info">Aave %1$s%%• Ставка с плавающим процентом</string>
<string name="yield_module_promo_screen_variable_rate_info">Aave %1$s%% • Плавающая ставка</string>
<string name="yield_module_provider">Aave</string>
<string name="yield_module_rate_info_sheet_chart_average">Сред. %s</string>
<string name="yield_module_rate_info_sheet_chart_title">Доходность за прошлый год</string>
@ -1636,11 +1650,15 @@
<string name="yield_module_stop_earning">Завершение режима доходности</string>
<string name="yield_module_stop_earning_sheet_description">Выключив эту функцию, вы выведёте средства из Aave, получите их обратно в %s в своем кошельке и перестанете зарабатывать награды.</string>
<string name="yield_module_stop_earning_sheet_fee_note">Комиссия сети будет вычтена из суммы вашего вывода.</string>
<string name="yield_module_stop_earning_sheet_title">Завершить режим доходности</string>
<string name="yield_module_supply">Внесение</string>
<string name="yield_module_supply_apr">Годовая доходность (APY)</string>
<string name="yield_module_token_details_earn_notification_apy">APY</string>
<string name="yield_module_token_details_earn_notification_description">Проценты начисляются автоматически.</string>
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_subtitle">Проценты начисляются автоматически.</string>
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">Режим доходности</string>
<string name="yield_module_token_details_earn_notification_processing">Отправка ваших средств</string>
<string name="yield_module_token_details_earn_notification_title">Режим доходности</string>
<string name="yield_module_transfer_mode_automatic">Автоматически</string>
<string name="yield_module_unable_to_cover_fee_description">Внесите немного %1$s %2$s, чтобы покрыть комиссию сети за транзакции.</string>
<string name="yield_module_unable_to_cover_fee_title">Невозможно покрыть комиссию в %s</string>

View file

@ -172,6 +172,7 @@
<string name="common_fee_selector_title">Швидкість та комісія</string>
<string name="common_finish">Завершити</string>
<string name="common_generate_addresses">Синхронізувати адреси</string>
<string name="common_get_started">Почати</string>
<string name="common_go_to_provider">Перейти до провайдера</string>
<string name="common_go_to_token">Перейти до токену</string>
<string name="common_got_it">Зrozуміло</string>
@ -370,6 +371,7 @@
<string name="express_provider">Провайдер</string>
<string name="express_provider_best_rate">Найкращий курс</string>
<string name="express_provider_fca_warning_list">Список попереджень FCA</string>
<string name="express_provider_great_rate">Найкращий вибір</string>
<string name="express_provider_max_amount">Доступно до %s</string>
<string name="express_provider_min_amount">Доступно від %s</string>
<string name="express_provider_not_available">Недоступно для цієї пари</string>
@ -760,6 +762,7 @@
<string name="organize_tokens_sort_by_balance">За балансом</string>
<string name="organize_tokens_title">Сортування токенів</string>
<string name="organize_tokens_ungroup">Список</string>
<string name="provider_name_support">Підтримка %s</string>
<string name="push_notifications_more_info">Більше</string>
<string name="push_notifications_permission_alert_description">Ви можете ввімкнути сповіщення у налаштуваннях</string>
<string name="push_notifications_permission_alert_negative_button">Увімкнути пізніше</string>
@ -1017,6 +1020,7 @@
<string name="staking_notification_restake_rewards_text">Реінвестуйте зароблені винагороди у суму стейкінгу, щоб збільшити потенційний прибуток.</string>
<string name="staking_notification_restake_text">Рестейк дозволяє вам перемістити ваші кошти від одного валідатора до іншого без необхідності виводити кошти зі стейкінгу</string>
<string name="staking_notification_stake_entire_balance_text">Ви збираєтеся застейкати весь свій баланс. Ми рекомендуємо залишити невелику суму, щоб покрити комісію мережі за зняття коштів або отримання винагороди.</string>
<string name="staking_notification_ton_account_initialization_message">Щоб розпочати стейкінг, спочатку активуйте свій TON-акаунт.</string>
<string name="staking_notification_ton_activate_account">Щоб почати стейкінг в TON, спочатку здійсніть вихідну транзакцію на будь-яку суму — це активує ваш гаманець.</string>
<string name="staking_notification_ton_extra_reserve_info">До 0.2 TON може знадобитися додатково мережевої комісії для завершення транзакції. Невикористана частина буде повернута.</string>
<string name="staking_notification_ton_extra_reserve_is_required">Для виконання операції потребується додатково 0.2 TON, крім мережевої комісії. Будь ласка, поповніть баланс.</string>
@ -1446,7 +1450,7 @@
<string name="yield_module_balance_info_sheet_subtitle">Наразі ваші кошти розміщені у протоколі Aave, але ви можете керувати ними в будь-який час.</string>
<string name="yield_module_balance_info_sheet_title">Ваш %s внесений у Aave</string>
<string name="yield_module_chart_loading_error">Неможливо завантажити графік</string>
<string name="yield_module_deposit_error_notification_title">Отримана сума, %1$s %2$s не була зарахована на Aave.</string>
<string name="yield_module_deposit_error_notification_title">Поповнення %1$s %2$s на Aave очікує виконання.</string>
<string name="yield_module_earn_badge">APY %1$s%%</string>
<string name="yield_module_earn_sheet_available_title">Доступно</string>
<string name="yield_module_earn_sheet_current_apy_title">Поточний APY</string>
@ -1464,7 +1468,7 @@
<string name="yield_module_fee_policy_sheet_fee_note">Приблизна мережева плата в розмірі %1$s (%2$s) буде вираховуватися з кожного наступного поповнення, і вона не перевищуватиме ваш ліміт %3$s (%4$s).</string>
<string name="yield_module_fee_policy_sheet_max_fee_note">Якщо мережеві комісії перевищують максимальну комісію, транзакція не пройде, поки вони не знизяться. Ви можете змінити цей ліміт пізніше.</string>
<string name="yield_module_fee_policy_sheet_max_fee_title">Максимальна комісія</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">Це найменший депозит, який можна надіслати в Aave. Щоб депозити залишалися прибутковими, ми не обробляємо їх, коли комісія мережі перевищує %1$s%2$s від суми.</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">Мінімальна сума розраховується з урахуванням поточного збору мережі, щоб вона не перевищувала 4%%, що становить мінімум %1$s (%2$s).</string>
<string name="yield_module_fee_policy_sheet_min_amount_title">Мінімальне поповнення</string>
<string name="yield_module_fee_policy_sheet_title">Політика комісій</string>
<string name="yield_module_fee_policy_tangem_service_fee_title">Tangem комісію за обслуговування у розмірі 15% від отриманого доходу.</string>
@ -1479,11 +1483,11 @@
<string name="yield_module_promo_screen_cash_out_subtitle">Відправляйте, обмінюйте або продавайте свої кошти миттєво, в будь-який час.</string>
<string name="yield_module_promo_screen_cash_out_title">Миттєвий вивід коштів</string>
<string name="yield_module_promo_screen_how_it_works_button_title">Як це працює?</string>
<string name="yield_module_promo_screen_self_custodial_subtitle">Aave — це децентралізований протокол, який управляє активами загальною вартістю понад 61 мільярд доларів.</string>
<string name="yield_module_promo_screen_self_custodial_subtitle">Aave — децентралізований протокол, що керує активами на понад $61 млрд.</string>
<string name="yield_module_promo_screen_self_custodial_title">Децентралізований та некастодіальний</string>
<string name="yield_module_promo_screen_terms_disclaimer">Використовуючи сервіс, ви погоджуєтесь з умовами провайдера %1$s та %2$s</string>
<string name="yield_module_promo_screen_title">Підключити Aave</string>
<string name="yield_module_promo_screen_variable_rate_info">Aave %1$s%% • Ставка з плаваючим відсотком</string>
<string name="yield_module_promo_screen_variable_rate_info">Aave %1$s%% • Плаваюча ставка</string>
<string name="yield_module_provider">Аave</string>
<string name="yield_module_rate_info_sheet_chart_average">Серед. %s</string>
<string name="yield_module_rate_info_sheet_chart_title">Дохідність за минулий рік</string>
@ -1497,14 +1501,17 @@
<string name="yield_module_start_earning_sheet_next_deposits">Ваші наступні поповнення рахунку автоматично надходитимуть до Aave.</string>
<string name="yield_module_status_active">Активний</string>
<string name="yield_module_status_paused">На паузі</string>
<string name="yield_module_stop_earning">Завершити заробіток</string>
<string name="yield_module_stop_earning">Вимкнення режиму прибутковості</string>
<string name="yield_module_stop_earning_sheet_description">Вимкнення цієї опції виведе ваші активи з Aave, отримаєте їх назад у %s у вашому гаманці і зупинить накопичення нагород.</string>
<string name="yield_module_stop_earning_sheet_fee_note">Комісія мережі буде вирахувана з суми, яку ви знімаєте.</string>
<string name="yield_module_stop_earning_sheet_title">Завершити заробіток</string>
<string name="yield_module_supply_apr">Річна прибутковість (APY)</string>
<string name="yield_module_token_details_earn_notification_apy">APY</string>
<string name="yield_module_token_details_earn_notification_description">Відсотки нараховуються автоматично.</string>
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_subtitle">Відсотки нараховуються автоматично</string>
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">Режим дохідності</string>
<string name="yield_module_token_details_earn_notification_processing">Відправка ваших коштів</string>
<string name="yield_module_token_details_earn_notification_title">Режим прибутковості</string>
<string name="yield_module_transfer_mode_automatic">Автоматично</string>
<string name="yield_module_unable_to_cover_fee_description">Внесіть трохи %1$s %2$s, щоб покрити комісію мережі за транзакції.</string>
<string name="yield_module_unable_to_cover_fee_title">Неможливо покрити комісію в %s</string>

View file

@ -160,7 +160,7 @@
<item quantity="one">%d token</item>
<item quantity="other">%d tokens</item>
</plurals>
<string name="card_reset_alert_continue_message">Please reset the next device to continue.</string>
<string name="card_reset_alert_continue_message">Please reset the next device to continue.</string>
<string name="card_reset_alert_continue_title">Wallet reset</string>
<string name="card_reset_alert_finish_message">All Tangem devices have been reset. You can now continue upgrading your wallet.</string>
<string name="card_reset_alert_finish_ok_button">Upgrade again</string>
@ -539,6 +539,13 @@
<string name="give_permission_swap_subtitle" formatted="false">To continue, grant %1s smart contracts permission to use your %2s</string>
<string name="give_permission_title">Give Permission</string>
<string name="give_permission_unlimited">Unlimited</string>
<string name="hardware_wallet_backup_feature_description">Your backup is created using 2 or 3 Tangem cards. Keep them in separate safe places to protect against loss or damage — no seed phrase needed.</string>
<string name="hardware_wallet_backup_feature_title">Backup with Multiple Cards</string>
<string name="hardware_wallet_create_title">Add Tangem Wallet</string>
<string name="hardware_wallet_key_feature_description">Your private key is generated directly inside the Tangem card and never leaves it.</string>
<string name="hardware_wallet_key_feature_title">Key Generation</string>
<string name="hardware_wallet_security_feature_description">All cryptographic operations happen inside the secure chip, certified against cloning and physical tampering.</string>
<string name="hardware_wallet_security_feature_title">Hardware-Level Security</string>
<string name="home_button_add_existing_wallet">Add Existing Wallet</string>
<string name="home_button_create_new_wallet">Create New Wallet</string>
<string name="home_button_order">Order Tangem</string>
@ -580,6 +587,21 @@
<string name="hw_import_existing_wallet">Import existing wallet</string>
<string name="hw_import_seed_phrase_already_imported">This recovery phrase has already been imported</string>
<string name="hw_mobile_wallet">Mobile Wallet</string>
<string name="hw_remove_wallet_action_forget_title">Forget wallet</string>
<string name="hw_remove_wallet_attention_description">This wallet will be permanently removed from your device</string>
<string name="hw_remove_wallet_confirmation_title">Are you sure you want to do this?</string>
<string name="hw_remove_wallet_nav_title">Forget wallet</string>
<string name="hw_remove_wallet_notification_action_backup_go">Go to backup</string>
<string name="hw_remove_wallet_notification_action_backup_view">View backup</string>
<string name="hw_remove_wallet_notification_action_forget">Forget wallet</string>
<string name="hw_remove_wallet_notification_action_forget_anyway">Forget Anyway</string>
<string name="hw_remove_wallet_notification_description_has_backup">A backup for this wallet exists. Review it before forgetting to make sure you can recover later.</string>
<string name="hw_remove_wallet_notification_description_without_backup">If you forget this wallet without a backup, youll permanently lose access to your funds.</string>
<string name="hw_remove_wallet_notification_title">Forget this wallet?</string>
<string name="hw_remove_wallet_warning_access">I understand that if I haven\'t backed up my wallet before removing it, I may lose access to it.</string>
<string name="hw_remove_wallet_warning_device">I understand that removing my wallet does not delete it—but simply removes it from my device.</string>
<string name="hw_upgrade_backup_description">No seed phrase is needed anymore — your Tangem card or ring becomes your secure backup.</string>
<string name="hw_upgrade_backup_title">Backup with Tangem</string>
<string name="hw_upgrade_error_card_already_has_wallet">Cant upgrade. A wallet already exists on this device.</string>
<string name="hw_upgrade_error_card_key_import">Pick another device. This one cant be used for the upgrade.</string>
<string name="hw_upgrade_error_wallet2_card_required">An error occurred during the operation.</string>
@ -1159,11 +1181,12 @@
<string name="settings_wallet_name_title">Name</string>
<string name="stake_token_description">Put your token to work</string>
<string name="staking_account_initialization_footer">A network fee is a small payment required to process and confirm your transaction on the blockchain.</string>
<string name="staking_account_initialization_message">To start staking, your TON account must be activated with a self-transaction of 1 TON. The funds stay in your wallet — this step only enables your account for staking.</string>
<string name="staking_account_initialization_message">To begin staking, your TON account must be activated with a transaction of 1 TON. The funds stay in your account because this step only activates it for staking.</string>
<string name="staking_account_initialization_title">Account activation</string>
<string name="staking_amount_requirement_error">The amount to stake must be at least %s</string>
<string name="staking_amount_tron_integer_error">Staking amount will be rounded to %1$s TRX due to network rules.</string>
<string name="staking_amount_tron_integer_error_unstaking">Unstaking amount will be rounded to %1$s TRX due to network rules.</string>
<string name="staking_apr_earn_badge">APR %1$s%%</string>
<string name="staking_claim_unstaked">Claim unstaked</string>
<string name="staking_details_account_fee">Stake account fee</string>
<string name="staking_details_account_fee_info">A staking account is a special account where staked SOL tokens are stored. It is created when you delegate your tokens to a validator to participate in transaction validation and receive rewards. A small fee is charged for creating the staking account, which is returned after the staking is completed.</string>
@ -1227,7 +1250,7 @@
<string name="staking_notification_restake_rewards_text">Reinvests your earned rewards in your staked amount, increasing potential earnings.</string>
<string name="staking_notification_restake_text">Restake lets you move your funds from one validator to another without the need to unstake</string>
<string name="staking_notification_stake_entire_balance_text">If you stake your entire balance, youll need to pay a network fee when you unstake. We recommend leaving a small amount in your wallet to cover network fees.</string>
<string name="staking_notification_ton_account_initialization_message">To start staking, your TON account must be activated with a self-transaction of 1 TON. The funds stay in your wallet — this step only enables your account for staking.</string>
<string name="staking_notification_ton_account_initialization_message">To begin staking, you need to activate your TON account first.</string>
<string name="staking_notification_ton_account_initialization_title">Account activation</string>
<string name="staking_notification_ton_activate_account">To start staking in TON, first send a small transaction to your own address — this will activate your wallet.</string>
<string name="staking_notification_ton_extra_reserve_info">Up to 0.2 TON may be required in addition to the network fee to complete the transaction. Any unused amount will be refunded.</string>
@ -1348,6 +1371,8 @@
<string name="tangem_pay_status_pending">Pending</string>
<string name="tangem_pay_transaction_declined_notification_text">The bank rejected this transaction request.</string>
<string name="tangem_pay_transaction_fee_notification_text">This fee goes to cover the cost of handling your transfer.</string>
<string name="tangem_pay_unfreeze_card_alert_body">Keep using your money. You can freeze anytime.</string>
<string name="tangem_pay_unfreeze_card_alert_title">Unfreeze your card?</string>
<string name="tangem_pay_withdrawal">Withdrawal</string>
<string name="tangempay_card_details_add_funds">Add funds</string>
<string name="tangempay_card_details_add_funds_subtitle">Top-up options</string>
@ -1372,6 +1397,7 @@
<string name="tangempay_card_details_reveal_text">Reveal</string>
<string name="tangempay_card_details_swap_description">Swap any asset in your portfolio for card</string>
<string name="tangempay_card_details_title">Card details</string>
<string name="tangempay_card_details_unfreeze_card">Unfreeze Card</string>
<string name="tangempay_issue_card_notification_title">Create account and issue a card</string>
<string name="tangempay_kyc_card_ready_notification_title">Tangem Pay</string>
<string name="tangempay_kyc_in_progress_notification_button">View Status</string>
@ -1856,12 +1882,12 @@
<string name="yield_module_balance_info_sheet_subtitle">Your funds are currently supplied to the Aave protocol, but you can manage them at any time.</string>
<string name="yield_module_balance_info_sheet_title">Your %s is deposited in Aave</string>
<string name="yield_module_chart_loading_error">Unable to load chart...</string>
<string name="yield_module_deposit_error_notification_title">The amount received, %1$s %2$s was not supplied to Aave.</string>
<string name="yield_module_deposit_error_notification_title">Supplying %1$s %2$s to Aave is pending.</string>
<string name="yield_module_earn_badge">APY %1$s%%</string>
<string name="yield_module_earn_sheet_available_title">Available</string>
<string name="yield_module_earn_sheet_current_apy_title">Current APY</string>
<string name="yield_module_earn_sheet_fee_description">When topping up for lending, a network fee not exceeding %1$s will be deducted from the balance.</string>
<string name="yield_module_earn_sheet_high_fee_description">The network fee is currently too high to execute lending. Funds will be supplied once it drops to %1$s or below. </string>
<string name="yield_module_earn_sheet_high_fee_description">The network fee is currently too high to execute lending. Funds will be supplied once it drops to %1$s or below.</string>
<string name="yield_module_earn_sheet_my_funds_title">My funds</string>
<string name="yield_module_earn_sheet_provider_description">Your %1$s is now deployed to Aave and earning yield. You hold %2$s tokens, which represent your balance and accrue yield automatically. When you top up, funds are added to Aave to earn more yield, minus fees.</string>
<string name="yield_module_earn_sheet_title">Yield mode</string>
@ -1874,7 +1900,7 @@
<string name="yield_module_fee_policy_sheet_fee_note">An approximate network fee of %1$s (%2$s) will be deducted from each future top-up, and it wont exceed your %3$s (%4$s) limit.</string>
<string name="yield_module_fee_policy_sheet_max_fee_note">If network fees rise above maximum fee, the transaction wont go through until they decrease. You can change this limit later.</string>
<string name="yield_module_fee_policy_sheet_max_fee_title">Maximum fee</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">The minimum amount is calculated from the current network fee to ensure it does not exceed 4%%, which makes the minimum %1$s (%2$s).</string>
<string name="yield_module_fee_policy_sheet_min_amount_note">The minimum amount is calculated based on the current network fee so that it does not exceed 4%% of the top-up amount, which makes the minimum %1$s (%2$s).</string>
<string name="yield_module_fee_policy_sheet_min_amount_title">Minimum top-up</string>
<string name="yield_module_fee_policy_sheet_title">Fee policy</string>
<string name="yield_module_fee_policy_tangem_service_fee_title">Tangem also takes a 15% service fee on yield earned.</string>
@ -1907,13 +1933,14 @@
<string name="yield_module_start_earning_sheet_next_deposits">Your next top-ups will be automatically supplied to Aave.</string>
<string name="yield_module_status_active">Active</string>
<string name="yield_module_status_paused">Paused</string>
<string name="yield_module_stop_earning">Disable yield mode</string>
<string name="yield_module_stop_earning">Disabling Yield Mode</string>
<string name="yield_module_stop_earning_sheet_description">Turning this off will withdraw your assets from Aave, convert them back to %s in your wallet, and stop yield accrual.</string>
<string name="yield_module_stop_earning_sheet_fee_note">The network fee will be deducted from the amount you withdraw.</string>
<string name="yield_module_stop_earning_sheet_title">Disable yield mode</string>
<string name="yield_module_supply">Supply</string>
<string name="yield_module_supply_apr">Supply APY</string>
<string name="yield_module_token_details_earn_notification_apy">APY</string>
<string name="yield_module_token_details_earn_notification_description">Interest accrues automatically</string>
<string name="yield_module_token_details_earn_notification_description">Interest accrues automatically.</string>
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_subtitle">Interest accrues automatically</string>
<string name="yield_module_token_details_earn_notification_earning_on_your_balance_title">Yield mode</string>
<string name="yield_module_token_details_earn_notification_processing">Processing your deposit</string>

View file

@ -75,6 +75,7 @@ fun Label(state: LabelUM, modifier: Modifier = Modifier) {
.padding(horizontal = 8.dp, vertical = 4.dp),
) {
Text(
modifier = Modifier.weight(1.0f, fill = false),
text = text.resolveReference(),
style = TangemTheme.typography.caption1,
color = textColor,
@ -125,7 +126,9 @@ private fun LabelPreview() {
)
Label(
state = LabelUM(
text = TextReference.Str("Regular Label"),
text = TextReference.Str(
"Regular long long long long long long long long long long long long Label",
),
style = LabelStyle.REGULAR,
icon = R.drawable.ic_information_24,
),

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -1,9 +1,8 @@
package com.tangem.domain.card
package com.tangem.domain.card.common
import com.tangem.domain.common.TwinsHelper
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Assert
import org.junit.Test
import org.junit.jupiter.api.Assertions.*
class TwinsHelperTest {
@ -19,7 +18,7 @@ class TwinsHelperTest {
@Test
fun `twins compatibility pack 1 success`() {
assertTrue(TwinsHelper.isTwinsCompatible(pack1Twins[0], pack1Twins[1]))
Assert.assertTrue(TwinsHelper.isTwinsCompatible(pack1Twins[0], pack1Twins[1]))
assertTrue(TwinsHelper.isTwinsCompatible(pack1Twins[1], pack1Twins[0]))
}

View file

@ -18,13 +18,13 @@ import com.tangem.domain.promo.models.PromoId
import com.tangem.domain.promo.models.StoryContent
import com.tangem.feature.referral.domain.ReferralRepository
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.runCatching
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import com.tangem.utils.coroutines.runCatching
internal class DefaultPromoRepository(
private val tangemApi: TangemTechApi,
@ -49,6 +49,11 @@ internal class DefaultPromoRepository(
PromoId.Sepa -> {
val isActive = getSepaPromoBanner()?.isActive ?: false
isActive && shouldShow
}
PromoId.VisaPresale -> {
val isActive = getVisaPromoBanner()?.isActive ?: false
isActive && shouldShow
}
}
@ -59,6 +64,7 @@ internal class DefaultPromoRepository(
return when (promoId) {
PromoId.Referral -> flowOf(false)
PromoId.Sepa -> flowOf(false)
PromoId.VisaPresale -> flowOf(false)
}
}
@ -134,8 +140,17 @@ internal class DefaultPromoRepository(
}.getOrNull()
}
private suspend fun getVisaPromoBanner(): PromoBanner? {
return runCatching(dispatchers.io) {
promoBannerConverter.convert(
tangemApi.getPromoBanner(VISA_NAME).getOrThrow(),
)
}.getOrNull()
}
private companion object {
const val SEPA_NAME = "sepa"
const val VISA_NAME = "visa-waitlist"
const val STORIES_LOAD_DELAY = 1000L
}
}

View file

@ -67,20 +67,6 @@ internal object TokensDataModule {
)
}
@Provides
@Singleton
fun providePolkadotAccountHealthCheckRepository(
walletManagersFacade: WalletManagersFacade,
appPreferencesStore: AppPreferencesStore,
dispatchers: CoroutineDispatcherProvider,
): PolkadotAccountHealthCheckRepository {
return DefaultPolkadotAccountHealthCheckRepository(
walletManagersFacade = walletManagersFacade,
appPreferencesStore = appPreferencesStore,
dispatchers = dispatchers,
)
}
@Provides
@Singleton
fun provideTokenReceiveWarningsViewedRepository(

View file

@ -1,179 +0,0 @@
package com.tangem.data.tokens.repository
import androidx.datastore.preferences.core.Preferences
import com.tangem.blockchain.blockchains.polkadot.AccountCheckProvider
import com.tangem.blockchain.blockchains.polkadot.network.accounthealthcheck.ExtrinsicListItemResponse
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.BlockchainSdkError
import com.tangem.blockchainsdk.utils.toBlockchain
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys.POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS_KEY
import com.tangem.datasource.local.preferences.PreferencesKeys.POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS_KEY
import com.tangem.datasource.local.preferences.PreferencesKeys.POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX_KEY
import com.tangem.datasource.local.preferences.utils.getObjectMapSync
import com.tangem.datasource.local.preferences.utils.getObjectSetSync
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.util.concurrent.ConcurrentHashMap
internal class DefaultPolkadotAccountHealthCheckRepository(
private val walletManagersFacade: WalletManagersFacade,
private val appPreferencesStore: AppPreferencesStore,
private val dispatchers: CoroutineDispatcherProvider,
) : PolkadotAccountHealthCheckRepository {
private val hasImmortalTransaction = MutableSharedFlow<Pair<String, Boolean>>()
private val hasResetTransaction = MutableSharedFlow<Pair<String, Boolean>>()
private val mutex = Mutex()
private val mutexes = ConcurrentHashMap<String, Mutex>()
override suspend fun runCheck(userWalletId: UserWalletId, network: Network) {
// Run Polkadot account health check
if (network.toBlockchain() != Blockchain.Polkadot) return
val walletManager = walletManagersFacade.getOrCreateWalletManager(userWalletId, network)
val address = requireNotNull(walletManager?.wallet?.address) {
Timber.e("Address is null")
return
}
val accountCheckProvider = requireNotNull(walletManager as? AccountCheckProvider) {
Timber.e("Unable to cast wallet manager to AccountCheckProvider")
return
}
// use a separate mutexForKey for each key to avoid multiple calls block() to the same key
// also used mutex to safe create mutexForKey, otherwise it can lead to multiple calls for the same key
val mutexForKey = mutex.withLock { mutexes.getOrPut(address) { Mutex() } }
mutexForKey.withLock {
withContext(dispatchers.io) {
checkHasReset(accountCheckProvider, address)
checkHasImmortal(accountCheckProvider, address)
}
}
}
override fun subscribeToHasImmortalResults() = hasImmortalTransaction.asSharedFlow()
override fun subscribeToHasResetResults() = hasResetTransaction.asSharedFlow()
private suspend fun checkHasReset(polkadotManager: AccountCheckProvider, address: String) {
val checkedAddresses = appPreferencesStore.getObjectSetSync<String>(POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS_KEY)
if (checkedAddresses.contains(address)) return
runCatching {
val accountInfo = requireNotNull(polkadotManager.getAccountInfo().account) {
Timber.e("Account info is null")
}
val nonce = accountInfo.nonce
val extrinsicCount = accountInfo.countExtrinsic
// Account was reset
if (nonce != null && extrinsicCount != null) {
val hasReset = nonce < extrinsicCount
updateChecked(address, POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS_KEY)
hasResetTransaction.emit(address to hasReset)
}
}.onFailure {
if ((it as? BlockchainSdkError.CustomError)?.customMessage == ACCOUNT_NOT_FOUND) {
updateChecked(address, POLKADOT_HEALTH_CHECKED_RESET_ACCOUNTS_KEY)
}
}
}
private suspend fun checkHasImmortal(accountCheckerProvider: AccountCheckProvider, address: String) {
val checkedAddresses =
appPreferencesStore.getObjectSetSync<String>(POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS_KEY)
if (checkedAddresses.contains(address)) return
runCatching {
do {
// Getting batch of extrinsics to check
val lastChecked = appPreferencesStore.getObjectMapSync<Long>(POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX_KEY)
val lastExtrinsic = lastChecked[address]
val extrinsicListResult = accountCheckerProvider.getExtrinsicList(afterExtrinsicId = lastExtrinsic)
extrinsicListResult.extrinsic
?.forEach { tx ->
// Checking extrinsic one by one
if (checkTx(tx, address, accountCheckerProvider)) return
}
} while (!extrinsicListResult.extrinsic.isNullOrEmpty())
// We checked all transactions up to current moment and did not found an `immortal` transaction
hasImmortalTransaction.emit(address to false)
updateChecked(address, POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS_KEY)
clearLastCheckedTransaction(address)
}
}
private suspend fun checkTx(
tx: ExtrinsicListItemResponse,
address: String,
accountCheckerProvider: AccountCheckProvider,
): Boolean {
val hash = tx.hash
val id = tx.id
if (hash != null && id != null) {
val details = accountCheckerProvider.getExtrinsicDetail(hash)
// We found an `immortal` transaction
if (details.lifetime == null) {
hasImmortalTransaction.emit(address to true)
updateChecked(address, POLKADOT_HEALTH_CHECKED_IMMUTABLE_ACCOUNTS_KEY)
clearLastCheckedTransaction(address)
return true
}
// Saving last checked transaction
updateLastCheckedTransaction(address, id)
}
return false
}
private suspend fun updateLastCheckedTransaction(address: String, txId: Long) {
appPreferencesStore.editData {
val savedList = it.getObjectMap<Long>(POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX_KEY)
val updatedList = savedList.toMutableMap()
updatedList[address] = txId
it.setObjectMap(POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX_KEY, updatedList)
}
}
private suspend fun clearLastCheckedTransaction(address: String) {
appPreferencesStore.editData { mutablePreferences ->
val savedList = mutablePreferences.getObjectMap<Long>(POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX_KEY)
val updatedList = savedList.toMutableMap()
updatedList.remove(address)
mutablePreferences.setObjectMap(POLKADOT_HEALTH_CHECK_LAST_INDEXED_TX_KEY, updatedList)
}
}
private suspend fun updateChecked(address: String, key: Preferences.Key<String>) {
appPreferencesStore.editData { mutablePreferences ->
val savedList = mutablePreferences.getObjectSet<String>(key)
val updatedList = savedList?.toMutableSet() ?: mutableSetOf()
updatedList.add(address)
if (updatedList.isNotEmpty()) {
mutablePreferences.setObjectSet(
key,
updatedList.toSet(),
)
} else {
mutablePreferences.remove(key)
}
}
}
private companion object {
const val ACCOUNT_NOT_FOUND = "Record Not Found"
}
}

View file

@ -12,8 +12,8 @@ internal object YieldMarketTokenConverter : Converter<YieldSupplyMarketTokenDto,
apy = value.apy.orZero(),
isActive = value.isActive ?: false,
chainId = value.chainId ?: -1,
maxFeeUSD = value.maxFeeUSD.orEmpty(),
maxFeeNative = value.maxFeeNative.orEmpty(),
maxFeeUSD = value.maxFeeUSD.orZero(),
maxFeeNative = value.maxFeeNative.orZero(),
)
}
}

View file

@ -1,90 +0,0 @@
package com.tangem.domain.common
import com.tangem.crypto.CryptoUtils
import com.tangem.domain.models.scan.CardDTO
object TwinsHelper {
/**
* Card compatibility
* cb61 <-> cb62
* cb64 <-> cb65
*
*/
private const val FIRST_CARD_FIRST_SERIES = "CB61"
private const val SECOND_CARD_FIRST_SERIES = "CB62"
private const val FIRST_CARD_SECOND_SERIES = "CB64"
private const val SECOND_CARD_SECOND_SERIES = "CB65"
@Suppress("MagicNumber")
fun verifyTwinPublicKey(issuerData: ByteArray, cardWalletPublicKey: ByteArray?): Boolean {
if (issuerData.size < 65 || cardWalletPublicKey == null) return false
val publicKey = issuerData.sliceArray(0 until 65)
val signedKey = issuerData.sliceArray(65 until issuerData.size)
return CryptoUtils.verify(cardWalletPublicKey, publicKey, signedKey)
}
fun getTwinCardNumber(cardId: String): TwinCardNumber? {
val isFirstCard = cardId.startsWith(FIRST_CARD_FIRST_SERIES) ||
cardId.startsWith(FIRST_CARD_SECOND_SERIES)
if (isFirstCard) return TwinCardNumber.First
val isSecondCard = cardId.startsWith(SECOND_CARD_FIRST_SERIES) ||
cardId.startsWith(SECOND_CARD_SECOND_SERIES)
if (isSecondCard) return TwinCardNumber.Second
return null
}
@Suppress("MagicNumber")
fun getTwinCardIdForUser(cardId: String): String {
if (cardId.length < 16) return cardId
val twinCardId = cardId.substring(11..14)
val twinCardNumber = getTwinCardNumber(cardId)?.number ?: 1
return "$twinCardId #$twinCardNumber"
}
/**
* Twins compatibility
* cb61 <-> cb62
* cb64 <-> cb65
*/
fun isTwinsCompatible(firstCardId: String, secondCardId: String): Boolean {
return secondCardId.startsWith(getCompatibleTwinCardId(firstCardId))
}
private fun getCompatibleTwinCardId(cardId: String): String {
return when {
cardId.startsWith(FIRST_CARD_FIRST_SERIES) -> SECOND_CARD_FIRST_SERIES
cardId.startsWith(FIRST_CARD_SECOND_SERIES) -> SECOND_CARD_SECOND_SERIES
cardId.startsWith(SECOND_CARD_FIRST_SERIES) -> FIRST_CARD_FIRST_SERIES
cardId.startsWith(SECOND_CARD_SECOND_SERIES) -> FIRST_CARD_SECOND_SERIES
else -> {
"unknown"
}
}
}
}
enum class TwinCardNumber(val number: Int) {
First(1), Second(2);
fun pairNumber(): TwinCardNumber = when (this) {
First -> Second
Second -> First
}
}
@Deprecated("Use ScanResponse.isTangemTwin")
fun CardDTO.isTangemTwin(): Boolean {
return TwinsHelper.getTwinCardNumber(cardId) != null
}
fun CardDTO.getTwinCardNumber(): TwinCardNumber? {
return TwinsHelper.getTwinCardNumber(this.cardId)
}
fun CardDTO.getTwinCardIdForUser(): String {
return TwinsHelper.getTwinCardIdForUser(this.cardId)
}

View file

@ -14,6 +14,10 @@ import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.derivations.DerivationsRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@Deprecated("Use SaveCryptoCurrenciesUseCase")
@Suppress("LongParameterList")
@ -26,6 +30,7 @@ class SaveManagedTokensUseCase(
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
private val stakingIdFactory: StakingIdFactory,
private val parallelUpdatingScope: CoroutineScope,
) {
suspend operator fun invoke(
@ -54,11 +59,23 @@ class SaveManagedTokensUseCase(
currencies = addingCurrencies,
)
refreshUpdatedNetworks(userWalletId = userWalletId, addedCurrencies = savedCurrencies)
refreshUpdatedYieldBalances(userWalletId = userWalletId, addedCurrencies = savedCurrencies)
refreshUpdatedQuotes(addedCurrencies = savedCurrencies)
parallelUpdatingScope.launch {
withContext(NonCancellable) {
launch {
refreshUpdatedNetworks(
userWalletId = userWalletId,
addedCurrencies = savedCurrencies,
)
}
launch {
refreshUpdatedYieldBalances(
userWalletId = userWalletId,
addedCurrencies = savedCurrencies,
)
}
launch { refreshUpdatedQuotes(addedCurrencies = savedCurrencies) }
}
}
}
}

View file

@ -11,6 +11,10 @@ import com.tangem.domain.staking.StakingIdFactory
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.wallets.derivations.DerivationsRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* Use case for saving tokens from Markets
@ -31,6 +35,7 @@ class SaveMarketTokensUseCase(
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
private val stakingIdFactory: StakingIdFactory,
private val parallelUpdatingScope: CoroutineScope,
) {
suspend operator fun invoke(
@ -70,11 +75,13 @@ class SaveMarketTokensUseCase(
currencies = addedCurrencies,
)
refreshUpdatedNetworks(userWalletId, savedCurrencies)
refreshUpdatedYieldBalances(userWalletId, savedCurrencies)
refreshUpdatedQuotes(savedCurrencies)
parallelUpdatingScope.launch {
withContext(NonCancellable) {
launch { refreshUpdatedNetworks(userWalletId, savedCurrencies) }
launch { refreshUpdatedYieldBalances(userWalletId, savedCurrencies) }
launch { refreshUpdatedQuotes(savedCurrencies) }
}
}
}
}

View file

@ -28,4 +28,5 @@ data class PromoBanner(
enum class PromoId {
Referral,
Sepa,
VisaPresale,
}

View file

@ -29,7 +29,9 @@ class ShouldShowPromoWalletUseCase(
if (!isReady) return false
return when (promoId) {
PromoId.Referral -> true
PromoId.Referral,
PromoId.VisaPresale,
-> true
PromoId.Sepa -> {
val walletFirstUsageDate = settingsRepository.getWalletFirstUsageDate()
if (walletFirstUsageDate == 0L) return false
@ -39,6 +41,7 @@ class ShouldShowPromoWalletUseCase(
}
}
}
suspend fun neverToShow(promoId: PromoId) = promoRepository.setNeverToShowWalletPromo(promoId)
private companion object {

View file

@ -1,8 +1,10 @@
package com.tangem.domain.staking.model
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchainsdk.utils.toBlockchain
import com.tangem.blockchainsdk.utils.toMigratedCoinId
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
/**
* Represents a staking integration identifier.
@ -143,6 +145,9 @@ sealed interface StakingIntegrationID {
}
}
val Network.isStakingSupported: Boolean
get() = this.toBlockchain().isStakingSupported
/**
* Extension property to check if staking is supported for a blockchain.
*

View file

@ -1,8 +1,5 @@
package com.tangem.domain.staking.usecase
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchainsdk.utils.toNetworkId
import com.tangem.domain.staking.model.StakingIntegrationID
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.staking.repositories.StakingRepository
import kotlinx.coroutines.flow.Flow
@ -21,22 +18,10 @@ class StakingApyFlowUseCase(private val stakingRepository: StakingRepository) {
return stakingRepository.getEnabledYields()
.map { yields ->
yields.associate { yield ->
val key = composeKey(yield)
val key = "${yield.token.coinGeckoId}_${yield.token.symbol}"
val apy = yield.validators
key to apy
}
}
}
// so that cause for api.stakek.it coinGeckoId on BNB Smart chain different how we receive our backendId
// coinGeckoId - binance
// our backendId BNB Smart Chain - binance-smart-chain
// our backendId BNB Beacon Chain - binance
private fun composeKey(yield: Yield): String {
return if (yield.token.symbol == StakingIntegrationID.Coin.BSC.blockchain.currency) {
"${Blockchain.BSC.toNetworkId()}_${yield.token.symbol}"
} else {
"${yield.token.coinGeckoId}_${yield.token.symbol}"
}
}
}

View file

@ -3,14 +3,14 @@ package com.tangem.domain.tokens.model.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
sealed class TokenSwapPromoAnalyticsEvent(
sealed class PromoAnalyticsEvent(
event: String,
params: Map<String, String> = mapOf(),
) : AnalyticsEvent(category = "Promotion", event = event, params = params) {
class NoticePromotionBanner(
source: AnalyticsParam.ScreensSources,
program: Program,
) : TokenSwapPromoAnalyticsEvent(
) : PromoAnalyticsEvent(
event = "Notice - Promotion Banner",
params = mapOf(
AnalyticsParam.SOURCE to source.value,
@ -22,7 +22,7 @@ sealed class TokenSwapPromoAnalyticsEvent(
source: AnalyticsParam.ScreensSources,
program: Program,
action: BannerAction,
) : TokenSwapPromoAnalyticsEvent(
) : PromoAnalyticsEvent(
event = "Promo Banner Clicked",
params = mapOf(
AnalyticsParam.SOURCE to source.value,
@ -36,6 +36,24 @@ sealed class TokenSwapPromoAnalyticsEvent(
}
}
// region visa waitlist promo
data object VisaWaitlistPromo : PromoAnalyticsEvent(event = "Visa Waitlist")
data object VisaWaitlistPromoJoin : PromoAnalyticsEvent(
event = "Button - Join Now",
params = mapOf(
"Program Name" to "Visa Waitlist",
),
)
data object VisaWaitlistPromoDismiss : PromoAnalyticsEvent(
event = "Button - Close",
params = mapOf(
"Program Name" to "Visa Waitlist",
),
)
//endregion
// Use it on new promo action
enum class Program(val programName: String) {
Empty("Empty"),

View file

@ -184,6 +184,7 @@ sealed class TokenScreenAnalyticsEvent(
private const val LOADING = "Loading"
private const val ASSET_REQUIREMENT = "AssetRequirement"
private const val TRUSTLINE_REQUIREMENT = "TrustlineRequirement"
private const val APPROVAL_REQUIRED = "Approval Required"
@Suppress("CyclomaticComplexMethod")
fun ScenarioUnavailabilityReason.toReasonAnalyticsText(): String {
@ -192,8 +193,8 @@ sealed class TokenScreenAnalyticsEvent(
is ScenarioUnavailabilityReason.NotExchangeable,
is ScenarioUnavailabilityReason.NotSupportedBySellService,
is ScenarioUnavailabilityReason.StakingUnavailable,
ScenarioUnavailabilityReason.YieldSupplyApprovalRequired,
-> UNAVAILABLE
is ScenarioUnavailabilityReason.YieldSupplyApprovalRequired -> APPROVAL_REQUIRED
ScenarioUnavailabilityReason.UnassociatedAsset -> ASSET_REQUIREMENT
ScenarioUnavailabilityReason.TrustlineRequired -> TRUSTLINE_REQUIREMENT
is ScenarioUnavailabilityReason.EmptyBalance -> EMPTY

View file

@ -1,11 +0,0 @@
package com.tangem.domain.tokens
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
import kotlinx.coroutines.flow.Flow
class GetPolkadotCheckHasImmortalUseCase(
private val polkadotAccountHealthCheckRepository: PolkadotAccountHealthCheckRepository,
) {
operator fun invoke(): Flow<Pair<String, Boolean>> =
polkadotAccountHealthCheckRepository.subscribeToHasImmortalResults()
}

View file

@ -1,12 +0,0 @@
package com.tangem.domain.tokens
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
import kotlinx.coroutines.flow.Flow
class GetPolkadotCheckHasResetUseCase(
private val polkadotAccountHealthCheckRepository: PolkadotAccountHealthCheckRepository,
) {
operator fun invoke(): Flow<Pair<String, Boolean>> =
polkadotAccountHealthCheckRepository.subscribeToHasResetResults()
}

View file

@ -1,15 +0,0 @@
package com.tangem.domain.tokens
import arrow.core.Either
import com.tangem.domain.models.network.Network
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
import com.tangem.domain.models.wallet.UserWalletId
class RunPolkadotAccountHealthCheckUseCase(
private val polkadotAccountHealthCheckRepository: PolkadotAccountHealthCheckRepository,
) {
suspend operator fun invoke(userWalletId: UserWalletId, network: Network): Either<Throwable, Unit> = Either.catch {
polkadotAccountHealthCheckRepository.runCheck(userWalletId, network)
}
}

View file

@ -1,14 +0,0 @@
package com.tangem.domain.tokens.repository
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWalletId
import kotlinx.coroutines.flow.Flow
interface PolkadotAccountHealthCheckRepository {
suspend fun runCheck(userWalletId: UserWalletId, network: Network)
fun subscribeToHasImmortalResults(): Flow<Pair<String, Boolean>>
fun subscribeToHasResetResults(): Flow<Pair<String, Boolean>>
}

View file

@ -2,8 +2,8 @@ package com.tangem.domain.wallets.usecase
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.services.Result
import com.tangem.domain.common.TwinCardNumber
import com.tangem.domain.common.TwinsHelper
import com.tangem.domain.card.common.TwinCardNumber
import com.tangem.domain.card.common.TwinsHelper
import com.tangem.domain.models.ArtworkModel
import com.tangem.domain.wallets.models.Artwork
import com.tangem.operations.attestation.ArtworkSize

View file

@ -12,8 +12,8 @@ data class YieldMarketToken(
val chainId: Int,
val apy: SerializedBigDecimal,
val isActive: Boolean,
val maxFeeNative: String,
val maxFeeUSD: String,
val maxFeeNative: SerializedBigDecimal,
val maxFeeUSD: SerializedBigDecimal,
val backendId: String? = null,
) {

View file

@ -3,6 +3,10 @@ package com.tangem.domain.yield.supply
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.domain.models.currency.CryptoCurrency
import java.math.BigInteger
import java.math.RoundingMode
private val HUNDRED_PERCENT = 100.toBigInteger() // base 100%
val INCREASE_GAS_LIMIT_FOR_SUPPLY = 112.toBigInteger() // 12% increase
fun Fee.fixFee(cryptoCurrency: CryptoCurrency, gasLimit: BigInteger): Fee = when (this) {
is Fee.Ethereum.Legacy -> copy(
@ -20,4 +24,24 @@ fun Fee.fixFee(cryptoCurrency: CryptoCurrency, gasLimit: BigInteger): Fee = when
),
)
else -> this
}
/**
* Increase gasLimit for Fee.Ethereum
*/
fun Fee.increaseGasLimitBy(percent: BigInteger): Fee {
if (this !is Fee.Ethereum) return this
val gasLimit = this.gasLimit
val increasedGasPrice = this.amount.value?.movePointRight(this.amount.decimals)
?.divide(gasLimit.toBigDecimal(), RoundingMode.HALF_UP)
val increasedGasLimit = gasLimit
.multiply(percent)
.divide(HUNDRED_PERCENT)
val increasedAmount = this.amount.copy(
value = increasedGasLimit.toBigDecimal().multiply(increasedGasPrice).movePointLeft(this.amount.decimals),
)
return when (this) {
is Fee.Ethereum.EIP1559 -> copy(amount = increasedAmount, gasLimit = increasedGasLimit)
is Fee.Ethereum.Legacy -> copy(amount = increasedAmount, gasLimit = increasedGasLimit)
}
}

View file

@ -6,11 +6,13 @@ import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.yieldsupply.providers.ethereum.yield.EthereumYieldSupplyEnterCallData
import com.tangem.domain.blockaid.BlockAidGasEstimate
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.yield.supply.fixFee
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.transaction.FeeRepository
import com.tangem.domain.transaction.error.FeeErrorResolver
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.yield.supply.INCREASE_GAS_LIMIT_FOR_SUPPLY
import com.tangem.domain.yield.supply.fixFee
import com.tangem.domain.yield.supply.increaseGasLimitBy
import com.tangem.utils.extensions.isSingleItem
import timber.log.Timber
@ -73,7 +75,10 @@ class YieldSupplyEstimateEnterFeeUseCase(
)
return transactionDataList.zip(estimatedFees.estimatedGasList) { transaction, estimatedGas ->
transaction.copy(fee = fee.fixFee(cryptoCurrency, estimatedGas))
transaction.copy(
fee = fee.fixFee(cryptoCurrency, estimatedGas)
.increaseGasLimitBy(INCREASE_GAS_LIMIT_FOR_SUPPLY),
)
}
}

View file

@ -14,11 +14,15 @@ import java.math.BigDecimal
import java.math.RoundingMode
/**
* Calculates max allowed network fee for Yield Supply enter transaction expressed in token units.
* Calculates the max allowed network fee for a Yield Supply transaction.
*
* Uses YieldMarketToken.maxFeeNative (native coin units) and converts it to token units with the
* same conversion logic as [YieldSupplyGetCurrentFeeUseCase]: based on fiat rate ratio
* (nativeFiatRate / tokenFiatRate).
* Result is a Pair<BigDecimal, BigDecimal> where:
* - first: fee in native coin units (maxFeeNative)
* - second: the same fee converted to token units using the fiat-rate ratio
* (nativeFiatRate / tokenFiatRate).
*
* Uses YieldMarketToken.maxFeeNative and the same conversion logic as
* [YieldSupplyGetCurrentFeeUseCase].
*/
class YieldSupplyGetMaxFeeUseCase(
private val yieldSupplyRepository: YieldSupplyRepository,
@ -29,7 +33,7 @@ class YieldSupplyGetMaxFeeUseCase(
suspend operator fun invoke(
userWallet: UserWallet,
cryptoCurrencyStatus: CryptoCurrencyStatus,
): Either<Throwable, BigDecimal> = catch {
): Either<Throwable, Pair<BigDecimal, BigDecimal>> = catch {
val token = cryptoCurrencyStatus.currency as? CryptoCurrency.Token
?: error("CryptoCurrency must be token for max fee calculation")
@ -55,7 +59,7 @@ class YieldSupplyGetMaxFeeUseCase(
val cachedMarketToken = yieldSupplyRepository.getCachedMarkets().orEmpty()
.firstOrNull { it.yieldSupplyKey == token.yieldSupplyKey() }
val marketToken = cachedMarketToken ?: yieldSupplyRepository.getTokenStatus(token)
val maxFeeNative = marketToken.maxFeeNative.toBigDecimal()
val maxFeeNative = marketToken.maxFeeNative
val rateRatio = nativeFiatRate.divide(
fiatRate,
@ -65,6 +69,6 @@ class YieldSupplyGetMaxFeeUseCase(
val tokenValue = rateRatio.multiply(maxFeeNative)
tokenValue.stripTrailingZeros()
maxFeeNative to tokenValue.stripTrailingZeros()
}
}

View file

@ -314,9 +314,9 @@ class YieldSupplyEstimateEnterFeeUseCaseTest {
val deployFee = txs.first().fee as Fee.Ethereum.EIP1559
val approveFee = txs[1].fee as Fee.Ethereum.EIP1559
val enterFee = txs.last().fee as Fee.Ethereum.EIP1559
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(1_000))
Truth.assertThat(approveFee.gasLimit).isEqualTo(BigInteger.valueOf(2_000))
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(3_000))
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(1_120))
Truth.assertThat(approveFee.gasLimit).isEqualTo(BigInteger.valueOf(2_240))
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(3_360))
}
@Test
@ -353,9 +353,9 @@ class YieldSupplyEstimateEnterFeeUseCaseTest {
val deployFee = txs.first().fee as Fee.Ethereum.Legacy
val approveFee = txs[1].fee as Fee.Ethereum.Legacy
val enterFee = txs.last().fee as Fee.Ethereum.Legacy
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(1_000))
Truth.assertThat(approveFee.gasLimit).isEqualTo(BigInteger.valueOf(2_000))
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(3_000))
Truth.assertThat(deployFee.gasLimit).isEqualTo(BigInteger.valueOf(1_120))
Truth.assertThat(approveFee.gasLimit).isEqualTo(BigInteger.valueOf(2_240))
Truth.assertThat(enterFee.gasLimit).isEqualTo(BigInteger.valueOf(3_360))
}
private fun getDeployTx() = uncompiled(

View file

@ -16,9 +16,9 @@ import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.toWrappedList
import com.tangem.datasource.local.config.issuers.IssuersConfigStorage
import com.tangem.domain.card.common.TwinCardNumber
import com.tangem.domain.card.common.getTwinCardNumber
import com.tangem.domain.card.repository.CardRepository
import com.tangem.domain.common.TwinCardNumber
import com.tangem.domain.common.getTwinCardNumber
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.domain.models.scan.ScanResponse
@ -68,6 +68,7 @@ internal class OnboardingTwinModel @Inject constructor(
private val params = paramsContainer.require<OnboardingTwinComponent.Params>()
private val firstCardTwinNumber = params.scanResponse.card.getTwinCardNumber() ?: error("Not twin")
private val cryptoCurrencyStatusJobHolder = JobHolder()
private var twinCardsIds = Pair<String?, String?>(null, null)
private val _uiState = MutableStateFlow(
when (params.mode) {
@ -159,6 +160,7 @@ internal class OnboardingTwinModel @Inject constructor(
}
is CompletionResult.Success -> {
if (params.mode == Mode.CreateWallet) {
twinCardsIds = twinCardsIds.copy(first = result.data.cardId)
cardRepository.startCardActivation(result.data.cardId)
}
@ -216,6 +218,7 @@ internal class OnboardingTwinModel @Inject constructor(
}
is CompletionResult.Success -> {
if (params.mode == Mode.CreateWallet) {
twinCardsIds = twinCardsIds.copy(second = result.data.cardId)
cardRepository.startCardActivation(result.data.cardId)
}
@ -299,7 +302,12 @@ internal class OnboardingTwinModel @Inject constructor(
return@coroutineScope
}
cardRepository.finishCardActivation(params.scanResponse.card.cardId)
twinCardsIds.first?.let {
cardRepository.finishCardActivation(it)
}
twinCardsIds.second?.let {
cardRepository.finishCardActivation(it)
}
params.modelCallbacks.onDone()
}

View file

@ -24,11 +24,10 @@ import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.haptic.TangemHapticEffect
import com.tangem.core.ui.haptic.VibratorHapticManager
import com.tangem.core.ui.message.DialogMessage
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
import com.tangem.core.ui.message.DialogMessage
import com.tangem.features.staking.impl.R
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
@ -60,6 +59,7 @@ import com.tangem.domain.transaction.usecase.*
import com.tangem.domain.utils.convertToSdkAmount
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.staking.api.StakingComponent
import com.tangem.features.staking.impl.R
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
@ -171,6 +171,7 @@ internal class StakingModel @Inject constructor(
}
private var isAccountInitialized: Boolean = true
private var isTonHeatupCase: Boolean = false
private lateinit var cryptoCurrencyStatus: CryptoCurrencyStatus
private var stakingActions: List<StakingAction> = emptyList()
private var feeCryptoCurrencyStatus: CryptoCurrencyStatus? = null
@ -1063,7 +1064,7 @@ internal class StakingModel @Inject constructor(
currency = params.cryptoCurrency,
).conflate().distinctUntilChanged()
.filter {
value.currentStep == StakingStep.InitialInfo || isCaseWithUnitializedTonAccount()
value.currentStep == StakingStep.InitialInfo || isTopHeatupCase()
}.onEach { (maybeAccount, maybeStatus) ->
isAccountsModeEnabled = isAccountsModeEnabledUseCase.invokeSync()
account = maybeAccount
@ -1077,7 +1078,7 @@ internal class StakingModel @Inject constructor(
isSingleWalletWithTokens = false,
).conflate().distinctUntilChanged()
.filter {
value.currentStep == StakingStep.InitialInfo || isCaseWithUnitializedTonAccount()
value.currentStep == StakingStep.InitialInfo || isTopHeatupCase()
}
.onEach { maybeStatus ->
maybeStatus.fold(
@ -1119,19 +1120,7 @@ internal class StakingModel @Inject constructor(
}
cryptoCurrencyStatus = status
val isAccountInitializedNew = checkAccountInitializedUseCase.invoke(
userWalletId = userWalletId,
network = cryptoCurrencyStatus.currency.network,
).getOrElse {
Timber.e(it)
false
}
if (isAccountInitializedNew && !isAccountInitialized) {
isAccountInitialized = true
updateNotifications()
}
isAccountInitialized = isAccountInitializedNew
checkForTonHeatupCase()
setupApprovalNeeded()
setupIsAnyTokenStaked()
checkIfSubtractAvailable()
@ -1277,6 +1266,26 @@ internal class StakingModel @Inject constructor(
)
}
private suspend fun checkForTonHeatupCase() {
val isAccountInitializedNewValue = checkAccountInitializedUseCase.invoke(
userWalletId = userWalletId,
network = cryptoCurrencyStatus.currency.network,
).getOrElse {
Timber.e(it)
false
}
if (!isAccountInitializedNewValue && isAccountInitialized) {
isTonHeatupCase = true
}
isAccountInitialized = isAccountInitializedNewValue
if (isTopHeatupCase()) {
updateNotifications()
}
}
private fun isExplicitExit(balanceType: BalanceType, pendingAction: PendingAction?): Boolean {
return balanceType == BalanceType.STAKED && pendingAction?.type?.isRestake == false
}
@ -1296,11 +1305,11 @@ internal class StakingModel @Inject constructor(
.getOrElse { false }
}
private fun isCaseWithUnitializedTonAccount(): Boolean {
private fun isTopHeatupCase(): Boolean {
if (!::cryptoCurrencyStatus.isInitialized) return false
return value.currentStep == StakingStep.Confirmation &&
isTon(cryptoCurrencyStatus.currency.network.rawId) &&
!isAccountInitialized
isTonHeatupCase
}
private companion object {

View file

@ -4,7 +4,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.tokens.model.analytics.TokenSwapPromoAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
@ -38,8 +38,8 @@ internal class TokenDetailsNotificationsAnalyticsSender(
-> TokenDetailsAnalyticsEvent.Notice.NotEnoughFee(
currency = cryptoCurrency,
)
is TokenDetailsNotification.SwapPromo -> TokenSwapPromoAnalyticsEvent.NoticePromotionBanner(
program = TokenSwapPromoAnalyticsEvent.Program.Empty, // Use it on new promo action
is TokenDetailsNotification.SwapPromo -> PromoAnalyticsEvent.NoticePromotionBanner(
program = PromoAnalyticsEvent.Program.Empty, // Use it on new promo action
source = AnalyticsParam.ScreensSources.Token,
)
is TokenDetailsNotification.KaspaIncompleteTransactionWarning -> TokenDetailsAnalyticsEvent.Notice.Reveal(

View file

@ -847,10 +847,10 @@ internal class TokenDetailsModel @Inject constructor(
modelScope.launch(dispatchers.main) {
shouldShowPromoTokenUseCase.neverToShow(promoId)
analyticsEventsHandler.send(
TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
PromoAnalyticsEvent.PromotionBannerClicked(
source = AnalyticsParam.ScreensSources.Token,
program = TokenSwapPromoAnalyticsEvent.Program.Empty, // Use it on new promo action
action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed,
program = PromoAnalyticsEvent.Program.Empty, // Use it on new promo action
action = PromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed,
),
)
}
@ -860,10 +860,10 @@ internal class TokenDetailsModel @Inject constructor(
modelScope.launch(dispatchers.main) {
shouldShowPromoTokenUseCase.neverToShow(promoId)
analyticsEventsHandler.send(
TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
PromoAnalyticsEvent.PromotionBannerClicked(
source = AnalyticsParam.ScreensSources.Token,
program = TokenSwapPromoAnalyticsEvent.Program.Empty, // Use it on new promo action
action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Clicked,
program = PromoAnalyticsEvent.Program.Empty, // Use it on new promo action
action = PromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Clicked,
),
)
}

View file

@ -33,7 +33,9 @@ import com.tangem.domain.settings.NeverToSuggestRateAppUseCase
import com.tangem.domain.settings.RemindToRateAppLaterUseCase
import com.tangem.domain.staking.StakingIdFactory
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
import com.tangem.domain.tokens.model.analytics.TokenSwapPromoAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent.Program
import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent.PromotionBannerClicked
import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType
import com.tangem.domain.wallets.models.UnlockWalletsError
import com.tangem.domain.wallets.usecase.*
@ -327,11 +329,12 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
analyticsEventHandler.send(
when (promoId) {
PromoId.Referral -> MainScreen.ReferralPromoButtonDismiss
PromoId.Sepa -> TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
PromoId.Sepa -> PromotionBannerClicked(
source = AnalyticsParam.ScreensSources.Main,
program = TokenSwapPromoAnalyticsEvent.Program.Sepa,
action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Closed,
program = Program.Sepa,
action = PromotionBannerClicked.BannerAction.Closed,
)
PromoId.VisaPresale -> PromoAnalyticsEvent.VisaWaitlistPromoDismiss
},
)
@ -349,10 +352,10 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
}
PromoId.Sepa -> {
analyticsEventHandler.send(
TokenSwapPromoAnalyticsEvent.PromotionBannerClicked(
PromotionBannerClicked(
source = AnalyticsParam.ScreensSources.Main,
program = TokenSwapPromoAnalyticsEvent.Program.Sepa,
action = TokenSwapPromoAnalyticsEvent.PromotionBannerClicked.BannerAction.Clicked,
program = Program.Sepa,
action = PromotionBannerClicked.BannerAction.Clicked,
),
)
cryptoCurrency ?: return
@ -365,6 +368,10 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
),
)
}
PromoId.VisaPresale -> {
analyticsEventHandler.send(PromoAnalyticsEvent.VisaWaitlistPromoJoin)
urlOpener.openUrl(VISA_PROMO_LINK)
}
}
}
@ -575,4 +582,10 @@ internal class WalletWarningsClickIntentsImplementor @Inject constructor(
}
}
}
private companion object {
const val VISA_PROMO_LINK = "https://tangem.com/en/cardwaitlist/?utm_source=tangem-app-banner" +
"&utm_medium=banner" +
"&utm_campaign=tangempaywaitlist"
}
}

View file

@ -46,26 +46,6 @@ sealed class WalletScreenAnalyticsEvent {
)
}
sealed class Token(
event: String,
params: Map<String, String> = mapOf(),
) : AnalyticsEvent(category = "Token", event = event, params = params) {
class PolkadotAccountReset(hasReset: Boolean) : Token(
event = "Polkadot Account Reset",
params = mapOf(
AnalyticsParam.STATE to if (hasReset) "Yes" else "No",
),
)
class PolkadotImmortalTransactions(hasImmortalTransaction: Boolean) : Token(
event = "Polkadot Immortal Transactions",
params = mapOf(
AnalyticsParam.STATE to if (hasImmortalTransaction) "Yes" else "No",
),
)
}
sealed class MainScreen(
event: String,
params: Map<String, String> = mapOf(),

View file

@ -4,8 +4,8 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.tokens.model.analytics.TokenSwapPromoAnalyticsEvent.*
import com.tangem.domain.tokens.model.analytics.TokenSwapPromoAnalyticsEvent.Program
import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.PromoAnalyticsEvent.Program
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent
import com.tangem.feature.wallet.presentation.wallet.analytics.WalletScreenAnalyticsEvent.MainScreen
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
@ -50,15 +50,16 @@ internal class WalletWarningsAnalyticsSender @Inject constructor(
is WalletNotification.RateApp -> MainScreen.HowDoYouLikeTangem
is WalletNotification.Critical.BackupError -> MainScreen.BackupError
is WalletNotification.NoteMigration -> MainScreen.NotePromo
is WalletNotification.SwapPromo -> NoticePromotionBanner(
is WalletNotification.SwapPromo -> PromoAnalyticsEvent.NoticePromotionBanner(
source = AnalyticsParam.ScreensSources.Main,
program = Program.Empty, // Use it on new promo action
)
is WalletNotification.Sepa -> NoticePromotionBanner(
is WalletNotification.Sepa -> PromoAnalyticsEvent.NoticePromotionBanner(
source = AnalyticsParam.ScreensSources.Main,
program = Program.Sepa,
)
is WalletNotification.ReferralPromo -> MainScreen.ReferralPromo
is WalletNotification.VisaPresalePromo -> PromoAnalyticsEvent.VisaWaitlistPromo
is WalletNotification.UnlockWallets -> null // See [SelectedWalletAnalyticsSender]
is WalletNotification.Informational.NoAccount,
is WalletNotification.Warning.LowSignatures,

View file

@ -97,7 +97,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
isReadyToShowRateAppUseCase(),
isNeedToBackupUseCase(userWallet.walletId),
seedPhraseNotificationUseCase(userWalletId = userWallet.walletId),
shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.Referral),
shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.VisaPresale),
shouldShowPromoWalletUseCase(userWalletId = userWallet.walletId, promoId = PromoId.Sepa),
notificationsRepository.getShouldShowNotification(NotificationId.EnablePushesReminderNotification.key),
) { array -> array }
@ -109,7 +109,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
val isReadyToShowRating = array[1] as Boolean
val isNeedToBackup = array[2] as Boolean
val seedPhraseIssueStatus = array[3] as SeedPhraseNotificationsStatus
val shouldShowReferralPromo = array[4] as Boolean
val shouldShowVisaPromo = array[4] as Boolean
val shouldShowSepaBanner = array[5] as Boolean
val shouldShowEnablePushesReminderNotification = array[6] as Boolean
@ -120,7 +120,7 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
addFinishWalletActivationNotification(userWallet, totalFiatBalance, clickIntents)
addReferralPromoNotification(cardTypesResolver, clickIntents, shouldShowReferralPromo)
addVisaPresalePromoNotification(clickIntents, shouldShowVisaPromo)
addSepaPromoNotification(userWallet, clickIntents, shouldShowSepaBanner)
@ -274,17 +274,16 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
.map(CryptoCurrencyStatus::currency)
}
private fun MutableList<WalletNotification>.addReferralPromoNotification(
cardTypesResolver: CardTypesResolver?,
private fun MutableList<WalletNotification>.addVisaPresalePromoNotification(
clickIntents: WalletClickIntents,
shouldShowPromo: Boolean,
) {
addIf(
element = WalletNotification.ReferralPromo(
onCloseClick = { clickIntents.onClosePromoClick(promoId = PromoId.Referral) },
onClick = { clickIntents.onPromoClick(promoId = PromoId.Referral) },
element = WalletNotification.VisaPresalePromo(
onCloseClick = { clickIntents.onClosePromoClick(promoId = PromoId.VisaPresale) },
onClick = { clickIntents.onPromoClick(promoId = PromoId.VisaPresale) },
),
condition = shouldShowPromo && (cardTypesResolver == null || cardTypesResolver.isTangemWallet()),
condition = shouldShowPromo,
)
}

View file

@ -2,17 +2,17 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.nft.GetNFTCollectionsUseCase
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender
@ -21,7 +21,6 @@ import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenList
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.*
import com.tangem.feature.wallet.presentation.account.AccountDependencies
@Suppress("LongParameterList")
@ModelScoped
@ -38,7 +37,6 @@ internal class MultiWalletContentLoader(
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val walletsRepository: WalletsRepository,
@ -59,7 +57,6 @@ internal class MultiWalletContentLoader(
tokenListStore = tokenListStore,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
accountDependencies = accountDependencies,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingApyFlowUseCase = stakingApyFlowUseCase,

View file

@ -5,7 +5,6 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.nft.GetNFTCollectionsUseCase
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
@ -35,7 +34,6 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val walletsRepository: WalletsRepository,
@ -59,7 +57,6 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
getStoryContentUseCase = getStoryContentUseCase,
shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase,
walletsRepository = walletsRepository,

View file

@ -4,7 +4,6 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
@ -31,7 +30,6 @@ internal class SingleWalletWithTokenContentLoader(
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val tokenListStore: MultiWalletTokenListStore,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val accountDependencies: AccountDependencies,
@ -49,7 +47,6 @@ internal class SingleWalletWithTokenContentLoader(
walletWithFundsChecker = walletWithFundsChecker,
tokenListStore = tokenListStore,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
accountDependencies = accountDependencies,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingApyFlowUseCase = stakingApyFlowUseCase,

View file

@ -5,7 +5,6 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
@ -32,7 +31,6 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
private val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val accountDependencies: AccountDependencies,
@ -52,7 +50,6 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
runPolkadotAccountHealthCheckUseCase = runPolkadotAccountHealthCheckUseCase,
getStoryContentUseCase = getStoryContentUseCase,
shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase,
accountDependencies = accountDependencies,

View file

@ -298,6 +298,23 @@ sealed class WalletNotification(val config: NotificationConfig) {
),
)
data class VisaPresalePromo(
val onCloseClick: () -> Unit,
val onClick: () -> Unit,
) : WalletNotification(
config = NotificationConfig(
title = resourceReference(R.string.notification_visa_waitlist_promo_title),
subtitle = resourceReference(R.string.notification_visa_waitlist_promo_text),
iconResId = R.drawable.img_visa_waitlist_promo,
onCloseClick = onCloseClick,
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = resourceReference(R.string.notification_referral_promo_button),
onClick = onClick,
),
iconSize = 54.dp,
),
)
data class Sepa(
val onCloseClick: () -> Unit,
val onClick: () -> Unit,

View file

@ -15,7 +15,6 @@ import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
@ -43,7 +42,6 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
protected abstract val tokenListAnalyticsSender: TokenListAnalyticsSender
protected abstract val walletWithFundsChecker: WalletWithFundsChecker
protected abstract val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase
protected abstract val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase
protected abstract val accountDependencies: AccountDependencies
protected abstract val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase
protected abstract val stakingApyFlowUseCase: StakingApyFlowUseCase
@ -80,8 +78,6 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
coroutineScope.launch {
onTokenListReceived(maybeTokenList)
}.saveIn(onTokenListReceivedJobHolder)
coroutineScope.launch { startCheck(maybeTokenList) }
},
flow2 = appCurrencyFlow(),
flow3 = yieldSupplyApyFlow(),
@ -137,20 +133,6 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
walletWithFundsChecker.check(tokenList)
}
private suspend fun startCheck(maybeTokenList: Lce<TokenListError, TokenList>) {
// Run Polkadot account health check
maybeTokenList.getOrNull()?.let { tokenList ->
tokenList
.flattenCurrencies()
.forEach {
runPolkadotAccountHealthCheckUseCase(
userWalletId = userWallet.walletId,
network = it.currency.network,
)
}
}
}
private fun createAccountListFlow(coroutineScope: CoroutineScope): Flow<*> = combine6(
flow1 = accountListFlow(coroutineScope)
.onEach { accountStatusList ->
@ -161,14 +143,7 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
)
}.saveIn(sendAnalyticsJobHolder)
}
.distinctUntilChanged()
.onEach { accountList ->
// todo account see[onAccountListReceived]
// coroutineScope.launch { onAccountListReceived() }.saveIn(onTokenListReceivedJobHolder)
accountList.flattenTokens()
.forEach { tokenList -> startCheck(Lce.Content(tokenList)) }
},
.distinctUntilChanged(),
flow2 = appCurrencyFlow(),
flow3 = accountDependencies.expandedAccountsHolder.expandedAccounts(userWallet),
flow4 = accountDependencies.isAccountsModeEnabledUseCase(),

View file

@ -12,7 +12,6 @@ import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
@ -34,7 +33,6 @@ internal class MultiWalletTokenListSubscriber(
override val tokenListAnalyticsSender: TokenListAnalyticsSender,
override val walletWithFundsChecker: WalletWithFundsChecker,
override val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
override val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
override val accountDependencies: AccountDependencies,
override val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
override val stakingApyFlowUseCase: StakingApyFlowUseCase,

View file

@ -8,7 +8,6 @@ import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.tokens.RunPolkadotAccountHealthCheckUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
@ -30,7 +29,6 @@ internal class SingleWalletWithTokenListSubscriber(
override val tokenListAnalyticsSender: TokenListAnalyticsSender,
override val walletWithFundsChecker: WalletWithFundsChecker,
override val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
override val runPolkadotAccountHealthCheckUseCase: RunPolkadotAccountHealthCheckUseCase,
override val accountDependencies: AccountDependencies,
override val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
override val stakingApyFlowUseCase: StakingApyFlowUseCase,

View file

@ -77,12 +77,26 @@ sealed class YieldSupplyAnalytics(
),
)
data object ButtonFeePolicy : YieldSupplyAnalytics(
data class ButtonFeePolicy(
val token: String,
val blockchain: String,
) : YieldSupplyAnalytics(
event = "Button - Fee Policy",
params = mapOf(
TOKEN_PARAM to token,
BLOCKCHAIN to blockchain,
),
)
data object EarnInProgressScreen : YieldSupplyAnalytics(
data class EarnInProgressScreen(
val token: String,
val blockchain: String,
) : YieldSupplyAnalytics(
event = "Earn In Progress Screen",
params = mapOf(
TOKEN_PARAM to token,
BLOCKCHAIN to blockchain,
),
)
data object FundsEarned : YieldSupplyAnalytics(
@ -162,10 +176,10 @@ sealed class YieldSupplyAnalytics(
val errorDescription: String?,
) : YieldSupplyAnalytics(
event = "Earn Errors",
params = buildMap {
ACTION to action
ERROR_DESCRIPTION to errorDescription.orEmpty()
},
params = mapOf(
ACTION to action.value,
ERROR_DESCRIPTION to errorDescription.orEmpty(),
),
)
data object ApyChartViewed : YieldSupplyAnalytics(
@ -184,6 +198,7 @@ sealed class YieldSupplyAnalytics(
)
enum class Action(val value: String) {
Start("Start"),
Approve("Approve"),
Stop("Stop"),
}

View file

@ -5,7 +5,6 @@ import com.tangem.blockchain.common.TransactionData
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.extensions.TextReference
import kotlinx.collections.immutable.ImmutableList
import java.math.BigDecimal
@Immutable
internal sealed class YieldSupplyFeeUM {
@ -31,5 +30,4 @@ internal data class YieldSupplyActionUM(
val yieldSupplyFeeUM: YieldSupplyFeeUM,
val isPrimaryButtonEnabled: Boolean,
val isTransactionSending: Boolean,
val maxFee: BigDecimal = BigDecimal.ZERO,
)

View file

@ -20,6 +20,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
@ -40,6 +41,7 @@ import com.tangem.utils.StringsSigns
internal fun YieldSupplyBlockContent(yieldSupplyUM: YieldSupplyUM, modifier: Modifier = Modifier) {
AnimatedContent(
targetState = yieldSupplyUM,
contentKey = { it::class },
) { supplyUM ->
when (supplyUM) {
is YieldSupplyUM.Available -> SupplyAvailable(supplyUM, modifier)
@ -90,6 +92,7 @@ private fun SupplyUnavailable(modifier: Modifier = Modifier) {
)
}
@Suppress("LongMethod")
@Composable
private fun SupplyContent(supplyUM: YieldSupplyUM.Content, modifier: Modifier = Modifier) {
Row(
@ -114,21 +117,30 @@ private fun SupplyContent(supplyUM: YieldSupplyUM.Content, modifier: Modifier =
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
Text(
modifier = Modifier.weight(1.0f, fill = false),
text = supplyUM.title.resolveReference(),
style = TangemTheme.typography.subtitle1,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = TangemTheme.colors.text.primary1,
)
Text(
text = StringsSigns.DOT,
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.tertiary,
)
Text(
text = supplyUM.rewardsApy.resolveReference(),
style = TangemTheme.typography.subtitle1,
maxLines = 1,
color = TangemTheme.colors.text.accent,
)
AnimatedVisibility(supplyUM.rewardsApy != TextReference.EMPTY) {
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
Text(
text = StringsSigns.DOT,
style = TangemTheme.typography.subtitle1,
color = TangemTheme.colors.text.tertiary,
)
Text(
text = supplyUM.rewardsApy.resolveReference(),
style = TangemTheme.typography.subtitle1,
maxLines = 1,
color = TangemTheme.colors.text.accent,
)
}
}
}
Text(
text = supplyUM.subtitle.resolveReference(),
@ -337,17 +349,17 @@ private class PreviewProvider : PreviewParameterProvider<YieldSupplyUM> {
onClick = {},
),
YieldSupplyUM.Content(
title = stringReference("Aave lending is active"),
title = stringReference("Aave l"),
subtitle = stringReference("Interest accrues automatically"),
rewardsApy = stringReference("5.1 % APY"),
rewardsApy = stringReference("APY 5.1%"),
onClick = {},
apy = "5.1",
showWarningIcon = false,
),
YieldSupplyUM.Content(
title = stringReference("Aave lending is active"),
title = stringReference("Aave lending is active "),
subtitle = stringReference("Interest accrues automatically"),
rewardsApy = stringReference("5.1 % APY"),
rewardsApy = stringReference("APY 5.1%"),
onClick = {},
apy = "5.1",
showWarningIcon = true,

View file

@ -6,6 +6,8 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -29,9 +31,7 @@ import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.yield.supply.impl.R
import com.tangem.features.yield.supply.impl.promo.entity.YieldSupplyPromoUM
import com.tangem.features.yield.supply.impl.promo.model.YieldSupplyPromoClickIntents
import com.tangem.utils.StringsSigns
@Suppress("MagicNumber")
@Composable
internal fun YieldSupplyPromoContent(
yieldSupplyPromoUM: YieldSupplyPromoUM,
@ -39,50 +39,18 @@ internal fun YieldSupplyPromoContent(
modifier: Modifier = Modifier,
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
.background(color = TangemTheme.colors.background.tertiary)
.fillMaxWidth()
.fillMaxSize()
.imePadding()
.systemBarsPadding()
.padding(horizontal = 16.dp),
.systemBarsPadding(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
YieldStatusAppBar(
onBackClick = clickIntents::onBackClick,
onHowItWorksClick = clickIntents::onHowItWorksClick,
)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(horizontal = 20.dp),
) {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.ic_analytics_up_24),
tint = TangemTheme.colors.icon.accent,
contentDescription = null,
modifier = Modifier
.background(TangemTheme.colors.icon.accent.copy(0.1f), CircleShape)
.padding(12.dp)
.size(32.dp),
)
SpacerH(20.dp)
Text(
text = yieldSupplyPromoUM.title.resolveReference(),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
)
SpacerH8()
Label(
state = LabelUM(
text = yieldSupplyPromoUM.subtitle,
style = LabelStyle.REGULAR,
icon = R.drawable.ic_information_24,
onIconClick = clickIntents::onApyInfoClick,
),
)
SpacerH32()
PromoItems()
}
SpacerHMax()
Content(yieldSupplyPromoUM = yieldSupplyPromoUM, clickIntents = clickIntents)
YieldSupplyTosText(
tosLink = yieldSupplyPromoUM.tosLink,
policyLink = yieldSupplyPromoUM.policyLink,
@ -91,16 +59,72 @@ internal fun YieldSupplyPromoContent(
PrimaryButton(
text = stringResourceSafe(R.string.yield_module_start_earning),
onClick = clickIntents::onStartEarningClick,
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.padding(
start = 16.dp,
end = 16.dp,
bottom = 8.dp,
)
.fillMaxWidth(),
)
}
}
@Suppress("MagicNumber")
@Composable
private fun ColumnScope.Content(yieldSupplyPromoUM: YieldSupplyPromoUM, clickIntents: YieldSupplyPromoClickIntents) {
Box(modifier = Modifier.weight(1f)) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 16.dp)
.verticalScroll(rememberScrollState()),
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(horizontal = 20.dp),
) {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.ic_analytics_up_24),
tint = TangemTheme.colors.icon.accent,
contentDescription = null,
modifier = Modifier
.background(TangemTheme.colors.icon.accent.copy(0.1f), CircleShape)
.padding(12.dp)
.size(32.dp),
)
SpacerH(20.dp)
Text(
text = yieldSupplyPromoUM.title.resolveReference(),
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
)
SpacerH8()
Label(
state = LabelUM(
text = yieldSupplyPromoUM.subtitle,
style = LabelStyle.REGULAR,
icon = R.drawable.ic_information_24,
onIconClick = clickIntents::onApyInfoClick,
),
)
SpacerH32()
PromoItems()
}
SpacerH32()
}
Fade(
backgroundColor = TangemTheme.colors.background.tertiary,
modifier = Modifier.align(Alignment.BottomCenter),
)
SpacerH8()
}
}
@Composable
private fun YieldStatusAppBar(onBackClick: () -> Unit, onHowItWorksClick: () -> Unit) {
Row(
modifier = Modifier.padding(vertical = 16.dp),
modifier = Modifier.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
@ -166,7 +190,12 @@ private fun PromoItem(@DrawableRes icon: Int, title: TextReference, subtitle: Te
}
@Composable
private fun YieldSupplyTosText(tosLink: String, policyLink: String, onClick: (String) -> Unit) {
private fun YieldSupplyTosText(
tosLink: String,
policyLink: String,
onClick: (String) -> Unit,
modifier: Modifier = Modifier,
) {
val tosTitle = stringResourceSafe(R.string.common_terms_of_use)
val policyTitle = stringResourceSafe(R.string.common_privacy_policy)
val fullString = stringResourceSafe(id = R.string.yield_module_promo_screen_terms_disclaimer, tosTitle, policyTitle)
@ -175,8 +204,6 @@ private fun YieldSupplyTosText(tosLink: String, policyLink: String, onClick: (St
Text(
text = buildAnnotatedString {
append(StringsSigns.POINT_SIGN)
appendSpace()
append(fullString.substring(0, tosIndex))
withLink(
link = LinkAnnotation.Clickable(
@ -207,7 +234,7 @@ private fun YieldSupplyTosText(tosLink: String, policyLink: String, onClick: (St
textAlign = TextAlign.Center,
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier
modifier = modifier
.fillMaxWidth()
.padding(16.dp),
)

View file

@ -45,7 +45,7 @@ import javax.inject.Inject
internal class YieldSupplyActiveModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
analyticsHandler: AnalyticsEventHandler,
private val analyticsHandler: AnalyticsEventHandler,
private val yieldSupplyGetProtocolBalanceUseCase: YieldSupplyGetProtocolBalanceUseCase,
private val yieldSupplyGetTokenStatusUseCase: YieldSupplyGetTokenStatusUseCase,
private val yieldSupplyMinAmountUseCase: YieldSupplyMinAmountUseCase,
@ -82,7 +82,7 @@ internal class YieldSupplyActiveModel @Inject constructor(
init {
analyticsHandler.send(
YieldSupplyAnalytics.EarningScreenInfoOpened(
YieldSupplyAnalytics.EarnInProgressScreen(
token = cryptoCurrency.symbol,
blockchain = cryptoCurrency.network.name,
),
@ -189,6 +189,12 @@ internal class YieldSupplyActiveModel @Inject constructor(
return if (notDepositedAmount > BigDecimal.ZERO) {
val formattedAmount =
notDepositedAmount.format { crypto(symbol = "", decimals = cryptoCurrencyStatus.currency.decimals) }
analyticsHandler.send(
YieldSupplyAnalytics.NoticeAmountNotDeposited(
token = cryptoCurrency.symbol,
blockchain = cryptoCurrency.network.name,
),
)
NotificationUM.Warning.YieldSupplyNotAllAmountSupplied(
formattedAmount = formattedAmount,
symbol = cryptoCurrency.symbol,
@ -242,7 +248,8 @@ internal class YieldSupplyActiveModel @Inject constructor(
cryptoCurrencyStatus = cryptoStatus,
appCurrency = appCurrency,
feeValue = currentFee,
maxNetworkFee = maxFee,
maxNetworkFee = maxFee.second,
analyticsHandler = analyticsHandler,
),
)
} else {

View file

@ -1,5 +1,6 @@
package com.tangem.features.yield.supply.impl.subcomponents.active.model.transformers
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
@ -9,6 +10,7 @@ import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics
import com.tangem.features.yield.supply.impl.R
import com.tangem.features.yield.supply.impl.subcomponents.active.entity.YieldSupplyActiveContentUM
import com.tangem.utils.transformer.Transformer
@ -22,6 +24,7 @@ internal class YieldSupplyActiveFeeContentTransformer(
private val appCurrency: AppCurrency,
private val feeValue: BigDecimal,
private val maxNetworkFee: BigDecimal,
private val analyticsHandler: AnalyticsEventHandler,
) : Transformer<YieldSupplyActiveContentUM> {
override fun transform(prevState: YieldSupplyActiveContentUM): YieldSupplyActiveContentUM {
@ -48,6 +51,15 @@ internal class YieldSupplyActiveFeeContentTransformer(
val isHighFee = feeValue > maxNetworkFee
if (isHighFee) {
analyticsHandler.send(
YieldSupplyAnalytics.NoticeHighNetworkFee(
token = cryptoCurrency.symbol,
blockchain = cryptoCurrency.network.name,
),
)
}
return prevState.copy(
currentFee = stringReference(tokenFiatFeeValueText),
feeDescription = feeNoteValue,

View file

@ -4,6 +4,8 @@ import arrow.core.getOrElse
import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -132,6 +134,12 @@ internal class YieldSupplyApproveModel @Inject constructor(
ifLeft = { error ->
Timber.e(error.toString())
uiState.update(YieldSupplyTransactionReadyTransformer)
analyticsEventHandler.send(
YieldSupplyAnalytics.EarnErrors(
action = YieldSupplyAnalytics.Action.Approve,
errorDescription = error.getAnalyticsDescription(),
),
)
yieldSupplyAlertFactory.getSendTransactionErrorState(
error = error,
popBack = params.callback::onBackClick,
@ -147,6 +155,17 @@ internal class YieldSupplyApproveModel @Inject constructor(
)
},
ifRight = {
val event = AnalyticsParam.TxSentFrom.Earning(
blockchain = cryptoCurrency.network.name,
token = cryptoCurrency.symbol,
feeType = AnalyticsParam.FeeType.Normal,
)
analyticsEventHandler.send(
Basic.TransactionSent(
sentFrom = event,
memoType = Basic.TransactionSent.MemoType.Null,
),
)
analyticsEventHandler.send(YieldSupplyAnalytics.ApprovalAction(
token = cryptoCurrency.symbol,
blockchain = cryptoCurrency.network.name,

View file

@ -59,7 +59,10 @@ internal class YieldSupplyStartEarningEntryModel @Inject constructor(
override fun onFeePolicyClick() {
analyticsEventHandler.send(
YieldSupplyAnalytics.ButtonFeePolicy,
YieldSupplyAnalytics.ButtonFeePolicy(
token = params.cryptoCurrency.symbol,
blockchain = params.cryptoCurrency.network.name,
),
)
router.push(YieldSupplyStartEarningRoute.FeePolicy)
}

View file

@ -3,16 +3,16 @@ package com.tangem.features.yield.supply.impl.subcomponents.startearning.model
import arrow.core.getOrElse
import com.tangem.blockchain.common.TransactionSender
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
@ -61,8 +61,8 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
private val yieldSupplyNotificationsUpdateTrigger: YieldSupplyNotificationsUpdateTrigger,
private val yieldSupplyAlertFactory: YieldSupplyAlertFactory,
private val yieldSupplyActivateUseCase: YieldSupplyActivateUseCase,
private val yieldSupplyGetTokenStatusUseCase: YieldSupplyGetTokenStatusUseCase,
private val yieldSupplyMinAmountUseCase: YieldSupplyMinAmountUseCase,
private val yieldSupplyGetMaxFeeUseCase: YieldSupplyGetMaxFeeUseCase,
private val yieldSupplyRepository: YieldSupplyRepository,
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
@ -130,11 +130,8 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
}
}
private suspend fun getMaxFee(): BigDecimal? {
if (uiState.value.maxFee != BigDecimal.ZERO) return uiState.value.maxFee
val yieldTokenStatus = yieldSupplyGetTokenStatusUseCase(cryptoCurrency as CryptoCurrency.Token)
.getOrNull()
return yieldTokenStatus?.maxFeeNative?.parseToBigDecimal(cryptoCurrency.decimals)
private suspend fun getMaxFeePair(): Pair<BigDecimal, BigDecimal>? {
return yieldSupplyGetMaxFeeUseCase(userWallet, cryptoCurrencyStatus).getOrNull()
}
private suspend fun onLoadFee() {
@ -144,11 +141,10 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
it.copy(yieldSupplyFeeUM = YieldSupplyFeeUM.Loading)
}
val maxFee = if (uiState.value.maxFee == BigDecimal.ZERO) {
getMaxFee()
} else {
uiState.value.maxFee
} ?: return
val maxFeePair = getMaxFeePair() ?: return
val maxFee = maxFeePair.first
val maxFeeFiat = maxFeePair.second
val transactionListData = yieldSupplyStartEarningUseCase(
userWalletId = userWallet.walletId,
@ -189,6 +185,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
val feeSum = updatedTransactionList.sumOf {
it.fee?.amount?.value.orZero()
}
uiState.update(
YieldSupplyStartEarningFeeContentTransformer(
cryptoCurrencyStatus = cryptoCurrencyStatusFlow.value,
@ -197,6 +194,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
updatedTransactionList = updatedTransactionList,
feeValue = feeSum,
maxNetworkFee = maxFee,
maxNetworkFeeFiat = maxFeeFiat,
minAmount = minAmount,
),
)
@ -232,7 +230,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
uiState.update(YieldSupplyTransactionReadyTransformer)
analytics.send(
YieldSupplyAnalytics.EarnErrors(
action = YieldSupplyAnalytics.Action.Approve,
action = YieldSupplyAnalytics.Action.Start,
errorDescription = error.getAnalyticsDescription(),
),
)
@ -252,7 +250,20 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
},
ifRight = {
yieldSupplyRepository.saveTokenProtocolStatus(cryptoCurrency, YieldSupplyEnterStatus.Enter)
val event = AnalyticsParam.TxSentFrom.Earning(
blockchain = cryptoCurrency.network.name,
token = cryptoCurrency.symbol,
feeType = AnalyticsParam.FeeType.Normal,
)
analytics.send(YieldSupplyAnalytics.FundsEarned)
yieldSupplyFeeUM.transactionDataList.forEach {
analytics.send(
Basic.TransactionSent(
sentFrom = event,
memoType = Basic.TransactionSent.MemoType.Null,
),
)
}
val address = cryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value
if (address != null) {

View file

@ -25,6 +25,7 @@ internal class YieldSupplyStartEarningFeeContentTransformer(
private val updatedTransactionList: List<TransactionData.Uncompiled>,
private val feeValue: BigDecimal,
private val maxNetworkFee: BigDecimal,
private val maxNetworkFeeFiat: BigDecimal,
private val minAmount: BigDecimal,
) : Transformer<YieldSupplyActionUM> {
override fun transform(prevState: YieldSupplyActionUM): YieldSupplyActionUM {
@ -42,14 +43,8 @@ internal class YieldSupplyStartEarningFeeContentTransformer(
val tokenFiatFee = feeFiat // same fiat amount
val tokenFiatFeeValueText = tokenFiatFee.format { fiat(appCurrency.code, appCurrency.symbol) }
val maxFiatFee = feeFiatRate?.let { rate ->
maxNetworkFee.multiply(rate)
}
val maxFeeCryptoValueText = tokenFiatRate?.let { rate ->
maxFiatFee?.divide(rate, cryptoCurrency.decimals, RoundingMode.HALF_UP)
}.format { crypto(cryptoCurrency) }
val maxFiatFeeValueText = maxFiatFee.format { fiat(appCurrency.code, appCurrency.symbol) }
val maxFeeCryptoValueText = maxNetworkFee.format { crypto(cryptoCurrency) }
val maxFiatFeeValueText = maxNetworkFeeFiat.format { fiat(appCurrency.code, appCurrency.symbol) }
val minAmountCryptoText = minAmount.format { crypto(cryptoCurrency) }
val minAmountFiat = tokenFiatRate?.let(minAmount::multiply)

View file

@ -2,6 +2,8 @@ package com.tangem.features.yield.supply.impl.subcomponents.stopearning.model
import arrow.core.getOrElse
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
@ -16,7 +18,9 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
import com.tangem.domain.transaction.usecase.GetFeeUseCase
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
import com.tangem.domain.yield.supply.INCREASE_GAS_LIMIT_FOR_SUPPLY
import com.tangem.domain.yield.supply.YieldSupplyRepository
import com.tangem.domain.yield.supply.increaseGasLimitBy
import com.tangem.domain.yield.supply.models.YieldSupplyEnterStatus
import com.tangem.domain.yield.supply.usecase.YieldSupplyDeactivateUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyStopEarningUseCase
@ -82,7 +86,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
val uiState: StateFlow<YieldSupplyActionUM>
field: MutableStateFlow<YieldSupplyActionUM> = MutableStateFlow(
YieldSupplyActionUM(
title = resourceReference(R.string.yield_module_stop_earning),
title = resourceReference(R.string.yield_module_stop_earning_sheet_title),
subtitle = resourceReference(
id = R.string.yield_module_stop_earning_sheet_description,
formatArgs = wrappedList(cryptoCurrency.symbol),
@ -168,6 +172,17 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
blockchain = cryptoCurrency.network.name,
),
)
val event = AnalyticsParam.TxSentFrom.Earning(
blockchain = cryptoCurrency.network.name,
token = cryptoCurrency.symbol,
feeType = AnalyticsParam.FeeType.Normal,
)
analytics.send(
Basic.TransactionSent(
sentFrom = event,
memoType = Basic.TransactionSent.MemoType.Null,
),
)
val address = cryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value
if (address != null) {
yieldSupplyDeactivateUseCase(cryptoCurrency, address)
@ -223,7 +238,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
}
},
ifRight = { fee ->
val fee = fee.normal
val fee = fee.normal.increaseGasLimitBy(INCREASE_GAS_LIMIT_FOR_SUPPLY)
val feeCryptoValue = fee.amount.value.orZero()
uiState.update(

View file

@ -5,7 +5,7 @@
# https://github.com/tangem/tangem-sdk-android/
# https://github.com/tangem/vico
tangemBlockchainSdk = "develop-1294"
tangemBlockchainSdk = "develop-1301"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-564"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^

View file

@ -26,5 +26,5 @@ internal enum class ProviderTypeIdMapping(val id: String, val providerType: Prov
KoinosPro(id = "koinospro", providerType = ProviderType.Koinos.KoinosPro),
AlephiumTangem(id = "tangemAlephium", providerType = ProviderType.Alephium.Tangem),
Blink(id = "blink", providerType = ProviderType.Blink),
Tatum(id = "tatum", providerType = ProviderType.Kusama.Tatum),
Tatum(id = "tatum", providerType = ProviderType.PolkadotLike.Tatum),
}