Updated on 2026-08-14
This commit is contained in:
parent
fa41036fca
commit
de6b0af228
18 changed files with 147 additions and 90 deletions
|
|
@ -3,11 +3,11 @@ package com.tangem.tap.common.analytics.converters
|
|||
import com.tangem.common.Converter
|
||||
import com.tangem.common.extensions.isZero
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.util.userWalletId
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Basic
|
||||
import com.tangem.tap.common.analytics.filters.BasicTopUpFilter
|
||||
import com.tangem.tap.domain.extensions.isMultiwalletAllowed
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
import com.tangem.tap.features.wallet.redux.WalletData
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
|
|
@ -29,7 +29,9 @@ class BasicSignInEventConverter(
|
|||
currency = cardCurrency,
|
||||
batch = scanResponse.card.batchId,
|
||||
).apply {
|
||||
filterData = scanResponse.card.userWalletId.stringValue
|
||||
filterData = UserWalletIdBuilder.scanResponse(scanResponse)
|
||||
.build()
|
||||
?.stringValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +45,7 @@ class BasicTopUpEventConverter(
|
|||
val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse) ?: return null
|
||||
|
||||
val data = BasicTopUpFilter.Data(
|
||||
walletId = scanResponse.card.userWalletId.stringValue,
|
||||
walletId = UserWalletIdBuilder.scanResponse(scanResponse).build()?.stringValue ?: "",
|
||||
cardBalanceState = AnalyticsParam.CardBalanceState.from(value.walletsDataFromStores),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import com.tangem.blockchain.common.WalletManager
|
|||
import com.tangem.blockchain.common.address.Address
|
||||
import com.tangem.domain.common.CardDTO
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.util.userWalletId
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
|
||||
class AdditionalFeedbackInfo {
|
||||
class EmailWalletInfo(
|
||||
|
|
@ -54,7 +54,7 @@ class AdditionalFeedbackInfo {
|
|||
cardFirmwareVersion = data.card.firmwareVersion.stringValue
|
||||
cardIssuer = data.card.issuer.name
|
||||
signedHashesCount = formatSignedHashes(data.card.wallets)
|
||||
userWalletId = data.card.userWalletId.stringValue
|
||||
userWalletId = UserWalletIdBuilder.scanResponse(data).build()?.stringValue ?: ""
|
||||
}
|
||||
|
||||
fun setWalletsInfo(walletManagers: List<WalletManager>) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.tap.domain.model
|
||||
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.util.UserWalletId
|
||||
|
||||
|
|
@ -33,23 +32,4 @@ data class UserWallet(
|
|||
|
||||
val isLocked: Boolean
|
||||
get() = scanResponse.card.wallets.isEmpty()
|
||||
}
|
||||
|
||||
/**
|
||||
* !!! Workaround !!!
|
||||
*
|
||||
* Calculate same [UserWalletId] for twins instead
|
||||
*
|
||||
* TODO: Remove after [REDACTED_JIRA]
|
||||
* */
|
||||
fun UserWallet.isTwinnedWith(other: UserWallet): Boolean {
|
||||
if (!scanResponse.isTangemTwins() || !other.scanResponse.isTangemTwins()) return false
|
||||
if (scanResponse.secondTwinPublicKey == null || other.scanResponse.secondTwinPublicKey == null) return false
|
||||
if (other.scanResponse.secondTwinPublicKey == scanResponse.card.wallets.firstOrNull()?.publicKey?.toHexString()) {
|
||||
return true
|
||||
}
|
||||
if (scanResponse.secondTwinPublicKey == other.scanResponse.card.wallets.firstOrNull()?.publicKey?.toHexString()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import com.tangem.domain.common.ScanResponse
|
|||
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
||||
import com.tangem.domain.common.TwinCardNumber
|
||||
import com.tangem.domain.common.TwinsHelper
|
||||
import com.tangem.domain.common.util.userWalletId
|
||||
import com.tangem.operations.attestation.OnlineCardVerifier
|
||||
import com.tangem.operations.attestation.TangemApi
|
||||
import com.tangem.tap.domain.model.UserWallet
|
||||
|
|
@ -49,16 +48,20 @@ class UserWalletBuilder(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun build(): UserWallet {
|
||||
suspend fun build(): UserWallet? {
|
||||
return with(scanResponse) {
|
||||
UserWallet(
|
||||
walletId = card.userWalletId,
|
||||
name = userWalletName,
|
||||
artworkUrl = loadArtworkUrl(card.cardId, card.cardPublicKey),
|
||||
cardsInWallet = backupCardsIds.plus(card.cardId),
|
||||
scanResponse = this,
|
||||
isMultiCurrency = isMultiCurrency,
|
||||
)
|
||||
UserWalletIdBuilder.scanResponse(scanResponse)
|
||||
.build()
|
||||
?.let {
|
||||
UserWallet(
|
||||
walletId = it,
|
||||
name = userWalletName,
|
||||
artworkUrl = loadArtworkUrl(card.cardId, card.cardPublicKey),
|
||||
cardsInWallet = backupCardsIds.plus(card.cardId),
|
||||
scanResponse = this,
|
||||
isMultiCurrency = isMultiCurrency,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
package com.tangem.tap.domain.model.builders
|
||||
|
||||
import com.tangem.common.extensions.calculateSha256
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.crypto.Secp256k1
|
||||
import com.tangem.domain.common.CardDTO
|
||||
import com.tangem.domain.common.ProductType
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
|
||||
import com.tangem.domain.common.extensions.calculateHmacSha256
|
||||
import com.tangem.domain.common.util.UserWalletId
|
||||
|
||||
class UserWalletIdBuilder private constructor(
|
||||
private val publicKey: ByteArray?,
|
||||
private val pairTwinPublicKey: ByteArray? = null,
|
||||
) {
|
||||
fun build(): UserWalletId? {
|
||||
val seed = if (publicKey != null) {
|
||||
if (pairTwinPublicKey != null) {
|
||||
Secp256k1.sum(publicKey, pairTwinPublicKey)
|
||||
} else {
|
||||
publicKey
|
||||
}
|
||||
} else null
|
||||
|
||||
return seed?.let {
|
||||
UserWalletId(value = calculateUserWalletId(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateUserWalletId(seed: ByteArray?): ByteArray? {
|
||||
val message = MESSAGE_FOR_WALLET_ID.toByteArray()
|
||||
val keyHash = seed?.calculateSha256()
|
||||
|
||||
return if (keyHash != null) {
|
||||
message.calculateHmacSha256(keyHash)
|
||||
} else null
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MESSAGE_FOR_WALLET_ID = "UserWalletID"
|
||||
|
||||
@Throws(IllegalArgumentException::class)
|
||||
fun card(card: CardDTO): UserWalletIdBuilder {
|
||||
require(!card.isTangemTwins) {
|
||||
"For twin cards use scanResponse to ID calculation"
|
||||
}
|
||||
|
||||
return UserWalletIdBuilder(findPublicKey(card.wallets))
|
||||
}
|
||||
|
||||
fun scanResponse(scanResponse: ScanResponse): UserWalletIdBuilder {
|
||||
return UserWalletIdBuilder(
|
||||
publicKey = findPublicKey(scanResponse.card.wallets),
|
||||
pairTwinPublicKey = when (scanResponse.productType) {
|
||||
ProductType.Twins -> scanResponse.secondTwinPublicKey?.hexToBytes()
|
||||
ProductType.Note,
|
||||
ProductType.Wallet,
|
||||
ProductType.SaltPay,
|
||||
-> null
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun findPublicKey(wallets: List<CardDTO.Wallet>): ByteArray? {
|
||||
return wallets.firstOrNull()
|
||||
?.publicKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,9 +6,9 @@ import com.tangem.common.services.Result
|
|||
import com.tangem.datasource.api.tangemTech.TangemTechService
|
||||
import com.tangem.datasource.api.tangemTech.UserTokensResponse
|
||||
import com.tangem.domain.common.CardDTO
|
||||
import com.tangem.domain.common.util.userWalletId
|
||||
import com.tangem.tap.common.AndroidFileReader
|
||||
import com.tangem.tap.domain.NoDataError
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
|
|
@ -24,7 +24,7 @@ class UserTokensRepository(
|
|||
private val networkService: UserTokensNetworkService,
|
||||
) {
|
||||
suspend fun getUserTokens(card: CardDTO): List<Currency> {
|
||||
val userId = card.userWalletId.stringValue
|
||||
val userId = getUserWalletId(card) ?: return emptyList()
|
||||
if (DemoHelper.isDemoCardId(card.cardId)) {
|
||||
return loadTokensOffline(card, userId).ifEmpty { loadDemoCurrencies() }
|
||||
}
|
||||
|
|
@ -47,14 +47,14 @@ class UserTokensRepository(
|
|||
}
|
||||
|
||||
suspend fun saveUserTokens(card: CardDTO, tokens: List<Currency>) {
|
||||
val userId = card.userWalletId.stringValue
|
||||
val userId = getUserWalletId(card) ?: return
|
||||
val userTokens = tokens.toUserTokensResponse()
|
||||
networkService.saveUserTokens(userId, userTokens)
|
||||
storageService.saveUserTokens(userId, userTokens)
|
||||
}
|
||||
|
||||
suspend fun removeUserTokens(card: CardDTO) {
|
||||
val userId = card.userWalletId.stringValue
|
||||
val userId = getUserWalletId(card) ?: return
|
||||
val userTokens = emptyList<Currency>().toUserTokensResponse()
|
||||
networkService.saveUserTokens(userId, userTokens)
|
||||
storageService.saveUserTokens(userId, userTokens)
|
||||
|
|
@ -70,7 +70,7 @@ class UserTokensRepository(
|
|||
}
|
||||
|
||||
suspend fun loadBlockchainsToDerive(card: CardDTO): List<BlockchainNetwork> {
|
||||
val userId = card.userWalletId.stringValue
|
||||
val userId = getUserWalletId(card) ?: return emptyList()
|
||||
val blockchainNetworks = loadTokensOffline(card, userId).toBlockchainNetworks()
|
||||
|
||||
if (DemoHelper.isDemoCardId(card.cardId)) {
|
||||
|
|
@ -103,6 +103,7 @@ class UserTokensRepository(
|
|||
coroutineScope { launch { networkService.saveUserTokens(userId = userId, tokens = userTokens) } }
|
||||
tokens
|
||||
}
|
||||
|
||||
else -> {
|
||||
val tokens = storageService.getUserTokens(userId) ?: storageService.getUserTokens(card)
|
||||
tokens.distinct()
|
||||
|
|
@ -114,6 +115,11 @@ class UserTokensRepository(
|
|||
return storageService.getUserTokens(userId) ?: storageService.getUserTokens(card)
|
||||
}
|
||||
|
||||
private fun getUserWalletId(card: CardDTO): String? {
|
||||
return UserWalletIdBuilder.card(card).build()
|
||||
?.stringValue
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val SORT_DEFAULT_VALUE = "manual"
|
||||
const val GROUP_DEFAULT_VALUE = "none"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.tangem.tap.domain.userWalletList.implementation
|
|||
import com.tangem.common.*
|
||||
import com.tangem.domain.common.util.UserWalletId
|
||||
import com.tangem.tap.domain.model.UserWallet
|
||||
import com.tangem.tap.domain.model.isTwinnedWith
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletListError
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletsListManager
|
||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||
|
|
@ -89,8 +88,7 @@ internal class BiometricUserWalletsListManager(
|
|||
} else {
|
||||
val isWalletSaved = state.value.userWallets
|
||||
.any {
|
||||
// Workaround, check [UserWallet.isTwinnedWith]
|
||||
it.cardsInWallet.contains(userWallet.cardId) || it.isTwinnedWith(userWallet)
|
||||
it.walletId == userWallet.walletId || it.cardsInWallet.contains(userWallet.cardId)
|
||||
}
|
||||
|
||||
if (isWalletSaved) {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package com.tangem.tap.domain.userWalletList.model
|
|||
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.tangem.domain.common.util.UserWalletId
|
||||
import com.tangem.domain.common.util.encryptionKey
|
||||
import com.tangem.tap.domain.model.UserWallet
|
||||
import com.tangem.tap.domain.userWalletList.utils.encryptionKey
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class UserWalletEncryptionKey(
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ import com.tangem.common.catching
|
|||
import com.tangem.common.mapFailure
|
||||
import com.tangem.common.services.secure.SecureStorage
|
||||
import com.tangem.domain.common.util.UserWalletId
|
||||
import com.tangem.domain.common.util.encryptionKey
|
||||
import com.tangem.tap.common.extensions.filterNotNull
|
||||
import com.tangem.tap.domain.model.UserWallet
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletListError
|
||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||
import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation
|
||||
import com.tangem.tap.domain.userWalletList.repository.UserWalletsSensitiveInformationRepository
|
||||
import com.tangem.tap.domain.userWalletList.utils.encryptionKey
|
||||
import com.tangem.tap.domain.userWalletList.utils.sensitiveInformation
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
|
|||
|
|
@ -1,24 +1,27 @@
|
|||
package com.tangem.domain.common.util
|
||||
package com.tangem.tap.domain.userWalletList.utils
|
||||
|
||||
import com.tangem.common.extensions.calculateSha256
|
||||
import com.tangem.domain.common.CardDTO
|
||||
import com.tangem.domain.common.extensions.calculateHmacSha256
|
||||
|
||||
val CardDTO.userWalletId: UserWalletId
|
||||
get() = UserWalletId(findWalletPublicKey(wallets))
|
||||
internal val CardDTO.encryptionKey: ByteArray
|
||||
@Throws(IllegalArgumentException::class)
|
||||
get() {
|
||||
val walletPublicKey = requireNotNull(findPublicKey(wallets)) {
|
||||
"Wallet public key must not be null"
|
||||
}
|
||||
|
||||
val CardDTO.encryptionKey: ByteArray
|
||||
get() = findWalletPublicKey(wallets)
|
||||
?.let { calculateEncryptionKey(it) }
|
||||
?: error("Wallet ID not found")
|
||||
return calculateEncryptionKey(walletPublicKey)
|
||||
}
|
||||
|
||||
private fun calculateEncryptionKey(publicKey: ByteArray): ByteArray {
|
||||
val message = MESSAGE_FOR_ENCRYPTION_KEY.toByteArray()
|
||||
val keyHash = publicKey.calculateSha256()
|
||||
|
||||
return message.calculateHmacSha256(keyHash)
|
||||
}
|
||||
|
||||
private fun findWalletPublicKey(wallets: List<CardDTO.Wallet>): ByteArray? {
|
||||
private fun findPublicKey(wallets: List<CardDTO.Wallet>): ByteArray? {
|
||||
return wallets.firstOrNull()
|
||||
?.publicKey
|
||||
}
|
||||
|
|
@ -4,10 +4,8 @@ import com.tangem.common.CompletionResult
|
|||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.common.flatMap
|
||||
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
|
||||
import com.tangem.domain.common.util.userWalletId
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
|
|
@ -20,6 +18,7 @@ import com.tangem.tap.common.redux.global.GlobalAction
|
|||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.domain.model.builders.UserWalletBuilder
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||
|
|
@ -27,6 +26,7 @@ import com.tangem.tap.preferencesStorage
|
|||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.tap.userTokensRepository
|
||||
import com.tangem.tap.userWalletsListManager
|
||||
import com.tangem.tap.walletStoresManager
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -79,20 +79,16 @@ class DetailsMiddleware {
|
|||
}
|
||||
DetailsAction.ScanCard -> {
|
||||
scope.launch {
|
||||
tangemSdkManager.scanCard(allowRequestAccessCodeFromRepository = true)
|
||||
.doOnSuccess { card ->
|
||||
val isSameWallet = state.scanResponse?.card?.userWalletId
|
||||
?.equals(card.userWalletId)
|
||||
?: false
|
||||
tangemSdkManager.scanProduct(userTokensRepository)
|
||||
.doOnSuccess { scanResponse ->
|
||||
val currentUserWalletId = state.scanResponse
|
||||
?.let { UserWalletIdBuilder.scanResponse(it).build() }
|
||||
val scannedUserWalletId = UserWalletIdBuilder.scanResponse(scanResponse)
|
||||
.build()
|
||||
val isSameWallet = currentUserWalletId == scannedUserWalletId
|
||||
|
||||
// !!! Workaround !!!
|
||||
// TODO: Remove after [REDACTED_JIRA]
|
||||
val isTwinned = card.wallets.firstOrNull()?.publicKey?.toHexString()
|
||||
?.equals(state.scanResponse?.secondTwinPublicKey)
|
||||
?: false
|
||||
|
||||
if (isSameWallet || isTwinned) {
|
||||
store.dispatchOnMain(DetailsAction.PrepareCardSettingsData(card))
|
||||
if (isSameWallet) {
|
||||
store.dispatchOnMain(DetailsAction.PrepareCardSettingsData(scanResponse.card))
|
||||
} else {
|
||||
store.dispatchDialogShow(
|
||||
AppDialog.SimpleOkDialogRes(
|
||||
|
|
@ -122,8 +118,10 @@ class DetailsMiddleware {
|
|||
is DetailsAction.ResetToFactory.Proceed -> {
|
||||
val card = store.state.detailsState.cardSettingsState?.card ?: return
|
||||
scope.launch {
|
||||
val userWalletId = UserWalletIdBuilder.card(card).build()
|
||||
|
||||
tangemSdkManager.resetToFactorySettings(card.cardId)
|
||||
.flatMap { userWalletsListManager.delete(listOf(card.userWalletId)) }
|
||||
.flatMap { userWalletsListManager.delete(listOfNotNull(userWalletId)) }
|
||||
.flatMap { tangemSdkManager.deleteSavedUserCodes(setOf(card.cardId)) }
|
||||
.doOnSuccess {
|
||||
Analytics.send(Settings.CardSettings.FactoryResetFinished())
|
||||
|
|
@ -275,7 +273,7 @@ class DetailsMiddleware {
|
|||
|
||||
private suspend fun saveCurrentWallet(state: DetailsState) {
|
||||
val scanResponse = state.scanResponse ?: return
|
||||
val userWallet = UserWalletBuilder(scanResponse).build()
|
||||
val userWallet = UserWalletBuilder(scanResponse).build() ?: return
|
||||
|
||||
userWalletsListManager.save(userWallet)
|
||||
.doOnFailure { error ->
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ private fun readCard() = scope.launch {
|
|||
onSuccess = { scanResponse ->
|
||||
scope.launch {
|
||||
if (preferencesStorage.shouldSaveUserWallets) {
|
||||
val userWallet = UserWalletBuilder(scanResponse).build()
|
||||
val userWallet = UserWalletBuilder(scanResponse).build() ?: return@launch
|
||||
userWalletsListManager.save(userWallet)
|
||||
.doOnFailure { error ->
|
||||
Timber.e(error, "Unable to save user wallet")
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import com.tangem.common.CompletionResult
|
|||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.userWalletId
|
||||
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
|
|
@ -25,6 +24,7 @@ import com.tangem.tap.common.redux.navigation.AppScreen
|
|||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.extensions.makePrimaryWalletManager
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
import com.tangem.tap.domain.twins.TwinCardsManager
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
|
|
@ -156,7 +156,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
|
|||
TwinCardsStep.CreateFirstWallet -> {
|
||||
scope.launch {
|
||||
userWalletsListManager.delete(
|
||||
listOf(getScanResponse().card.userWalletId),
|
||||
listOfNotNull(UserWalletIdBuilder.scanResponse(getScanResponse()).build()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ internal class SaveWalletMiddleware {
|
|||
scope.launch {
|
||||
val userWallet = UserWalletBuilder(scanResponse)
|
||||
.backupCardsIds(state.backupInfo?.backupCardsIds)
|
||||
.build()
|
||||
.build() ?: return@launch
|
||||
|
||||
val isFirstSavedWallet = !userWalletsListManager.hasSavedUserWallets
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.tap.features.walletSelector.redux
|
||||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.doOnFailure
|
||||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.common.flatMap
|
||||
|
|
@ -162,6 +163,7 @@ internal class WalletSelectorMiddleware {
|
|||
|
||||
private suspend fun saveUserWalletAndPopBackToWalletScreen(scanResponse: ScanResponse): CompletionResult<Unit> {
|
||||
val userWallet = UserWalletBuilder(scanResponse).build()
|
||||
?: return CompletionResult.Failure(TangemSdkError.WalletIsNotCreated())
|
||||
|
||||
return userWalletsListManager.save(userWallet)
|
||||
.doOnSuccess {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ internal class WelcomeMiddleware {
|
|||
|
||||
private fun proceedWithCard(state: WelcomeState) = scope.launch {
|
||||
scanCardInternal { scanResponse ->
|
||||
val userWallet = UserWalletBuilder(scanResponse).build()
|
||||
val userWallet = UserWalletBuilder(scanResponse).build() ?: return@scanCardInternal
|
||||
|
||||
userWalletsListManager.save(userWallet, canOverride = true)
|
||||
.doOnFailure { error ->
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ import com.tangem.domain.common.CardDTO
|
|||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.common.util.userWalletId
|
||||
import com.tangem.lib.crypto.UserWalletManager
|
||||
import com.tangem.lib.crypto.models.Currency
|
||||
import com.tangem.lib.crypto.models.NativeToken
|
||||
import com.tangem.lib.crypto.models.NonNativeToken
|
||||
import com.tangem.tap.domain.extensions.makeWalletManagerForApp
|
||||
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
|
||||
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import org.rekotlin.Action
|
||||
|
|
@ -54,7 +54,12 @@ class UserWalletManagerImpl(
|
|||
}
|
||||
|
||||
override fun getWalletId(): String {
|
||||
return appStateHolder.getActualCard()?.userWalletId?.stringValue ?: ""
|
||||
return appStateHolder.getActualCard()?.let {
|
||||
UserWalletIdBuilder.card(it)
|
||||
.build()
|
||||
?.stringValue
|
||||
}
|
||||
?: ""
|
||||
}
|
||||
|
||||
override suspend fun isTokenAdded(currency: Currency): Boolean {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
package com.tangem.domain.common.util
|
||||
|
||||
import com.tangem.common.extensions.calculateSha256
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.domain.common.extensions.calculateHmacSha256
|
||||
|
||||
class UserWalletId(
|
||||
val stringValue: String,
|
||||
) {
|
||||
val value = stringValue.hexToBytes()
|
||||
|
||||
constructor(walletPublicKey: ByteArray?) : this(
|
||||
stringValue = walletPublicKey?.let { calculateUserWalletId(it).toHexString() } ?: "",
|
||||
constructor(value: ByteArray?) : this(
|
||||
stringValue = value?.toHexString() ?: "",
|
||||
)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
|
@ -32,12 +30,4 @@ class UserWalletId(
|
|||
"UserWalletId(${take(3)}...${takeLast(3)})"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateUserWalletId(publicKey: ByteArray): ByteArray {
|
||||
val message = MESSAGE_FOR_WALLET_ID.toByteArray()
|
||||
val keyHash = publicKey.calculateSha256()
|
||||
return message.calculateHmacSha256(keyHash)
|
||||
}
|
||||
|
||||
private const val MESSAGE_FOR_WALLET_ID = "UserWalletID"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue