Updated on 2026-08-14
This commit is contained in:
commit
438126dc82
665 changed files with 16174 additions and 6245 deletions
|
|
@ -32,6 +32,7 @@ dependencies {
|
|||
// region Tangem libraries
|
||||
implementation(tangemDeps.blockchain) // android-library
|
||||
implementation(tangemDeps.card.core)
|
||||
implementation(tangemDeps.hot.core)
|
||||
// endregion
|
||||
|
||||
// region DI
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ plugins {
|
|||
dependencies {
|
||||
// region Tangem libraries
|
||||
implementation(tangemDeps.card.core)
|
||||
implementation(tangemDeps.hot.core)
|
||||
// endregion
|
||||
|
||||
// region Domain modules
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package com.tangem.domain.wallets.models
|
||||
|
||||
import com.tangem.domain.models.MobileWallet
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.wallets.models.UserWallet.Cold
|
||||
import com.tangem.hot.sdk.model.HotWalletId
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
|
@ -56,17 +57,22 @@ sealed interface UserWallet {
|
|||
data class Hot(
|
||||
override val name: String,
|
||||
override val walletId: UserWalletId,
|
||||
val isLocked: Boolean,
|
||||
) : UserWallet
|
||||
val hotWalletId: HotWalletId,
|
||||
val wallets: List<MobileWallet>?,
|
||||
val backedUp: Boolean,
|
||||
) : UserWallet {
|
||||
|
||||
val isLocked: Boolean get() = wallets == null
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun UserWallet.requireColdWallet(): Cold {
|
||||
fun UserWallet.requireColdWallet(): UserWallet.Cold {
|
||||
contract {
|
||||
returns() implies (this@requireColdWallet is Cold)
|
||||
returns() implies (this@requireColdWallet is UserWallet.Cold)
|
||||
}
|
||||
|
||||
return this as? Cold
|
||||
return this as? UserWallet.Cold
|
||||
?: error("This user wallet is not a cold wallet")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
package com.tangem.domain.wallets.builder
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.domain.models.MobileWallet
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.GenerateWalletNameUseCase
|
||||
import com.tangem.hot.sdk.TangemHotSdk
|
||||
import com.tangem.hot.sdk.model.DeriveWalletRequest
|
||||
import com.tangem.hot.sdk.model.HotAuth
|
||||
import com.tangem.hot.sdk.model.HotWalletId
|
||||
import com.tangem.hot.sdk.model.UnlockHotWallet
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class HotUserWalletBuilder @AssistedInject constructor(
|
||||
@Assisted private val hotWalletId: HotWalletId,
|
||||
private val hotSdk: TangemHotSdk,
|
||||
private val generateWalletNameUseCase: GenerateWalletNameUseCase,
|
||||
private val dispatcherProvider: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
suspend fun build(): UserWallet.Hot = withContext(dispatcherProvider.default) {
|
||||
val allNetworks = Blockchain.entries // TODO use HotDerivationsRepository to get supported networks
|
||||
val curves = allNetworks.map { it.getSupportedCurves() }.flatten().toSet()
|
||||
val requests = curves.sortedBy { it.ordinal }.map { curve ->
|
||||
val derivationPaths = allNetworks.filter { curve in it.getSupportedCurves() }
|
||||
.mapNotNull { it.derivationPath(DerivationStyle.V3) }
|
||||
|
||||
DeriveWalletRequest.Request(
|
||||
curve = curve,
|
||||
paths = derivationPaths,
|
||||
)
|
||||
}
|
||||
|
||||
val derivationResult = hotSdk.derivePublicKey(
|
||||
unlockHotWallet = UnlockHotWallet(
|
||||
walletId = hotWalletId,
|
||||
auth = HotAuth.NoAuth,
|
||||
),
|
||||
request = DeriveWalletRequest(
|
||||
requests = requests,
|
||||
),
|
||||
)
|
||||
|
||||
val wallets = derivationResult.responses.map {
|
||||
MobileWallet(
|
||||
publicKey = it.seedKey.publicKey,
|
||||
chainCode = it.seedKey.chainCode,
|
||||
curve = it.curve,
|
||||
derivedKeys = it.publicKeys,
|
||||
)
|
||||
}
|
||||
|
||||
UserWallet.Hot(
|
||||
name = generateWalletNameUseCase.invokeForHot(),
|
||||
walletId = UserWalletIdBuilder.walletPublicKey(wallets.first().publicKey),
|
||||
hotWalletId = hotWalletId,
|
||||
wallets = wallets,
|
||||
backedUp = false,
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(hotWalletId: HotWalletId): HotUserWalletBuilder
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.domain.wallets.repository
|
||||
|
||||
import com.tangem.domain.models.network.Network
|
||||
|
||||
interface HotDerivationsRepository {
|
||||
|
||||
fun getAllSupportedNetworks(): Set<Network>
|
||||
}
|
||||
|
|
@ -21,6 +21,12 @@ class GenerateWalletNameUseCase(
|
|||
return suggestedWalletName(defaultName, existingNames)
|
||||
}
|
||||
|
||||
fun invokeForHot(): String {
|
||||
val defaultName = "Wallet"
|
||||
val existingNames = userWalletsListManager.userWalletsSync.map { it.name }.toSet()
|
||||
return suggestedWalletName(defaultName, existingNames)
|
||||
}
|
||||
|
||||
private fun suggestedWalletName(defaultName: String, existingNames: Set<String>): String {
|
||||
val startIndex = 2
|
||||
if (!existingNames.contains(defaultName)) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.domain.wallets.usecase
|
||||
|
||||
import com.tangem.common.card.FirmwareVersion
|
||||
import com.tangem.common.extensions.toHexString
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.domain.common.TwinCardNumber
|
||||
import com.tangem.domain.common.TwinsHelper
|
||||
|
|
@ -9,20 +8,16 @@ import com.tangem.domain.models.ArtworkModel
|
|||
import com.tangem.domain.wallets.models.Artwork
|
||||
import com.tangem.operations.attestation.ArtworkSize
|
||||
import com.tangem.operations.attestation.CardArtworksProvider
|
||||
import com.tangem.operations.attestation.OnlineCardVerifier
|
||||
import com.tangem.sdk.api.featuretoggles.CardSdkFeatureToggles
|
||||
|
||||
/**
|
||||
* Use case for getting card image url
|
||||
*
|
||||
* @property verifier online card verifier
|
||||
* @property cardArtworksProvider card artworks provider
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class GetCardImageUseCase(
|
||||
private val verifier: OnlineCardVerifier,
|
||||
private val cardArtworksProvider: CardArtworksProvider,
|
||||
private val cardSdkFeatureToggles: CardSdkFeatureToggles,
|
||||
) {
|
||||
|
||||
/**
|
||||
|
|
@ -38,39 +33,17 @@ class GetCardImageUseCase(
|
|||
firmwareVersion: FirmwareVersion,
|
||||
size: ArtworkSize = ArtworkSize.SMALL,
|
||||
): ArtworkModel {
|
||||
return if (cardSdkFeatureToggles.isNewArtworkLoadingEnabled) {
|
||||
val result = cardArtworksProvider.getArtwork(
|
||||
cardId = cardId,
|
||||
cardPublicKey = cardPublicKey,
|
||||
manufacturerName = manufacturerName,
|
||||
firmwareVersion = firmwareVersion,
|
||||
size = size,
|
||||
)
|
||||
when (result) {
|
||||
is Result.Failure -> ArtworkModel(null, getFallbackArtworkUrl(cardId))
|
||||
is Result.Success -> ArtworkModel(result.data, getFallbackArtworkUrl(cardId))
|
||||
}
|
||||
} else {
|
||||
ArtworkModel(null, getLegacyArtwork(cardId, cardPublicKey))
|
||||
}
|
||||
}
|
||||
val result = cardArtworksProvider.getArtwork(
|
||||
cardId = cardId,
|
||||
cardPublicKey = cardPublicKey,
|
||||
manufacturerName = manufacturerName,
|
||||
firmwareVersion = firmwareVersion,
|
||||
size = size,
|
||||
)
|
||||
|
||||
private suspend fun getLegacyArtwork(cardId: String, cardPublicKey: ByteArray): String {
|
||||
return when (val result = verifier.getCardInfo(cardId, cardPublicKey)) {
|
||||
is Result.Success -> {
|
||||
val artworkId = result.data.artwork?.id
|
||||
if (artworkId.isNullOrEmpty()) {
|
||||
getFallbackArtworkUrl(cardId)
|
||||
} else {
|
||||
CardArtworksProvider.getUrlForArtwork(
|
||||
cardId = cardId,
|
||||
cardPublicKey = cardPublicKey.toHexString(),
|
||||
artworkId = artworkId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is Result.Failure -> getFallbackArtworkUrl(cardId)
|
||||
return when (result) {
|
||||
is Result.Failure -> ArtworkModel(null, getFallbackArtworkUrl(cardId))
|
||||
is Result.Success -> ArtworkModel(result.data, getFallbackArtworkUrl(cardId))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue