Updated on 2026-08-14

This commit is contained in:
Tangem 2023-08-11 16:53:59 +03:00
parent dee402f968
commit 133dd14ec9
25 changed files with 215 additions and 103 deletions

View file

@ -94,18 +94,20 @@ class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigReposit
scanResponse: ScanResponse,
mnemonic: String,
): CompletionResult<CreateProductWalletTaskResponse> {
return when (val seedResult = DefaultMnemonic(mnemonic, tangemSdk.wordlist).generateSeed()) {
is CompletionResult.Success -> runTaskAsync(
CreateProductWalletTask(
cardTypesResolver = scanResponse.cardTypesResolver,
derivationStyleProvider = scanResponse.derivationStyleProvider,
),
scanResponse.card.cardId,
Message(resources.getString(R.string.initial_message_create_wallet_body)),
)
is CompletionResult.Failure -> CompletionResult.Failure(seedResult.error)
val mnemonic = try {
DefaultMnemonic(mnemonic, tangemSdk.wordlist)
} catch (e: TangemSdkError.MnemonicException) {
return CompletionResult.Failure(e)
}
return runTaskAsync(
CreateProductWalletTask(
scanResponse.cardTypesResolver,
derivationStyleProvider = scanResponse.derivationStyleProvider,
mnemonic,
),
scanResponse.card.cardId,
Message(resources.getString(R.string.initial_message_create_wallet_body)),
)
}
private fun sendScanResultsToAnalytics(result: CompletionResult<ScanResponse>) {

View file

@ -11,11 +11,13 @@ import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.toMapKey
import com.tangem.common.map
import com.tangem.crypto.bip39.Mnemonic
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.DerivationStyleProvider
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.extensions.derivationPath
import com.tangem.domain.common.configs.CardConfig
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.KeyWalletPublicKey
import com.tangem.operations.CommandResponse
@ -58,7 +60,7 @@ private data class CreateWalletResponse(
class CreateProductWalletTask(
private val cardTypesResolver: CardTypesResolver,
private val derivationStyleProvider: DerivationStyleProvider,
private val seed: ByteArray? = null,
private val mnemonic: Mnemonic? = null,
) : CardSessionRunnable<CreateProductWalletTaskResponse> {
override val allowsRequestAccessCodeFromRepository: Boolean = false
@ -78,7 +80,7 @@ class CreateProductWalletTask(
cardTypesResolver.isTangemTwins() ->
throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
else -> CreateWalletTangemWallet(seed, derivationStyleProvider)
else -> CreateWalletTangemWallet(mnemonic, derivationStyleProvider)
}
commandProcessor.proceed(cardDto, session) {
when (it) {
@ -133,8 +135,11 @@ private class CreateWalletTangemNote(private val cardTypesResolver: CardTypesRes
}
}
/**
* Uses for multiWallet 1st and 2nd
*/
private class CreateWalletTangemWallet(
private val seed: ByteArray?,
private val mnemonic: Mnemonic?,
private val derivationStyleProvider: DerivationStyleProvider,
) : ProductCommandProcessor<CreateProductWalletTaskResponse> {
@ -145,8 +150,9 @@ private class CreateWalletTangemWallet(
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
) {
val config = CardConfig.createConfig(card)
val walletsOnCard = card.wallets.map { it.curve }.toSet()
val curves = card.supportedCurves.intersect(CURVES_FOR_WALLETS).subtract(walletsOnCard).toList()
val curves = card.supportedCurves.intersect(config.mandatoryCurves.toSet()).subtract(walletsOnCard).toList()
if (curves.isEmpty()) {
val createWalletResponses = card.wallets.map { wallet ->
@ -155,8 +161,7 @@ private class CreateWalletTangemWallet(
proceedWithCreatedWallets(card, createWalletResponses, session, callback)
return
}
CreateWalletsTask(curves, seed).run(session) { result ->
CreateWalletsTask(curves, mnemonic).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
proceedWithCreatedWallets(

View file

@ -5,6 +5,8 @@ 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.crypto.bip39.Mnemonic
import com.tangem.crypto.hdWallet.masterkey.AnyMasterKeyFactory
import com.tangem.operations.CommandResponse
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.operations.wallet.CreateWalletTask
@ -18,7 +20,7 @@ class CreateWalletsResponse(
class CreateWalletsTask(
private val curves: List<EllipticCurve>,
private val seed: ByteArray? = null,
private val mnemonic: Mnemonic? = null,
) : CardSessionRunnable<CreateWalletsResponse> {
private val createdWalletsResponses = mutableListOf<CreateWalletResponse>()
@ -38,7 +40,10 @@ class CreateWalletsTask(
session: CardSession,
callback: (result: CompletionResult<CreateWalletsResponse>) -> Unit,
) {
CreateWalletTask(curve, seed).run(session) { result ->
val extendedPrivateKey = mnemonic?.let {
AnyMasterKeyFactory(mnemonic = it, passphrase = "").makeMasterKey(curve)
}
CreateWalletTask(curve, extendedPrivateKey).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
createdWalletsResponses.add(result.data)

View file

@ -21,7 +21,7 @@ import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
import com.tangem.domain.common.TwinsHelper
import com.tangem.domain.common.extensions.getPrimaryCurve
import com.tangem.domain.common.configs.CardConfig
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
@ -209,6 +209,7 @@ private class ScanWalletProcessor(
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
val productType = ProductType.Wallet
val config = CardConfig.createConfig(card)
scope.launch {
val scanResponse = ScanResponse(
card = card,
@ -216,7 +217,7 @@ private class ScanWalletProcessor(
walletData = session.environment.walletData,
primaryCard = primaryCard,
)
val derivations = collectDerivations(card, scanResponse.derivationStyleProvider)
val derivations = collectDerivations(card, config, scanResponse.derivationStyleProvider)
if (derivations.isEmpty() || !card.settings.isHDWalletAllowed) {
callback(CompletionResult.Success(scanResponse))
return@launch
@ -299,13 +300,14 @@ private class ScanWalletProcessor(
private suspend fun collectDerivations(
card: CardDTO,
config: CardConfig,
derivationStyleProvider: DerivationStyleProvider,
): Map<ByteArrayKey, List<DerivationPath>> {
val blockchains = getBlockchainsToDerive(card, derivationStyleProvider)
val derivations = mutableMapOf<ByteArrayKey, List<DerivationPath>>()
blockchains.forEach { blockchain ->
val curve = blockchain.blockchain.getPrimaryCurve()
val curve = config.primaryCurve(blockchain.blockchain)
val wallet = card.wallets.firstOrNull { it.curve == curve } ?: return@forEach
if (wallet.chainCode == null) return@forEach

View file

@ -1,27 +0,0 @@
package com.tangem.tap.domain.tokens
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.card.FirmwareVersion
import com.tangem.domain.models.scan.CardDTO
object CurrenciesRepository {
fun getBlockchains(cardFirmware: CardDTO.FirmwareVersion, isTestNet: Boolean = false): List<Blockchain> {
val blockchains = if (cardFirmware < FirmwareVersion.MultiWalletAvailable) {
Blockchain.secp256k1Blockchains(isTestNet)
} else {
Blockchain.secp256k1Blockchains(isTestNet) + Blockchain.ed25519OnlyBlockchains(isTestNet)
}
return excludeUnsupportedBlockchains(blockchains)
}
// Use this list to temporarily exclude a blockchain from the list of tokens.
private fun excludeUnsupportedBlockchains(blockchains: List<Blockchain>): List<Blockchain> {
return blockchains.toMutableList().apply {
removeAll(
listOf(
// Any blockchain
),
)
}
}
}

View file

@ -7,6 +7,7 @@ import com.tangem.common.extensions.guard
import com.tangem.common.extensions.toMapKey
import com.tangem.common.flatMap
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.common.configs.CardConfig
import com.tangem.domain.common.extensions.derivationPath
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.domain.common.util.derivationStyleProvider
@ -69,10 +70,11 @@ class DefaultCustomTokenInteractor(
currencyList: List<Currency>,
onSuccess: suspend (ScanResponse) -> Unit,
) {
val derivationDataList = listOfNotNull(
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencyList),
getDerivations(EllipticCurve.Ed25519, scanResponse, currencyList),
)
val config = CardConfig.createConfig(scanResponse.card)
val derivationDataList = currencyList.mapNotNull {
val curve = config.primaryCurve(it.blockchain)
curve?.let { getDerivations(curve, scanResponse, currencyList) }
}
val derivations = derivationDataList.associate(TokensMiddleware.DerivationData::derivations)
if (derivations.isEmpty()) {

View file

@ -9,6 +9,7 @@ import com.tangem.common.extensions.guard
import com.tangem.common.extensions.toMapKey
import com.tangem.common.flatMap
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.common.configs.CardConfig
import com.tangem.domain.common.extensions.derivationPath
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.common.util.supportsHdWallet
@ -134,10 +135,11 @@ internal class DefaultTokensListInteractor(
}
private suspend fun deriveMissingBlockchains(scanResponse: ScanResponse, currencies: List<Currency>) {
val derivations = listOfNotNull(
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencies),
getDerivations(EllipticCurve.Ed25519, scanResponse, currencies),
).associate(transform = TokensMiddleware.DerivationData::derivations)
val config = CardConfig.createConfig(scanResponse.card)
val derivations = currencies.mapNotNull {
val curve = config.primaryCurve(it.blockchain)
curve?.let { getDerivations(curve, scanResponse, currencies) }
}.associate(transform = TokensMiddleware.DerivationData::derivations)
if (derivations.isEmpty()) {
submitAdd(scanResponse, currencies)

View file

@ -13,6 +13,7 @@ import com.tangem.core.navigation.AppScreen
import com.tangem.core.navigation.NavigationAction
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.DomainWrapped
import com.tangem.domain.common.configs.CardConfig
import com.tangem.domain.common.extensions.derivationPath
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.common.util.hasDerivation
@ -119,10 +120,11 @@ object TokensMiddleware {
currencyList: List<Currency>,
onSuccess: (ScanResponse) -> Unit,
) {
val derivationDataList = listOfNotNull(
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencyList),
getDerivations(EllipticCurve.Ed25519, scanResponse, currencyList),
)
val config = CardConfig.createConfig(scanResponse.card)
val derivationDataList = currencyList.mapNotNull {
val curve = config.primaryCurve(it.blockchain)
curve?.let { getDerivations(curve, scanResponse, currencyList) }
}
val derivations = derivationDataList.associate { it.derivations }
if (derivations.isEmpty()) {
onSuccess(scanResponse)

View file

@ -10,6 +10,7 @@ import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.extensions.toMapKey
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.common.BlockchainNetwork
import com.tangem.domain.common.configs.CardConfig
import com.tangem.domain.common.extensions.derivationPath
import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.domain.common.util.derivationStyleProvider
@ -94,10 +95,11 @@ class DerivationManagerImpl(
onSuccess: (ScanResponse) -> Unit,
onFailure: (Exception) -> Unit,
) {
val derivationDataList = listOfNotNull(
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencyList),
getDerivations(EllipticCurve.Ed25519, scanResponse, currencyList),
)
val config = CardConfig.createConfig(scanResponse.card)
val derivationDataList = currencyList.mapNotNull {
val curve = config.primaryCurve(it.blockchain)
curve?.let { getDerivations(curve, scanResponse, currencyList) }
}
val derivations = derivationDataList.associate { it.derivations }
if (derivations.isEmpty()) {
onSuccess(scanResponse)