Updated on 2026-08-14
This commit is contained in:
commit
7b456a1d08
13 changed files with 78 additions and 32 deletions
|
|
@ -91,7 +91,7 @@ class TapWalletManager {
|
|||
store.dispatch(WalletAction.MultiWallet.SetIsMultiwalletAllowed(data.card.isMultiwalletAllowed))
|
||||
if (data.card.isTangemTwin()) {
|
||||
data.card.getTwinCardNumber()?.let {
|
||||
store.dispatch(WalletAction.TwinsAction.SetTwinCard(null, it, true))
|
||||
store.dispatch(WalletAction.TwinsAction.SetTwinCard(it, true))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,8 +117,17 @@ class ScanNoteTask(val card: Card? = null) : CardSessionRunnable<ScanResponse> {
|
|||
|
||||
private fun getErrorIfExcludedCard(card: Card): TangemError? {
|
||||
if (card.isExcluded()) return TapSdkError.CardForDifferentApp
|
||||
// Disable new cards on the old version of the app // TODO: remove when cards are supported
|
||||
if (card.isMultiCurrencyWallet() || card.isNote()) return UpdateAppToUseThisCard()
|
||||
// Disable new multi-currency HD wallet cards on the old version of the app
|
||||
// if (card.isMultiCurrencyWallet()) return UpdateAppToUseThisCard()
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getWalletManagerFactory(): WalletManagerFactory {
|
||||
val blockchainSdkConfig = store.state.globalState.configManager?.config
|
||||
?.blockchainSdkConfig ?: BlockchainSdkConfig()
|
||||
return WalletManagerFactory(blockchainSdkConfig)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.tangem.common.KeyPair
|
|||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.operations.wallet.CreateWalletCommand
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
|
|
@ -13,14 +14,21 @@ import com.tangem.operations.wallet.PurgeWalletCommand
|
|||
import com.tangem.tap.domain.extensions.getSingleWallet
|
||||
|
||||
class CreateSecondTwinWalletTask(
|
||||
private val firstPublicKey: String,
|
||||
private val issuerKeys: KeyPair,
|
||||
private val preparingMessage: Message,
|
||||
private val creatingWalletMessage: Message
|
||||
private val firstPublicKey: String,
|
||||
private val firstCardId: String,
|
||||
private val issuerKeys: KeyPair,
|
||||
private val preparingMessage: Message,
|
||||
private val creatingWalletMessage: Message
|
||||
) : CardSessionRunnable<CreateWalletResponse> {
|
||||
override fun run(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> Unit) {
|
||||
val publicKey = session.environment.card?.getSingleWallet()?.publicKey
|
||||
val card = session.environment.card
|
||||
val publicKey = card?.getSingleWallet()?.publicKey
|
||||
if (publicKey != null) {
|
||||
if (!card.cardId.startsWith(TwinsHelper.getPairCardSeries(firstCardId) ?: "")) {
|
||||
callback(CompletionResult.Failure(TangemSdkError.WrongCardType()))
|
||||
return
|
||||
}
|
||||
|
||||
session.setInitialMessage(preparingMessage)
|
||||
PurgeWalletCommand(publicKey).run(session) { response ->
|
||||
when (response) {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ import com.tangem.tap.tangemSdkManager
|
|||
class TwinCardsManager(private val scanResponse: ScanResponse, context: Context) {
|
||||
|
||||
private val currentCardId: String = scanResponse.card.cardId
|
||||
// private val secondCardId: String? = TwinsHelper.getTwinsCardId(currentCardId)
|
||||
private val secondCardId: String? = null
|
||||
|
||||
private var currentCardPublicKey: String? = null
|
||||
private var secondCardPublicKey: String? = null
|
||||
|
|
@ -60,13 +58,15 @@ class TwinCardsManager(private val scanResponse: ScanResponse, context: Context)
|
|||
preparingMessage: Message,
|
||||
creatingWalletMessage: Message,
|
||||
): SimpleResult {
|
||||
val task = CreateSecondTwinWalletTask(
|
||||
firstPublicKey = currentCardPublicKey!!,
|
||||
firstCardId = currentCardId,
|
||||
issuerKeys = issuerKeyPair,
|
||||
preparingMessage = preparingMessage,
|
||||
creatingWalletMessage = creatingWalletMessage
|
||||
)
|
||||
val response = tangemSdkManager.runTaskAsync(
|
||||
CreateSecondTwinWalletTask(
|
||||
firstPublicKey = currentCardPublicKey!!,
|
||||
issuerKeys = issuerKeyPair,
|
||||
preparingMessage = preparingMessage,
|
||||
creatingWalletMessage = creatingWalletMessage),
|
||||
secondCardId, initialMessage
|
||||
task, null, initialMessage
|
||||
)
|
||||
when (response) {
|
||||
is CompletionResult.Success -> {
|
||||
|
|
@ -116,6 +116,14 @@ class TwinCardsManager(private val scanResponse: ScanResponse, context: Context)
|
|||
return CryptoUtils.verify(cardWalletPublicKey, publicKey, signedKey)
|
||||
}
|
||||
|
||||
fun verifyTwinPublicKey(issuerData: ByteArray, cardWalletPublicKey: ByteArray?): Boolean {
|
||||
if (issuerData.size < 65) return false
|
||||
val publicKey = issuerData.sliceArray(0 until 65)
|
||||
val signedKey = issuerData.sliceArray(65 until issuerData.size)
|
||||
return (cardWalletPublicKey != null &&
|
||||
CryptoUtils.verify(cardWalletPublicKey, publicKey, signedKey))
|
||||
}
|
||||
|
||||
private fun getIssuerKeys(context: Context, publicKey: String): KeyPair {
|
||||
val issuer = getIssuers(context).first { it.publicKey == publicKey }
|
||||
return KeyPair(
|
||||
|
|
|
|||
|
|
@ -20,6 +20,19 @@ class TwinsHelper {
|
|||
}
|
||||
}
|
||||
|
||||
fun getPairCardSeries(cardId: String): String? {
|
||||
return when (getTwinCardNumber(cardId) ?: return null) {
|
||||
TwinCardNumber.First -> {
|
||||
val index = firstCardSeries.indexOf(cardId.take(4))
|
||||
secondCardSeries[index]
|
||||
}
|
||||
TwinCardNumber.Second -> {
|
||||
val index = secondCardSeries.indexOf(cardId.take(4))
|
||||
firstCardSeries[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getTwinCardIdForUser(cardId: String): String {
|
||||
if (cardId.length < 16) return cardId
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class WalletConnectSdkHelper {
|
|||
|
||||
val decimals = blockchain.decimals()
|
||||
|
||||
val value = transaction.value?.hexToBigDecimal()
|
||||
val value = (transaction.value ?: "0").hexToBigDecimal()
|
||||
?.movePointLeft(decimals) ?: return null
|
||||
|
||||
val gasPrice = transaction.gasPrice?.hexToBigDecimal()
|
||||
|
|
|
|||
|
|
@ -170,12 +170,16 @@ private fun handleSecurityAction(
|
|||
state.copy(confirmScreenState = confirmScreenState)
|
||||
}
|
||||
is DetailsAction.ManageSecurity.SaveChanges.Success -> {
|
||||
// Setting options to show only LongTap from now on
|
||||
// Setting options to show only LongTap from now on for non-twins
|
||||
state.copy(
|
||||
securityScreenState = state.securityScreenState?.copy(
|
||||
currentOption = state.securityScreenState.selectedOption,
|
||||
allowedOptions = EnumSet.of(SecurityOption.LongTap)
|
||||
))
|
||||
securityScreenState = state.securityScreenState?.copy(
|
||||
currentOption = state.securityScreenState.selectedOption,
|
||||
allowedOptions = state.card?.let {
|
||||
prepareAllowedSecurityOptions(
|
||||
it, state.securityScreenState.selectedOption
|
||||
)
|
||||
} ?: EnumSet.of(SecurityOption.LongTap)
|
||||
))
|
||||
}
|
||||
|
||||
else -> state
|
||||
|
|
@ -187,7 +191,12 @@ private fun prepareAllowedSecurityOptions(
|
|||
): EnumSet<SecurityOption> {
|
||||
val prohibitDefaultPin = card?.settings?.isResettingUserCodesAllowed != true
|
||||
|
||||
val prohibitDefaultPin = card?.settings?.isRemovingAccessCodeAllowed != true
|
||||
val allowedSecurityOptions = EnumSet.noneOf(SecurityOption::class.java)
|
||||
|
||||
if (card?.isTwinCard() == true) {
|
||||
allowedSecurityOptions.add(SecurityOption.PassCode)
|
||||
}
|
||||
if ((currentSecurityOption == SecurityOption.LongTap) || !prohibitDefaultPin) {
|
||||
allowedSecurityOptions.add(SecurityOption.LongTap)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,8 +151,8 @@ sealed class WalletAction : Action {
|
|||
object ShowOnboarding : TwinsAction()
|
||||
object SetOnboardingShown : TwinsAction()
|
||||
data class SetTwinCard(
|
||||
val secondCardId: String?, val number: TwinCardNumber,
|
||||
val isCreatingTwinCardsAllowed: Boolean,
|
||||
val number: TwinCardNumber,
|
||||
val isCreatingTwinCardsAllowed: Boolean,
|
||||
) : TwinsAction()
|
||||
}
|
||||
}
|
||||
|
|
@ -199,7 +199,6 @@ data class TradeCryptoAvailability(
|
|||
)
|
||||
|
||||
data class TwinCardsState(
|
||||
val secondCardId: String?,
|
||||
val cardNumber: TwinCardNumber?,
|
||||
val showTwinOnboarding: Boolean,
|
||||
val isCreatingTwinCardsAllowed: Boolean
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ class TwinsReducer {
|
|||
is WalletAction.TwinsAction.SetTwinCard -> {
|
||||
state.copy(
|
||||
twinCardsState = TwinCardsState(
|
||||
secondCardId = action.secondCardId,
|
||||
cardNumber = action.number,
|
||||
showTwinOnboarding = state.twinCardsState?.showTwinOnboarding
|
||||
?: false,
|
||||
|
|
@ -21,7 +20,7 @@ class TwinsReducer {
|
|||
is WalletAction.TwinsAction.ShowOnboarding -> {
|
||||
state.copy(
|
||||
twinCardsState = state.twinCardsState?.copy(showTwinOnboarding = true)
|
||||
?: TwinCardsState(null, null,
|
||||
?: TwinCardsState(cardNumber = null,
|
||||
showTwinOnboarding = true,
|
||||
isCreatingTwinCardsAllowed = false)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import androidx.transition.TransitionInflater
|
|||
import com.squareup.picasso.Picasso
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.domain.twins.TwinsHelper
|
||||
import com.tangem.tap.features.wallet.redux.Artwork
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.store
|
||||
|
|
@ -34,10 +33,9 @@ class OnboardingTwinsFragment : Fragment(R.layout.fragment_twin_cards) {
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
store.dispatch(WalletAction.TwinsAction.SetOnboardingShown)
|
||||
|
||||
val secondCardId = store.state.walletState.twinCardsState?.secondCardId ?: ""
|
||||
val secondTwinCardId = TwinsHelper.getTwinCardIdForUser(secondCardId)
|
||||
val text = getString(R.string.twins_onboarding_description_format, secondTwinCardId)
|
||||
val secondTwinNumber =
|
||||
store.state.walletState.twinCardsState?.cardNumber?.pairNumber()?.number ?: ""
|
||||
val text = getString(R.string.twins_onboarding_description_format, secondTwinNumber)
|
||||
tv_twin_cards_description_1.text = text
|
||||
|
||||
setOnClickListeners()
|
||||
|
|
|
|||
|
|
@ -94,7 +94,10 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
override fun newState(state: WalletState) {
|
||||
if (activity == null) return
|
||||
|
||||
if (state.isMultiwalletAllowed && walletView is SingleWalletView) {
|
||||
if (state.isMultiwalletAllowed &&
|
||||
state.primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard &&
|
||||
walletView is SingleWalletView
|
||||
) {
|
||||
walletView = MultiWalletView()
|
||||
walletView.changeWalletView(this)
|
||||
} else if (!state.isMultiwalletAllowed && walletView is MultiWalletView) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue