Updated on 2026-08-14

This commit is contained in:
Tangem 2024-02-02 10:12:14 +03:00
parent 9b6de19ebe
commit ce602107bb
16 changed files with 178 additions and 115 deletions

View file

@ -85,11 +85,15 @@ class TangemSdkManager(
).also { sendScanResultsToAnalytics(it) }
}
suspend fun createProductWallet(scanResponse: ScanResponse): CompletionResult<CreateProductWalletTaskResponse> {
suspend fun createProductWallet(
scanResponse: ScanResponse,
shouldReset: Boolean = false,
): CompletionResult<CreateProductWalletTaskResponse> {
return runTaskAsync(
runnable = CreateProductWalletTask(
cardTypesResolver = scanResponse.cardTypesResolver,
derivationStyleProvider = scanResponse.derivationStyleProvider,
shouldReset = shouldReset,
),
cardId = scanResponse.card.cardId,
initialMessage = Message(resources.getString(R.string.initial_message_create_wallet_body)),
@ -100,6 +104,7 @@ class TangemSdkManager(
suspend fun importWallet(
scanResponse: ScanResponse,
mnemonic: String,
shouldReset: Boolean,
): CompletionResult<CreateProductWalletTaskResponse> {
val defaultMnemonic = try {
DefaultMnemonic(mnemonic, tangemSdk.wordlist)
@ -108,9 +113,10 @@ class TangemSdkManager(
}
return runTaskAsync(
CreateProductWalletTask(
scanResponse.cardTypesResolver,
cardTypesResolver = scanResponse.cardTypesResolver,
derivationStyleProvider = scanResponse.derivationStyleProvider,
defaultMnemonic,
mnemonic = defaultMnemonic,
shouldReset = shouldReset,
),
scanResponse.card.cardId,
Message(resources.getString(R.string.initial_message_create_wallet_body)),

View file

@ -1,38 +0,0 @@
package com.tangem.tap.domain.tasks
import com.tangem.common.CompletionResult
import com.tangem.common.card.Card
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.operations.PreflightReadMode
import com.tangem.operations.PreflightReadTask
import com.tangem.operations.wallet.CreateWalletTask
@Deprecated("Use CreateProductWalletAndRescanTask instead")
class CreateWalletAndRescanTask : CardSessionRunnable<Card> {
override fun run(session: CardSession, callback: (result: CompletionResult<Card>) -> Unit) {
val card = session.environment.card.guard {
callback(CompletionResult.Failure(TangemSdkError.CardError()))
return
}
val firmwareVersion = card.firmwareVersion
val task = if (firmwareVersion < FirmwareVersion.MultiWalletAvailable) {
CreateWalletTask(card.supportedCurves.first())
} else {
CreateWalletsTask()
}
task.run(session) { result ->
when (result) {
is CompletionResult.Success ->
PreflightReadTask(PreflightReadMode.FullCardRead).run(session, callback)
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
}
}
}

View file

@ -1,49 +0,0 @@
package com.tangem.tap.domain.tasks
import com.tangem.common.CompletionResult
import com.tangem.common.card.Card
import com.tangem.common.card.EllipticCurve
import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.operations.PreflightReadMode
import com.tangem.operations.PreflightReadTask
import com.tangem.operations.wallet.CreateWalletTask
@Deprecated("Use CreateProductWalletTask instead")
class CreateWalletsTask(curves: List<EllipticCurve>? = null) : CardSessionRunnable<Card> {
private val curves = curves ?: listOf(
EllipticCurve.Secp256k1,
EllipticCurve.Ed25519,
EllipticCurve.Secp256r1,
)
private var index = 0
override fun run(session: CardSession, callback: (result: CompletionResult<Card>) -> Unit) {
val curve = curves[index]
createWallet(curve, session, callback)
}
private fun createWallet(
curve: EllipticCurve,
session: CardSession,
callback: (result: CompletionResult<Card>) -> Unit,
) {
CreateWalletTask(curve).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
if (index == curves.lastIndex) {
PreflightReadTask(PreflightReadMode.FullCardRead).run(session, callback)
return@run
}
index += 1
createWallet(curves[index], session, callback)
}
is CompletionResult.Failure -> {
callback(CompletionResult.Failure(result.error))
}
}
}
}
}

View file

@ -0,0 +1,13 @@
package com.tangem.tap.domain.tasks.product
import com.tangem.common.card.CardWallet
import com.tangem.common.card.EllipticCurve
class CardInitializationValidator(private val expectedCurves: List<EllipticCurve>) {
fun validateWallets(wallets: List<CardWallet>): Boolean {
val curves = wallets.map { it.curve }.toSet()
return curves.size == expectedCurves.size &&
curves.containsAll(expectedCurves)
}
}

View file

@ -4,6 +4,7 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.common.CompletionResult
import com.tangem.common.card.Card
import com.tangem.common.card.EllipticCurve
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.TangemSdkError
@ -24,6 +25,7 @@ import com.tangem.operations.backup.PrimaryCard
import com.tangem.operations.backup.StartPrimaryCardLinkingCommand
import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import com.tangem.operations.read.ReadWalletsListCommand
import com.tangem.operations.wallet.CreateWalletTask
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.operations.wallet.CreateWalletResponse as SdkCreateWalletResponse
@ -60,6 +62,7 @@ class CreateProductWalletTask(
private val cardTypesResolver: CardTypesResolver,
private val derivationStyleProvider: DerivationStyleProvider,
private val mnemonic: Mnemonic? = null,
private val shouldReset: Boolean,
) : CardSessionRunnable<CreateProductWalletTaskResponse> {
override val allowsRequestAccessCodeFromRepository: Boolean = false
@ -79,7 +82,7 @@ class CreateProductWalletTask(
cardTypesResolver.isTangemTwins() ->
throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
else -> CreateWalletTangemWallet(mnemonic, derivationStyleProvider)
else -> CreateWalletTangemWallet(mnemonic, shouldReset, derivationStyleProvider, cardDto)
}
commandProcessor.proceed(cardDto, session) {
when (it) {
@ -139,38 +142,38 @@ private class CreateWalletTangemNote(private val cardTypesResolver: CardTypesRes
*/
private class CreateWalletTangemWallet(
private val mnemonic: Mnemonic?,
private val shouldReset: Boolean,
private val derivationStyleProvider: DerivationStyleProvider,
cardDTO: CardDTO,
) : ProductCommandProcessor<CreateProductWalletTaskResponse> {
private var primaryCard: PrimaryCard? = null
private val cardConfig = CardConfig.createConfig(cardDTO)
override fun proceed(
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
) {
val config = CardConfig.createConfig(card)
val walletsOnCard = card.wallets.map { it.curve }.toSet()
val curves = config.mandatoryCurves.toSet()
.intersect(card.supportedCurves.toSet())
.subtract(walletsOnCard).toList()
if (curves.isEmpty()) {
val createWalletResponses = card.wallets.map { wallet ->
CreateWalletResponse(card.cardId, wallet)
}
proceedWithCreatedWallets(card, createWalletResponses, session, callback)
return
if (walletsOnCard.isEmpty()) {
createMultiWallet(card, session, callback)
} else if (shouldReset) {
resetCard(card, session, callback)
} else {
callback(CompletionResult.Failure(TangemSdkError.WalletAlreadyCreated()))
}
CreateWalletsTask(curves, mnemonic).run(session) { result ->
}
private fun createMultiWallet(
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
) {
CreateWalletsTask(cardConfig.mandatoryCurves, mnemonic).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
proceedWithCreatedWallets(
card = card,
createWalletResponses = result.data.createWalletResponses.map { CreateWalletResponse(it) },
session = session,
callback = callback,
)
checkIfAllWalletsCreated(card, session, result.data, callback)
}
is CompletionResult.Failure -> {
callback(CompletionResult.Failure(result.error))
@ -179,6 +182,61 @@ private class CreateWalletTangemWallet(
}
}
private fun checkIfAllWalletsCreated(
card: CardDTO,
session: CardSession,
createResponse: CreateWalletsResponse,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
) {
if (card.firmwareVersion < FirmwareVersion.MultiWalletAvailable) {
proceedWithCreatedWallets(
card = card,
createWalletResponses = createResponse.createWalletResponses.map { CreateWalletResponse(it) },
session = session,
callback = callback,
)
return
}
val command = ReadWalletsListCommand()
command.run(session) { response ->
when (response) {
is CompletionResult.Success -> {
val cardInitializationValidator = CardInitializationValidator(cardConfig.mandatoryCurves)
if (cardInitializationValidator.validateWallets(response.data.wallets)) {
proceedWithCreatedWallets(
card = card,
createWalletResponses = createResponse.createWalletResponses.map {
CreateWalletResponse(it)
},
session = session,
callback = callback,
)
} else {
callback(CompletionResult.Failure(TangemSdkError.WalletAlreadyCreated()))
}
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(response.error))
}
}
}
private fun resetCard(
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
) {
val resetCommand = ResetToFactorySettingsTask(allowsRequestAccessCodeFromRepository = false)
resetCommand.run(session) {
when (it) {
is CompletionResult.Success -> {
createMultiWallet(card, session, callback)
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(it.error))
}
}
}
private fun proceedWithCreatedWallets(
card: CardDTO,
createWalletResponses: List<CreateWalletResponse>,