Updated on 2026-08-14

This commit is contained in:
Tangem 2024-03-05 09:24:26 +00:00
commit c50439d698
7 changed files with 52 additions and 35 deletions

View file

@ -8,11 +8,15 @@ internal class DelegatedKeystoreManager(
private val keystoreManagerProvider: Provider<KeystoreManager>, private val keystoreManagerProvider: Provider<KeystoreManager>,
) : KeystoreManager { ) : KeystoreManager {
override suspend fun authenticateAndGetKey(keyAlias: String): SecretKey? { override suspend fun get(keyAlias: String): SecretKey? {
return keystoreManagerProvider().authenticateAndGetKey(keyAlias) return keystoreManagerProvider().get(keyAlias)
} }
override suspend fun storeKey(keyAlias: String, key: SecretKey) { override suspend fun get(keyAliases: Collection<String>): Map<String, SecretKey> {
keystoreManagerProvider().storeKey(keyAlias, key) return keystoreManagerProvider().get(keyAliases)
}
override suspend fun store(keyAlias: String, key: SecretKey) {
return keystoreManagerProvider().store(keyAlias, key)
} }
} }

View file

@ -81,41 +81,38 @@ internal class BiometricUserWalletsKeysRepository(
} }
private suspend fun getAllInternal(): CompletionResult<List<UserWalletEncryptionKey>> { private suspend fun getAllInternal(): CompletionResult<List<UserWalletEncryptionKey>> {
return getUserWalletsIds() return catching {
.map { userWalletId -> val userWalletIds = getUserWalletsIds()
getEncryptionKey(userWalletId)
.doOnFailure { error ->
when (error) {
is TangemSdkError.UserCanceledAuthentication -> {
// If the user cancels biometric authentication, then cancel operation with error
return CompletionResult.Failure(error)
}
is TangemSdkError.KeystoreInvalidated -> {
// If the biometric cryptography key was invalidated,
// then delete all user wallets encryption keys and cancel operation with error
getUserWalletsIds().forEach { userWalletId ->
deleteEncryptionKey(userWalletId)
}
return CompletionResult.Failure(error) getEncryptionKeys(userWalletIds)
} }
.doOnFailure { error ->
when (error) {
is TangemSdkError.KeystoreInvalidated -> {
// If the biometric cryptography key was invalidated, then delete all encryption keys
getUserWalletsIds().forEach { userWalletId ->
deleteEncryptionKey(userWalletId)
} }
} }
} else -> Unit
.fold(listOf()) { acc, data -> }
if (data != null) acc + data else acc
} }
} }
private suspend fun getEncryptionKey(userWalletId: UserWalletId): CompletionResult<UserWalletEncryptionKey?> { private suspend fun getEncryptionKeys(userWalletsIds: List<UserWalletId>): List<UserWalletEncryptionKey> {
return catching { authenticatedStorage.get(StorageKey.UserWalletEncryptionKey(userWalletId).name) } val keys = userWalletsIds.map { userWalletId ->
.map { it.decodeToKey() } StorageKey.UserWalletEncryptionKey(userWalletId).name
}
return authenticatedStorage.get(keys).mapNotNull { (_, encodedData) ->
encodedData.decodeToKey()
}
} }
private suspend fun storeEncryptionKey(encryptionKey: UserWalletEncryptionKey): CompletionResult<Unit> { private suspend fun storeEncryptionKey(encryptionKey: UserWalletEncryptionKey): CompletionResult<Unit> {
return catching { return catching {
authenticatedStorage.store( authenticatedStorage.store(
key = StorageKey.UserWalletEncryptionKey(encryptionKey.walletId).name, keyAlias = StorageKey.UserWalletEncryptionKey(encryptionKey.walletId).name,
data = encryptionKey.encode(), data = encryptionKey.encode(),
) )
} }

View file

@ -3,10 +3,12 @@ package com.tangem.tap.proxy
import androidx.core.text.isDigitsOnly import androidx.core.text.isDigitsOnly
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tangem.Message import com.tangem.Message
import com.tangem.blockchain.blockchains.algorand.AlgorandTransactionExtras
import com.tangem.blockchain.blockchains.binance.BinanceTransactionExtras import com.tangem.blockchain.blockchains.binance.BinanceTransactionExtras
import com.tangem.blockchain.blockchains.cosmos.CosmosTransactionExtras import com.tangem.blockchain.blockchains.cosmos.CosmosTransactionExtras
import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras import com.tangem.blockchain.blockchains.ethereum.EthereumTransactionExtras
import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager
import com.tangem.blockchain.blockchains.hedera.HederaTransactionBuilder
import com.tangem.blockchain.blockchains.optimism.OptimismWalletManager import com.tangem.blockchain.blockchains.optimism.OptimismWalletManager
import com.tangem.blockchain.blockchains.stellar.StellarMemo import com.tangem.blockchain.blockchains.stellar.StellarMemo
import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras import com.tangem.blockchain.blockchains.stellar.StellarTransactionExtras
@ -138,6 +140,8 @@ class TransactionManagerImpl(
Blockchain.XRP -> memo.toLongOrNull()?.let { XrpTransactionBuilder.XrpTransactionExtras(it) } Blockchain.XRP -> memo.toLongOrNull()?.let { XrpTransactionBuilder.XrpTransactionExtras(it) }
Blockchain.Cosmos -> CosmosTransactionExtras(memo) Blockchain.Cosmos -> CosmosTransactionExtras(memo)
Blockchain.TON -> TonTransactionExtras(memo) Blockchain.TON -> TonTransactionExtras(memo)
Blockchain.Hedera -> HederaTransactionBuilder.HederaTransactionExtras(memo)
Blockchain.Algorand -> AlgorandTransactionExtras(memo)
else -> null else -> null
} }
} }

View file

@ -16,7 +16,7 @@ internal object AccountCreatorModule {
@Provides @Provides
@Singleton @Singleton
fun provideAccountCreator(authProvider: AuthProvider, @DevTangemApi tangemTechApi: TangemTechApi): AccountCreator { fun provideAccountCreator(authProvider: AuthProvider, tangemTechApi: TangemTechApi): AccountCreator {
return DefaultAccountCreator(authProvider, tangemTechApi) return DefaultAccountCreator(authProvider, tangemTechApi)
} }
} }

View file

@ -915,10 +915,10 @@ internal class StateBuilder(
) )
} }
fun addAlert(uiState: SwapStateHolder, onClick: () -> Unit): SwapStateHolder { fun addAlert(uiState: SwapStateHolder, message: TextReference? = null, onClick: () -> Unit): SwapStateHolder {
return uiState.copy( return uiState.copy(
alert = SwapWarning.GenericWarning( alert = SwapWarning.GenericWarning(
message = null, message = message,
onClick = onClick, onClick = onClick,
), ),
) )

View file

@ -9,6 +9,7 @@ import arrow.core.getOrElse
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic import com.tangem.core.analytics.models.Basic
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.utils.InputNumberFormatter import com.tangem.core.ui.utils.InputNumberFormatter
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.appcurrency.model.AppCurrency
@ -119,7 +120,7 @@ internal class SwapViewModel @Inject constructor(
val cryptoCurrencyStatus = val cryptoCurrencyStatus =
getCryptoCurrencyStatusUseCase(it.walletId, initialCryptoCurrency.id).getOrNull() getCryptoCurrencyStatusUseCase(it.walletId, initialCryptoCurrency.id).getOrNull()
if (cryptoCurrencyStatus == null) { if (cryptoCurrencyStatus == null) {
uiState = stateBuilder.addAlert(uiState, swapRouter::back) uiState = stateBuilder.addAlert(uiState = uiState, onClick = swapRouter::back)
} else { } else {
initialCryptoCurrencyStatus = cryptoCurrencyStatus initialCryptoCurrencyStatus = cryptoCurrencyStatus
initTokens() initTokens()
@ -482,7 +483,12 @@ internal class SwapViewModel @Inject constructor(
return return
} }
val fromCurrency = requireNotNull(dataState.fromCryptoCurrency) val fromCurrency = requireNotNull(dataState.fromCryptoCurrency)
val fee = requireNotNull(dataState.selectedFee) val fee = dataState.selectedFee
// TODO: unexpected crash for some users, this workaround to prevent app crash and follow to support
if (fee == null) {
makeDefaultAlert(TextReference.Str("Fee estimation error. Please send feedback to support."))
return
}
viewModelScope.launch(dispatchers.main) { viewModelScope.launch(dispatchers.main) {
runCatching(dispatchers.io) { runCatching(dispatchers.io) {
swapInteractor.onSwap( swapInteractor.onSwap(
@ -821,6 +827,12 @@ internal class SwapViewModel @Inject constructor(
} }
} }
private fun makeDefaultAlert(message: TextReference) {
uiState = stateBuilder.addAlert(uiState, message) {
uiState = stateBuilder.clearAlert(uiState)
}
}
@Suppress("LongMethod", "CyclomaticComplexMethod") @Suppress("LongMethod", "CyclomaticComplexMethod")
private fun createUiActions(): UiActions { private fun createUiActions(): UiActions {
return UiActions( return UiActions(

View file

@ -85,9 +85,9 @@ web3j = "4.10.1"
# endregion Other libraries # endregion Other libraries
# region Tangem # region Tangem
tangemBlockchainSdk = "develop-510" tangemBlockchainSdk = "develop-514"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-331" tangemCardSdk = "develop-332"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
# endregion Tangem # endregion Tangem