Updated on 2026-08-14

This commit is contained in:
Tangem 2023-08-21 10:45:29 +03:00
parent e91c59c442
commit c7b11501e7
5 changed files with 151 additions and 59 deletions

View file

@ -82,7 +82,7 @@ fun WalletManager?.getAddressData(): WalletDataModel.AddressData? {
}
fun <T> WalletManager.Companion.stub(): T {
val wallet = Wallet(Blockchain.Unknown, setOf(), Wallet.PublicKey(byteArrayOf(), null, null), setOf())
val wallet = Wallet(Blockchain.Unknown, setOf(), Wallet.PublicKey(byteArrayOf(), null), setOf())
return object : WalletManager(wallet) {
override val currentHost: String = ""
override suspend fun update() {}

View file

@ -1,5 +1,6 @@
package com.tangem.tap.domain.tasks.product
import com.tangem.blockchain.blockchains.cardano.CardanoUtils
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.CompletionResult
import com.tangem.common.card.Card
@ -217,7 +218,8 @@ private class ScanWalletProcessor(
walletData = session.environment.walletData,
primaryCard = primaryCard,
)
val derivations = collectDerivations(card, config, scanResponse.derivationStyleProvider)
val derivations =
collectDerivations(card, config, scanResponse.derivationStyleProvider)
if (derivations.isEmpty() || !card.settings.isHDWalletAllowed) {
callback(CompletionResult.Success(scanResponse))
return@launch
@ -242,60 +244,101 @@ private class ScanWalletProcessor(
val userTokensRepository = userTokensRepository ?: return emptyList()
val blockchainsToDerive = userTokensRepository.loadBlockchainsToDerive(card)
.toMutableList()
.ifEmpty {
mutableListOf(
BlockchainNetwork(
blockchain = Blockchain.Bitcoin,
derivationStyleProvider = derivationStyleProvider,
),
BlockchainNetwork(
blockchain = Blockchain.Ethereum,
derivationStyleProvider = derivationStyleProvider,
),
)
}
.ifEmpty { getDefaultBlockchains(derivationStyleProvider) }
if (card.settings.isHDWalletAllowed) {
blockchainsToDerive.addAll(
listOf(
BlockchainNetwork(
blockchain = Blockchain.Ethereum,
derivationStyleProvider = derivationStyleProvider,
),
BlockchainNetwork(
blockchain = Blockchain.EthereumTestnet,
derivationStyleProvider = derivationStyleProvider,
),
),
)
blockchainsToDerive += getEthereumBlockchains(derivationStyleProvider)
}
if (additionalBlockchainsToDerive != null) {
blockchainsToDerive.addAll(
additionalBlockchainsToDerive.map {
BlockchainNetwork(
blockchain = it,
derivationStyleProvider = derivationStyleProvider,
)
},
)
additionalBlockchainsToDerive?.let {
blockchainsToDerive += getAdditionalBlockchainToDerive(derivationStyleProvider, it)
}
// we should generate second key for cardano
// because cardano address generation for wallet2 requires keys from 2 derivations
// https://developers.cardano.org/docs/get-started/cardano-serialization-lib/generating-keys/
val secondCardanoNetwork = blockchainsToDerive
.find { it.blockchain == Blockchain.Cardano }
?.let { getCardanoSecondNetwork(it) }
secondCardanoNetwork?.let { blockchainsToDerive.add(it) }
// pay attention to this
if (!card.useOldStyleDerivation) {
blockchainsToDerive.removeAll(
listOf(
Blockchain.BSC, Blockchain.BSCTestnet,
Blockchain.Polygon, Blockchain.PolygonTestnet,
Blockchain.RSK,
Blockchain.Fantom, Blockchain.FantomTestnet,
Blockchain.Avalanche, Blockchain.AvalancheTestnet,
).map {
BlockchainNetwork(
blockchain = it,
derivationStyleProvider = derivationStyleProvider,
)
},
removeUnnecessaryBlockchains(blockchainsToDerive, derivationStyleProvider)
}
return blockchainsToDerive.distinct()
}
private fun getDefaultBlockchains(
derivationStyleProvider: DerivationStyleProvider,
): MutableList<BlockchainNetwork> {
return mutableListOf(
BlockchainNetwork(
blockchain = Blockchain.Bitcoin,
derivationStyleProvider = derivationStyleProvider,
),
BlockchainNetwork(
blockchain = Blockchain.Ethereum,
derivationStyleProvider = derivationStyleProvider,
),
)
}
private fun getEthereumBlockchains(derivationStyleProvider: DerivationStyleProvider): List<BlockchainNetwork> {
return listOf(
BlockchainNetwork(
blockchain = Blockchain.Ethereum,
derivationStyleProvider = derivationStyleProvider,
),
BlockchainNetwork(
blockchain = Blockchain.EthereumTestnet,
derivationStyleProvider = derivationStyleProvider,
),
)
}
private fun getAdditionalBlockchainToDerive(
derivationStyleProvider: DerivationStyleProvider,
collection: Collection<Blockchain>,
): List<BlockchainNetwork> {
return collection.map {
BlockchainNetwork(
blockchain = it,
derivationStyleProvider = derivationStyleProvider,
)
}
return blockchainsToDerive.distinct()
}
private fun getCardanoSecondNetwork(cardanoBlockchainNetwork: BlockchainNetwork): BlockchainNetwork? {
val cardanoStandardDerivation = cardanoBlockchainNetwork.derivationPath?.let { DerivationPath(it) }
?: return null
val cardanoPatchedDerivation = CardanoUtils.extendedDerivationPath(cardanoStandardDerivation)
return BlockchainNetwork(
blockchain = Blockchain.Cardano,
derivationPath = cardanoPatchedDerivation.rawPath,
tokens = emptyList(),
)
}
private fun removeUnnecessaryBlockchains(
blockchainsToDerive: MutableList<BlockchainNetwork>,
derivationStyleProvider: DerivationStyleProvider,
) {
blockchainsToDerive.removeAll(
listOf(
Blockchain.BSC, Blockchain.BSCTestnet,
Blockchain.Polygon, Blockchain.PolygonTestnet,
Blockchain.RSK,
Blockchain.Fantom, Blockchain.FantomTestnet,
Blockchain.Avalanche, Blockchain.AvalancheTestnet,
).map {
BlockchainNetwork(
blockchain = it,
derivationStyleProvider = derivationStyleProvider,
)
},
)
}
private suspend fun collectDerivations(

View file

@ -16,6 +16,7 @@ object Wallet2CardConfig : CardConfig {
/**
* Logic to determine primary curve for blockchain in TangemWallet 2.0
* Order is important here
*/
override fun primaryCurve(blockchain: Blockchain): EllipticCurve? {
// order is important, new curve is preferred for wallet 2
@ -29,6 +30,10 @@ object Wallet2CardConfig : CardConfig {
blockchain.getSupportedCurves().contains(EllipticCurve.Bls12381G2Aug) -> {
EllipticCurve.Bls12381G2Aug
}
// only for support cardano on Wallet2
blockchain.getSupportedCurves().contains(EllipticCurve.Ed25519) -> {
EllipticCurve.Ed25519
}
else -> {
Timber.e("Unsupported blockchain, curve not found")
null

View file

@ -1,10 +1,13 @@
package com.tangem.domain.common.extensions
import com.tangem.blockchain.blockchains.cardano.CardanoUtils
import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.derivation.DerivationStyle
import com.tangem.common.card.EllipticCurve
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toMapKey
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
import com.tangem.domain.common.configs.CardConfig
@ -12,6 +15,7 @@ import com.tangem.domain.common.configs.Wallet2CardConfig
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.blockchain.common.CardanoAddressConfig
fun WalletManagerFactory.makeWalletManagerForApp(
scanResponse: ScanResponse,
@ -45,18 +49,19 @@ fun WalletManagerFactory.makeWalletManagerForApp(
}
scanResponse.card.settings.isHDWalletAllowed && seedKey != null && derivationParams != null -> {
val derivedKeys = scanResponse.derivedKeys[wallet.publicKey.toMapKey()]
val derivationPath = when (derivationParams) {
is DerivationParams.Default -> blockchain.derivationPath(derivationParams.style)
is DerivationParams.Custom -> derivationParams.path
}
val derivedKey = derivedKeys?.get(derivationPath)
?: return null
val derivationPath = derivationParams.getPath(blockchain)
val publicKey = makePublicKey(
seedKey = wallet.publicKey,
blockchain = blockchain,
derivationPath = derivationPath ?: return null,
derivedWalletKeys = derivedKeys ?: return null,
isWallet2 = scanResponse.cardTypesResolver.isWallet2(),
)
createWalletManager(
blockchain = environmentBlockchain,
seedKey = wallet.publicKey,
derivedKey = derivedKey,
derivation = derivationParams,
publicKey = publicKey,
)
}
else -> {
@ -69,6 +74,45 @@ fun WalletManagerFactory.makeWalletManagerForApp(
}
}
private fun makePublicKey(
seedKey: ByteArray,
blockchain: Blockchain,
derivationPath: DerivationPath,
derivedWalletKeys: Map<DerivationPath, ExtendedPublicKey>,
isWallet2: Boolean,
): Wallet.PublicKey {
val derivedKey = derivedWalletKeys[derivationPath] ?: error("No derivation found")
val derivationKey = Wallet.HDKey(
path = derivationPath,
extendedPublicKey = derivedKey,
)
// we should generate second key for cardano
// because cardano address generation for wallet2 requires keys from 2 derivations
// https://developers.cardano.org/docs/get-started/cardano-serialization-lib/generating-keys/
if (blockchain == Blockchain.Cardano) {
CardanoAddressConfig.useExtendedAddressing = isWallet2
if (isWallet2) {
val extendedDerivationPath = CardanoUtils.extendedDerivationPath(derivationPath)
val secondDerivedKey = derivedWalletKeys[extendedDerivationPath] ?: error("No derivation found")
val secondDerivationKey = Wallet.HDKey(secondDerivedKey, extendedDerivationPath)
return Wallet.PublicKey(
seedKey = seedKey,
derivationType = Wallet.PublicKey.DerivationType.Double(derivationKey, secondDerivationKey),
)
}
}
return Wallet.PublicKey(
seedKey = seedKey,
derivationType = Wallet.PublicKey.DerivationType.Plain(derivationKey),
)
}
private fun getDerivationParams(card: CardDTO): DerivationParams? {
return if (!card.settings.isHDWalletAllowed) {
null

View file

@ -80,7 +80,7 @@ okHttp-prettyLogging = "3.1.0"
# endregion Other libraries
# region Tangem
tangemBlockchainSdk = "develop-322"
tangemBlockchainSdk = "develop-325"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "develop-289"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds