Updated on 2026-08-14
This commit is contained in:
parent
03f4f51fc7
commit
2f91afa922
67 changed files with 623 additions and 371 deletions
|
|
@ -1,34 +0,0 @@
|
||||||
package com.tangem.tap.di.data
|
|
||||||
|
|
||||||
import com.tangem.data.common.network.NetworkFactory
|
|
||||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
|
||||||
import com.tangem.domain.card.repository.DerivationsRepository
|
|
||||||
import com.tangem.sdk.api.TangemSdkManager
|
|
||||||
import com.tangem.tap.domain.card.DefaultDerivationsRepository
|
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|
||||||
import dagger.Module
|
|
||||||
import dagger.Provides
|
|
||||||
import dagger.hilt.InstallIn
|
|
||||||
import dagger.hilt.components.SingletonComponent
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Module
|
|
||||||
@InstallIn(SingletonComponent::class)
|
|
||||||
internal object CardDataModule {
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun providesDerivationsRepository(
|
|
||||||
tangemSdkManager: TangemSdkManager,
|
|
||||||
userWalletsStore: UserWalletsStore,
|
|
||||||
networkFactory: NetworkFactory,
|
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
|
||||||
): DerivationsRepository {
|
|
||||||
return DefaultDerivationsRepository(
|
|
||||||
tangemSdkManager = tangemSdkManager,
|
|
||||||
userWalletsStore = userWalletsStore,
|
|
||||||
networkFactory = networkFactory,
|
|
||||||
dispatchers = dispatchers,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,11 +2,14 @@ package com.tangem.tap.di.domain
|
||||||
|
|
||||||
import com.tangem.domain.card.*
|
import com.tangem.domain.card.*
|
||||||
import com.tangem.domain.card.repository.CardRepository
|
import com.tangem.domain.card.repository.CardRepository
|
||||||
import com.tangem.domain.card.repository.DerivationsRepository
|
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||||
import com.tangem.domain.demo.models.DemoConfig
|
import com.tangem.domain.demo.models.DemoConfig
|
||||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||||
|
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
|
||||||
|
import com.tangem.domain.wallets.usecase.GetExtendedPublicKeyForCurrencyUseCase
|
||||||
|
import com.tangem.domain.wallets.usecase.HasMissedDerivationsUseCase
|
||||||
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
|
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
|
||||||
import com.tangem.domain.wallets.usecase.NetworkHasDerivationUseCase
|
import com.tangem.domain.wallets.usecase.NetworkHasDerivationUseCase
|
||||||
import com.tangem.sdk.api.TangemSdkManager
|
import com.tangem.sdk.api.TangemSdkManager
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.tangem.tap.di.domain
|
package com.tangem.tap.di.domain
|
||||||
|
|
||||||
import com.tangem.domain.card.repository.DerivationsRepository
|
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||||
import com.tangem.domain.managetokens.*
|
import com.tangem.domain.managetokens.*
|
||||||
import com.tangem.domain.managetokens.repository.CustomTokensRepository
|
import com.tangem.domain.managetokens.repository.CustomTokensRepository
|
||||||
import com.tangem.domain.managetokens.repository.ManageTokensRepository
|
import com.tangem.domain.managetokens.repository.ManageTokensRepository
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.tangem.tap.di.domain
|
package com.tangem.tap.di.domain
|
||||||
|
|
||||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||||
import com.tangem.domain.card.repository.DerivationsRepository
|
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||||
import com.tangem.domain.markets.*
|
import com.tangem.domain.markets.*
|
||||||
import com.tangem.domain.markets.repositories.MarketsTokenRepository
|
import com.tangem.domain.markets.repositories.MarketsTokenRepository
|
||||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.tangem.tap.di.domain
|
package com.tangem.tap.di.domain
|
||||||
|
|
||||||
|
import com.tangem.data.wallets.hot.TangemHotWalletSigner
|
||||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||||
import com.tangem.domain.demo.models.DemoConfig
|
import com.tangem.domain.demo.models.DemoConfig
|
||||||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||||
|
|
@ -11,7 +12,6 @@ import com.tangem.domain.transaction.FeeRepository
|
||||||
import com.tangem.domain.transaction.TransactionRepository
|
import com.tangem.domain.transaction.TransactionRepository
|
||||||
import com.tangem.domain.transaction.usecase.*
|
import com.tangem.domain.transaction.usecase.*
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.tap.domain.hot.TangemHotWalletSigner
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package com.tangem.tap.di.hot
|
package com.tangem.tap.di.hot
|
||||||
|
|
||||||
import com.tangem.hot.sdk.TangemHotSdk
|
import com.tangem.hot.sdk.TangemHotSdk
|
||||||
import com.tangem.tap.domain.hot.HotWalletPasswordRequester
|
|
||||||
import com.tangem.tap.features.hot.DefaultHotWalletPasswordRequester
|
|
||||||
import com.tangem.tap.features.hot.TangemHotSDKProxy
|
import com.tangem.tap.features.hot.TangemHotSDKProxy
|
||||||
import dagger.Binds
|
import dagger.Binds
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
|
|
@ -17,8 +15,4 @@ internal interface TangemHotSdkModule {
|
||||||
@Binds
|
@Binds
|
||||||
@Singleton
|
@Singleton
|
||||||
fun bindTangemHotSdk(proxy: TangemHotSDKProxy): TangemHotSdk
|
fun bindTangemHotSdk(proxy: TangemHotSDKProxy): TangemHotSdk
|
||||||
|
|
||||||
@Binds
|
|
||||||
@Singleton
|
|
||||||
fun bindHotWalletPasswordRequester(impl: DefaultHotWalletPasswordRequester): HotWalletPasswordRequester
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
package com.tangem.tap.domain.hot
|
|
||||||
|
|
||||||
import com.tangem.hot.sdk.model.HotAuth
|
|
||||||
import com.tangem.hot.sdk.model.HotWalletId
|
|
||||||
|
|
||||||
interface HotWalletPasswordRequester {
|
|
||||||
|
|
||||||
suspend fun requestPassword(hotWalletId: HotWalletId): HotAuth.Password
|
|
||||||
}
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
package com.tangem.tap.domain.hot
|
|
||||||
|
|
||||||
import com.tangem.blockchain.common.TransactionSigner
|
|
||||||
import com.tangem.blockchain.common.Wallet
|
|
||||||
import com.tangem.common.CompletionResult
|
|
||||||
import com.tangem.common.core.TangemSdkError
|
|
||||||
import com.tangem.common.map
|
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
|
||||||
import com.tangem.hot.sdk.model.DataToSign
|
|
||||||
import com.tangem.operations.sign.SignData
|
|
||||||
import dagger.assisted.Assisted
|
|
||||||
import dagger.assisted.AssistedFactory
|
|
||||||
import dagger.assisted.AssistedInject
|
|
||||||
|
|
||||||
class TangemHotSigner @AssistedInject constructor(
|
|
||||||
@Assisted private val userWallet: UserWallet.Hot,
|
|
||||||
private val hotWalletAccessor: HotWalletAccessor,
|
|
||||||
) : TransactionSigner {
|
|
||||||
|
|
||||||
override suspend fun sign(hash: ByteArray, publicKey: Wallet.PublicKey): CompletionResult<ByteArray> {
|
|
||||||
return sign(listOf(hash), publicKey).map { it.first() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun sign(
|
|
||||||
hashes: List<ByteArray>,
|
|
||||||
publicKey: Wallet.PublicKey,
|
|
||||||
): CompletionResult<List<ByteArray>> {
|
|
||||||
val wallet = userWallet.wallets.orEmpty().firstOrNull { it.publicKey == publicKey.seedKey }
|
|
||||||
?: return CompletionResult.Failure(
|
|
||||||
TangemSdkError.ExceptionError(IllegalStateException("wallet is locked")),
|
|
||||||
)
|
|
||||||
|
|
||||||
val result = hotWalletAccessor.signHashes(
|
|
||||||
hotWalletId = userWallet.hotWalletId,
|
|
||||||
dataToSign = listOf(
|
|
||||||
DataToSign(
|
|
||||||
curve = wallet.curve,
|
|
||||||
hashes = hashes,
|
|
||||||
derivationPath = publicKey.derivationPath,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
return CompletionResult.Success(result.map { it.signatures }.flatten())
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun multiSign(
|
|
||||||
dataToSign: List<SignData>,
|
|
||||||
publicKey: Wallet.PublicKey,
|
|
||||||
): CompletionResult<Map<ByteArray, ByteArray>> {
|
|
||||||
val result = hotWalletAccessor.signHashes(
|
|
||||||
hotWalletId = userWallet.hotWalletId,
|
|
||||||
dataToSign = dataToSign.map { signData ->
|
|
||||||
val wallet = userWallet.wallets.orEmpty().firstOrNull { it.publicKey == signData.publicKey }
|
|
||||||
?: return CompletionResult.Failure(
|
|
||||||
TangemSdkError.ExceptionError(IllegalStateException("wallet is locked")),
|
|
||||||
)
|
|
||||||
|
|
||||||
DataToSign(
|
|
||||||
curve = wallet.curve,
|
|
||||||
hashes = listOf(signData.hash),
|
|
||||||
derivationPath = signData.derivationPath,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
return CompletionResult.Success(
|
|
||||||
result.mapIndexed { index, data ->
|
|
||||||
dataToSign[index].publicKey to data.signatures.first()
|
|
||||||
}.toMap(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@AssistedFactory
|
|
||||||
interface Factory {
|
|
||||||
fun create(@Assisted userWallet: UserWallet.Hot): TangemHotSigner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -20,7 +20,7 @@ import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||||
import com.tangem.domain.card.common.util.derivationStyleProvider
|
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import com.tangem.common.map
|
||||||
import com.tangem.crypto.bip39.Mnemonic
|
import com.tangem.crypto.bip39.Mnemonic
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.domain.card.CardTypesResolver
|
import com.tangem.domain.card.CardTypesResolver
|
||||||
import com.tangem.domain.card.DerivationStyleProvider
|
import com.tangem.domain.wallets.derivations.DerivationStyleProvider
|
||||||
import com.tangem.domain.card.common.TapWorkarounds.isTestCard
|
import com.tangem.domain.card.common.TapWorkarounds.isTestCard
|
||||||
import com.tangem.domain.card.configs.CardConfig
|
import com.tangem.domain.card.configs.CardConfig
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.datasource.local.token.UserTokensResponseStore
|
import com.tangem.datasource.local.token.UserTokensResponseStore
|
||||||
import com.tangem.domain.card.DerivationStyleProvider
|
import com.tangem.domain.wallets.derivations.DerivationStyleProvider
|
||||||
import com.tangem.domain.card.common.TapWorkarounds.useOldStyleDerivation
|
import com.tangem.domain.card.common.TapWorkarounds.useOldStyleDerivation
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,14 @@ import com.tangem.common.tlv.Tlv
|
||||||
import com.tangem.common.tlv.TlvDecoder
|
import com.tangem.common.tlv.TlvDecoder
|
||||||
import com.tangem.crypto.CryptoUtils
|
import com.tangem.crypto.CryptoUtils
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.domain.card.DerivationStyleProvider
|
import com.tangem.domain.wallets.derivations.DerivationStyleProvider
|
||||||
import com.tangem.domain.card.common.TapWorkarounds.isExcluded
|
import com.tangem.domain.card.common.TapWorkarounds.isExcluded
|
||||||
import com.tangem.domain.card.common.TapWorkarounds.isNotSupportedInThatRelease
|
import com.tangem.domain.card.common.TapWorkarounds.isNotSupportedInThatRelease
|
||||||
import com.tangem.domain.card.common.TapWorkarounds.isStart2Coin
|
import com.tangem.domain.card.common.TapWorkarounds.isStart2Coin
|
||||||
import com.tangem.domain.card.common.TapWorkarounds.isTangemTwins
|
import com.tangem.domain.card.common.TapWorkarounds.isTangemTwins
|
||||||
import com.tangem.domain.card.common.TapWorkarounds.isVisa
|
import com.tangem.domain.card.common.TapWorkarounds.isVisa
|
||||||
import com.tangem.domain.common.TwinsHelper
|
import com.tangem.domain.common.TwinsHelper
|
||||||
import com.tangem.domain.card.common.util.derivationStyleProvider
|
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
||||||
import com.tangem.domain.card.common.visa.VisaUtilities
|
import com.tangem.domain.card.common.visa.VisaUtilities
|
||||||
import com.tangem.domain.card.configs.CardConfig
|
import com.tangem.domain.card.configs.CardConfig
|
||||||
import com.tangem.domain.models.scan.CardDTO
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import com.tangem.common.extensions.toHexString
|
||||||
import com.tangem.core.error.ext.tangemError
|
import com.tangem.core.error.ext.tangemError
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||||
import com.tangem.domain.card.common.util.derivationStyleProvider
|
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
||||||
import com.tangem.domain.card.common.visa.VisaUtilities
|
import com.tangem.domain.card.common.visa.VisaUtilities
|
||||||
import com.tangem.domain.card.common.visa.VisaWalletPublicKeyUtility
|
import com.tangem.domain.card.common.visa.VisaWalletPublicKeyUtility
|
||||||
import com.tangem.domain.card.common.visa.VisaWalletPublicKeyUtility.findKeyWithoutDerivation
|
import com.tangem.domain.card.common.visa.VisaWalletPublicKeyUtility.findKeyWithoutDerivation
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package com.tangem.tap.features.hot
|
|
||||||
|
|
||||||
import com.tangem.hot.sdk.model.HotAuth
|
|
||||||
import com.tangem.hot.sdk.model.HotWalletId
|
|
||||||
import com.tangem.tap.domain.hot.HotWalletPasswordRequester
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class DefaultHotWalletPasswordRequester @Inject constructor() : HotWalletPasswordRequester {
|
|
||||||
|
|
||||||
override suspend fun requestPassword(hotWalletId: HotWalletId): HotAuth.Password {
|
|
||||||
return HotAuth.Password("TODO [REDACTED_TASK_KEY]".toCharArray()) // TODO [REDACTED_TASK_KEY]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -8,8 +8,8 @@ import com.tangem.blockchainsdk.utils.toNetworkId
|
||||||
import com.tangem.common.test.domain.card.MockScanResponseFactory
|
import com.tangem.common.test.domain.card.MockScanResponseFactory
|
||||||
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
|
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
|
||||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||||
import com.tangem.domain.card.DerivationStyleProvider
|
import com.tangem.domain.wallets.derivations.DerivationStyleProvider
|
||||||
import com.tangem.domain.card.common.util.derivationStyleProvider
|
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
||||||
import com.tangem.domain.card.configs.GenericCardConfig
|
import com.tangem.domain.card.configs.GenericCardConfig
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@ import com.tangem.blockchain.common.FeePaidCurrency
|
||||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||||
import com.tangem.blockchainsdk.utils.toBlockchain
|
import com.tangem.blockchainsdk.utils.toBlockchain
|
||||||
import com.tangem.blockchainsdk.utils.toNetworkId
|
import com.tangem.blockchainsdk.utils.toNetworkId
|
||||||
import com.tangem.domain.card.DerivationStyleProvider
|
|
||||||
import com.tangem.domain.card.common.extensions.canHandleToken
|
import com.tangem.domain.card.common.extensions.canHandleToken
|
||||||
import com.tangem.domain.card.common.util.derivationStyleProvider
|
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.wallets.derivations.DerivationStyleProvider
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ import com.tangem.common.test.domain.card.MockScanResponseFactory
|
||||||
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
||||||
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
|
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
|
||||||
import com.tangem.common.test.utils.ProvideTestModels
|
import com.tangem.common.test.utils.ProvideTestModels
|
||||||
import com.tangem.domain.card.DerivationStyleProvider
|
import com.tangem.domain.wallets.derivations.DerivationStyleProvider
|
||||||
import com.tangem.domain.card.configs.GenericCardConfig
|
import com.tangem.domain.card.configs.GenericCardConfig
|
||||||
import com.tangem.domain.card.configs.MultiWalletCardConfig
|
import com.tangem.domain.card.configs.MultiWalletCardConfig
|
||||||
import com.tangem.domain.card.common.util.derivationStyleProvider
|
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ dependencies {
|
||||||
implementation(projects.domain.models)
|
implementation(projects.domain.models)
|
||||||
implementation(projects.domain.manageTokens)
|
implementation(projects.domain.manageTokens)
|
||||||
implementation(projects.domain.card)
|
implementation(projects.domain.card)
|
||||||
|
implementation(projects.domain.wallets)
|
||||||
implementation(projects.domain.tokens.models)
|
implementation(projects.domain.tokens.models)
|
||||||
implementation(projects.domain.wallets.models)
|
implementation(projects.domain.wallets.models)
|
||||||
implementation(projects.domain.legacy)
|
implementation(projects.domain.legacy)
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
||||||
import com.tangem.domain.managetokens.repository.CustomTokensRepository
|
import com.tangem.domain.managetokens.repository.CustomTokensRepository
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.models.wallet.requireColdWallet
|
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
@ -247,7 +247,22 @@ internal class DefaultCustomTokensRepository(
|
||||||
val userWallet = requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
|
val userWallet = requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
|
||||||
"User wallet [$userWalletId] not found while getting supported networks"
|
"User wallet [$userWalletId] not found while getting supported networks"
|
||||||
}
|
}
|
||||||
val scanResponse = userWallet.requireColdWallet().scanResponse // TODO [REDACTED_TASK_KEY]
|
|
||||||
|
when (userWallet) {
|
||||||
|
is UserWallet.Hot -> {
|
||||||
|
Blockchain.entries.mapNotNull {
|
||||||
|
// TODO: refactor [REDACTED_JIRA]\
|
||||||
|
if (it.isTestnet() || it in excludedBlockchains) return@mapNotNull null
|
||||||
|
|
||||||
|
networkFactory.create(
|
||||||
|
blockchain = it,
|
||||||
|
extraDerivationPath = null,
|
||||||
|
userWallet = userWallet,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is UserWallet.Cold -> {
|
||||||
|
val scanResponse = userWallet.scanResponse
|
||||||
|
|
||||||
Blockchain.entries
|
Blockchain.entries
|
||||||
.mapNotNull { blockchain ->
|
.mapNotNull { blockchain ->
|
||||||
|
|
@ -268,6 +283,8 @@ internal class DefaultCustomTokensRepository(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun createDerivationPath(rawPath: String): Network.DerivationPath {
|
override fun createDerivationPath(rawPath: String): Network.DerivationPath {
|
||||||
val sdkPath = DerivationPath(rawPath)
|
val sdkPath = DerivationPath(rawPath)
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,14 @@ import com.tangem.data.common.network.NetworkFactory
|
||||||
import com.tangem.datasource.api.tangemTech.models.CoinsResponse
|
import com.tangem.datasource.api.tangemTech.models.CoinsResponse
|
||||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||||
import com.tangem.datasource.local.config.testnet.models.TestnetTokensConfig
|
import com.tangem.datasource.local.config.testnet.models.TestnetTokensConfig
|
||||||
import com.tangem.domain.card.DerivationStyleProvider
|
|
||||||
import com.tangem.domain.card.common.extensions.canHandleToken
|
import com.tangem.domain.card.common.extensions.canHandleToken
|
||||||
import com.tangem.domain.card.common.util.derivationStyleProvider
|
|
||||||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
||||||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency.SourceNetwork
|
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency.SourceNetwork
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.wallets.derivations.DerivationStyleProvider
|
||||||
|
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
internal class ManagedCryptoCurrencyFactory(
|
internal class ManagedCryptoCurrencyFactory(
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ dependencies {
|
||||||
/** Project - Domain */
|
/** Project - Domain */
|
||||||
implementation(projects.domain.visa)
|
implementation(projects.domain.visa)
|
||||||
implementation(projects.domain.card)
|
implementation(projects.domain.card)
|
||||||
|
implementation(projects.domain.wallets)
|
||||||
implementation(projects.domain.models)
|
implementation(projects.domain.models)
|
||||||
implementation(projects.domain.wallets.models)
|
implementation(projects.domain.wallets.models)
|
||||||
implementation(projects.domain.appCurrency.models)
|
implementation(projects.domain.appCurrency.models)
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,11 @@ package com.tangem.data.visa.utils
|
||||||
import com.tangem.blockchain.common.Blockchain
|
import com.tangem.blockchain.common.Blockchain
|
||||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||||
import com.tangem.data.common.network.NetworkFactory
|
import com.tangem.data.common.network.NetworkFactory
|
||||||
import com.tangem.domain.card.common.util.derivationStyleProvider
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.NetworkAddress
|
import com.tangem.domain.models.network.NetworkAddress
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.models.wallet.requireColdWallet
|
|
||||||
import com.tangem.domain.visa.model.VisaCurrency
|
import com.tangem.domain.visa.model.VisaCurrency
|
||||||
|
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
||||||
import com.tangem.lib.visa.model.VisaContractInfo
|
import com.tangem.lib.visa.model.VisaContractInfo
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import org.joda.time.DateTimeZone
|
import org.joda.time.DateTimeZone
|
||||||
|
|
@ -34,7 +33,7 @@ internal class VisaCurrencyFactory @Inject constructor(
|
||||||
val currencyNetwork = networkFactory.create(
|
val currencyNetwork = networkFactory.create(
|
||||||
blockchain = Blockchain.Polygon,
|
blockchain = Blockchain.Polygon,
|
||||||
extraDerivationPath = null,
|
extraDerivationPath = null,
|
||||||
derivationStyleProvider = userWallet.requireColdWallet().scanResponse.derivationStyleProvider,
|
derivationStyleProvider = userWallet.derivationStyleProvider,
|
||||||
canHandleTokens = true,
|
canHandleTokens = true,
|
||||||
) ?: error("Unable to create network for Visa currency")
|
) ?: error("Unable to create network for Visa currency")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.data.walletmanager.extensions.makePublicKey
|
import com.tangem.data.walletmanager.extensions.makePublicKey
|
||||||
import com.tangem.data.walletmanager.extensions.makeWalletManagerForApp
|
import com.tangem.data.walletmanager.extensions.makeWalletManagerForApp
|
||||||
import com.tangem.domain.card.DerivationStyleProvider
|
import com.tangem.domain.wallets.derivations.DerivationStyleProvider
|
||||||
import com.tangem.domain.card.common.util.derivationStyleProvider
|
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
internal class WalletManagerFactory(
|
internal class WalletManagerFactory(
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,14 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(projects.data.common)
|
||||||
|
|
||||||
/** Tangem libraries */
|
/** Tangem libraries */
|
||||||
implementation(tangemDeps.blockchain) // android-library
|
implementation(tangemDeps.blockchain)
|
||||||
|
implementation(tangemDeps.card.core)
|
||||||
|
implementation(tangemDeps.hot.core)
|
||||||
|
implementation(projects.libs.tangemSdkApi)
|
||||||
|
implementation(projects.libs.blockchainSdk)
|
||||||
|
|
||||||
/** Core */
|
/** Core */
|
||||||
implementation(projects.core.datasource)
|
implementation(projects.core.datasource)
|
||||||
|
|
@ -21,6 +26,7 @@ dependencies {
|
||||||
|
|
||||||
/** Domain */
|
/** Domain */
|
||||||
implementation(projects.domain.wallets)
|
implementation(projects.domain.wallets)
|
||||||
|
implementation(projects.domain.card)
|
||||||
api(projects.domain.models)
|
api(projects.domain.models)
|
||||||
|
|
||||||
/** Domain models */
|
/** Domain models */
|
||||||
|
|
@ -29,15 +35,17 @@ dependencies {
|
||||||
|
|
||||||
/** DI */
|
/** DI */
|
||||||
implementation(deps.hilt.android)
|
implementation(deps.hilt.android)
|
||||||
implementation(project(":domain:legacy"))
|
|
||||||
kapt(deps.hilt.kapt)
|
kapt(deps.hilt.kapt)
|
||||||
|
|
||||||
/** Other deps */
|
/** Other deps */
|
||||||
implementation(deps.androidx.datastore)
|
implementation(deps.androidx.datastore)
|
||||||
implementation(deps.arrow.core)
|
implementation(deps.arrow.core)
|
||||||
|
implementation(deps.kotlin.coroutines)
|
||||||
|
implementation(deps.timber)
|
||||||
|
|
||||||
/** tests */
|
/** tests */
|
||||||
testImplementation(projects.domain.models)
|
testImplementation(projects.domain.models)
|
||||||
|
testImplementation(projects.common.test)
|
||||||
testImplementation(deps.test.junit)
|
testImplementation(deps.test.junit)
|
||||||
testImplementation(deps.test.coroutine)
|
testImplementation(deps.test.coroutine)
|
||||||
testImplementation(deps.test.truth)
|
testImplementation(deps.test.truth)
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,50 @@
|
||||||
package com.tangem.tap.domain.card
|
package com.tangem.data.wallets.cold
|
||||||
|
|
||||||
import com.tangem.blockchain.common.Blockchain
|
import com.tangem.blockchain.common.Blockchain
|
||||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||||
import com.tangem.common.CompletionResult
|
import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.card.EllipticCurve
|
import com.tangem.common.card.EllipticCurve
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.common.doOnFailure
|
|
||||||
import com.tangem.common.doOnSuccess
|
|
||||||
import com.tangem.common.extensions.ByteArrayKey
|
import com.tangem.common.extensions.ByteArrayKey
|
||||||
import com.tangem.common.extensions.toMapKey
|
import com.tangem.common.extensions.toMapKey
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.data.common.network.NetworkFactory
|
import com.tangem.data.common.network.NetworkFactory
|
||||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
import com.tangem.data.wallets.derivations.Derivations
|
||||||
import com.tangem.domain.card.BackendId
|
import com.tangem.data.wallets.derivations.MissedDerivationsFinder
|
||||||
import com.tangem.domain.card.repository.DerivationsRepository
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.wallets.derivations.ColdMapDerivationsRepository
|
||||||
import com.tangem.domain.models.wallet.requireColdWallet
|
import com.tangem.domain.wallets.usecase.BackendId
|
||||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||||
import com.tangem.sdk.api.TangemSdkManager
|
import com.tangem.sdk.api.TangemSdkManager
|
||||||
import com.tangem.tap.domain.tasks.UserWalletIdPreflightReadFilter
|
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal typealias Derivations = Map<ByteArrayKey, List<DerivationPath>>
|
|
||||||
private typealias DerivedKeys = Map<ByteArrayKey, ExtendedPublicKeysMap>
|
private typealias DerivedKeys = Map<ByteArrayKey, ExtendedPublicKeysMap>
|
||||||
|
|
||||||
internal class DefaultDerivationsRepository(
|
internal class DefaultColdMapDerivationsRepository @Inject constructor(
|
||||||
private val tangemSdkManager: TangemSdkManager,
|
private val tangemSdkManager: TangemSdkManager,
|
||||||
private val userWalletsStore: UserWalletsStore,
|
|
||||||
private val networkFactory: NetworkFactory,
|
private val networkFactory: NetworkFactory,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
) : DerivationsRepository {
|
) : ColdMapDerivationsRepository {
|
||||||
|
|
||||||
override suspend fun derivePublicKeys(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
|
override suspend fun derivePublicKeys(
|
||||||
derivePublicKeysByNetworks(userWalletId = userWalletId, networks = currencies.map(CryptoCurrency::network))
|
userWallet: UserWallet.Cold,
|
||||||
|
currencies: List<CryptoCurrency>,
|
||||||
|
): UserWallet.Cold = withContext(dispatchers.io) {
|
||||||
|
derivePublicKeysByNetworks(userWallet = userWallet, networks = currencies.map(CryptoCurrency::network))
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun derivePublicKeysByNetworkIds(userWalletId: UserWalletId, networkIds: List<Network.RawID>) {
|
override suspend fun derivePublicKeysByNetworkIds(
|
||||||
val userWallet = userWalletsStore.getSyncOrNull(userWalletId) ?: error("User wallet not found")
|
userWallet: UserWallet.Cold,
|
||||||
|
networkIds: List<Network.RawID>,
|
||||||
|
): UserWallet.Cold = withContext(dispatchers.io) {
|
||||||
derivePublicKeysByNetworks(
|
derivePublicKeysByNetworks(
|
||||||
userWalletId = userWalletId,
|
userWallet = userWallet,
|
||||||
networks = networkIds.mapNotNull {
|
networks = networkIds.mapNotNull {
|
||||||
networkFactory.create(
|
networkFactory.create(
|
||||||
blockchain = Blockchain.fromNetworkId(it.value) ?: return@mapNotNull null,
|
blockchain = Blockchain.fromNetworkId(it.value) ?: return@mapNotNull null,
|
||||||
|
|
@ -56,44 +55,55 @@ internal class DefaultDerivationsRepository(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun derivePublicKeysByNetworks(userWalletId: UserWalletId, networks: List<Network>) {
|
override suspend fun derivePublicKeysByNetworks(
|
||||||
val userWallet = withContext(dispatchers.io) {
|
userWallet: UserWallet.Cold,
|
||||||
userWalletsStore.getSyncOrNull(userWalletId) ?: error("User wallet not found")
|
networks: List<Network>,
|
||||||
}
|
): UserWallet.Cold = withContext(dispatchers.io) {
|
||||||
|
|
||||||
if (userWallet is UserWallet.Hot) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
userWallet.requireColdWallet()
|
|
||||||
|
|
||||||
if (!userWallet.scanResponse.card.settings.isHDWalletAllowed) {
|
if (!userWallet.scanResponse.card.settings.isHDWalletAllowed) {
|
||||||
Timber.d("Nothing to derive")
|
Timber.d("Nothing to derive")
|
||||||
return
|
return@withContext userWallet
|
||||||
}
|
}
|
||||||
|
|
||||||
val derivations = MissedDerivationsFinder(scanResponse = userWallet.scanResponse)
|
val derivations = MissedDerivationsFinder(userWallet)
|
||||||
.findByNetworks(networks)
|
.findByNetworks(networks)
|
||||||
.ifEmpty {
|
.ifEmpty {
|
||||||
Timber.d("Nothing to derive")
|
Timber.d("Nothing to derive")
|
||||||
return
|
return@withContext userWallet
|
||||||
}
|
}
|
||||||
|
|
||||||
derivePublicKeys(userWalletId = userWalletId, derivations = derivations)
|
return@withContext derivePublicKeys(userWallet = userWallet, derivations = derivations).first
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun derivePublicKeys(
|
||||||
|
userWallet: UserWallet.Cold,
|
||||||
|
derivations: Map<ByteArrayKey, List<DerivationPath>>,
|
||||||
|
): Pair<UserWallet.Cold, Map<ByteArrayKey, ExtendedPublicKeysMap>> = withContext(dispatchers.io) {
|
||||||
|
// todo replace it in task [REDACTED_JIRA]
|
||||||
|
val preflightReadFilter = UserWalletIdPreflightReadFilter(userWallet.walletId)
|
||||||
|
val result = tangemSdkManager.derivePublicKeys(
|
||||||
|
cardId = null,
|
||||||
|
derivations = derivations,
|
||||||
|
preflightReadFilter = preflightReadFilter,
|
||||||
|
)
|
||||||
|
|
||||||
|
when (result) {
|
||||||
|
is CompletionResult.Success -> {
|
||||||
|
userWallet.updateDerivedKeys(result.data.entries).also {
|
||||||
|
validateDerivations(scanResponse = it.scanResponse, derivations = derivations)
|
||||||
|
} to result.data.entries
|
||||||
|
}
|
||||||
|
is CompletionResult.Failure -> {
|
||||||
|
throw result.error
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun hasMissedDerivations(
|
override suspend fun hasMissedDerivations(
|
||||||
userWalletId: UserWalletId,
|
userWallet: UserWallet.Cold,
|
||||||
networksWithDerivationPath: Map<BackendId, String?>,
|
networksWithDerivationPath: Map<BackendId, String?>,
|
||||||
): Boolean {
|
): Boolean = withContext(dispatchers.io) {
|
||||||
val userWallet = userWalletsStore.getSyncOrNull(userWalletId) ?: error("User wallet not found")
|
|
||||||
|
|
||||||
if (userWallet is UserWallet.Hot) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val derivations =
|
val derivations =
|
||||||
MissedDerivationsFinder(scanResponse = userWallet.requireColdWallet().scanResponse)
|
MissedDerivationsFinder(userWallet)
|
||||||
.findByNetworks(
|
.findByNetworks(
|
||||||
networksWithDerivationPath.mapNotNull { (backendId, extraDerivationPath) ->
|
networksWithDerivationPath.mapNotNull { (backendId, extraDerivationPath) ->
|
||||||
networkFactory.create(
|
networkFactory.create(
|
||||||
|
|
@ -104,28 +114,7 @@ internal class DefaultDerivationsRepository(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
return derivations.isNotEmpty()
|
derivations.isNotEmpty()
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun derivePublicKeys(userWalletId: UserWalletId, derivations: Derivations): DerivedKeys {
|
|
||||||
// todo replace it in task [REDACTED_JIRA]
|
|
||||||
val preflightReadFilter = UserWalletIdPreflightReadFilter(userWalletId)
|
|
||||||
tangemSdkManager.derivePublicKeys(
|
|
||||||
cardId = null,
|
|
||||||
derivations = derivations,
|
|
||||||
preflightReadFilter = preflightReadFilter,
|
|
||||||
).doOnSuccess { response ->
|
|
||||||
updatePublicKeys(userWalletId = userWalletId, keys = response.entries)
|
|
||||||
.doOnSuccess {
|
|
||||||
// TODO [REDACTED_TASK_KEY]
|
|
||||||
validateDerivations(scanResponse = it.requireColdWallet().scanResponse, derivations = derivations)
|
|
||||||
return response.entries
|
|
||||||
}
|
|
||||||
.doOnFailure { throw it }
|
|
||||||
}
|
|
||||||
.doOnFailure { throw it }
|
|
||||||
|
|
||||||
error("This code should never be reached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -144,16 +133,7 @@ internal class DefaultDerivationsRepository(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun updatePublicKeys(userWalletId: UserWalletId, keys: DerivedKeys): CompletionResult<UserWallet> {
|
private fun UserWallet.Cold.updateDerivedKeys(keys: DerivedKeys): UserWallet.Cold {
|
||||||
return withContext(dispatchers.io) {
|
|
||||||
userWalletsStore.update(
|
|
||||||
userWalletId = userWalletId,
|
|
||||||
update = { userWallet -> userWallet.requireColdWallet().updateDerivedKeys(keys) }, // TODO [REDACTED_TASK_KEY]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun UserWallet.Cold.updateDerivedKeys(keys: DerivedKeys): UserWallet {
|
|
||||||
return copy(
|
return copy(
|
||||||
scanResponse = scanResponse.copy(
|
scanResponse = scanResponse.copy(
|
||||||
derivedKeys = getUpdatedDerivedKeys(oldKeys = scanResponse.derivedKeys, newKeys = keys),
|
derivedKeys = getUpdatedDerivedKeys(oldKeys = scanResponse.derivedKeys, newKeys = keys),
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.tangem.data.wallets.cold
|
||||||
|
|
||||||
|
import com.tangem.common.card.Card
|
||||||
|
import com.tangem.common.core.SessionEnvironment
|
||||||
|
import com.tangem.common.core.TangemSdkError
|
||||||
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
||||||
|
import com.tangem.operations.preflightread.PreflightReadFilter
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [PreflightReadFilter] for checking if card has expected user wallet id
|
||||||
|
*
|
||||||
|
[REDACTED_AUTHOR]
|
||||||
|
*/
|
||||||
|
class UserWalletIdPreflightReadFilter(private val expectedUserWalletId: UserWalletId) : PreflightReadFilter {
|
||||||
|
|
||||||
|
override fun onCardRead(card: Card, environment: SessionEnvironment) = Unit
|
||||||
|
|
||||||
|
override fun onFullCardRead(card: Card, environment: SessionEnvironment) {
|
||||||
|
val actualUserWalletId = UserWalletIdBuilder.card(card = CardDTO(card)).build() ?: return
|
||||||
|
|
||||||
|
if (expectedUserWalletId != actualUserWalletId) throw TangemSdkError.WalletNotFound()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
package com.tangem.data.wallets.derivations
|
||||||
|
|
||||||
|
import com.tangem.common.CompletionResult
|
||||||
|
import com.tangem.common.extensions.ByteArrayKey
|
||||||
|
import com.tangem.common.map
|
||||||
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
|
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||||
|
import com.tangem.domain.wallets.derivations.ColdMapDerivationsRepository
|
||||||
|
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||||
|
import com.tangem.domain.wallets.derivations.HotMapDerivationsRepository
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.wallets.usecase.BackendId
|
||||||
|
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||||
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal class DefaultDerivationsRepository @Inject constructor(
|
||||||
|
private val userWalletsStore: UserWalletsStore,
|
||||||
|
private val hotDerivationsRepository: HotMapDerivationsRepository,
|
||||||
|
private val coldDerivationsRepository: ColdMapDerivationsRepository,
|
||||||
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
|
) : DerivationsRepository {
|
||||||
|
|
||||||
|
override suspend fun derivePublicKeys(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
|
||||||
|
derivePublicKeysByNetworks(userWalletId = userWalletId, networks = currencies.map(CryptoCurrency::network))
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun derivePublicKeysByNetworkIds(userWalletId: UserWalletId, networkIds: List<Network.RawID>) {
|
||||||
|
val userWallet = userWalletsStore.getSyncStrict(userWalletId)
|
||||||
|
when (userWallet) {
|
||||||
|
is UserWallet.Cold -> coldDerivationsRepository.derivePublicKeysByNetworkIds(userWallet, networkIds)
|
||||||
|
is UserWallet.Hot -> hotDerivationsRepository.derivePublicKeysByNetworkIds(userWallet, networkIds)
|
||||||
|
}.also {
|
||||||
|
userWallet.update(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun derivePublicKeysByNetworks(userWalletId: UserWalletId, networks: List<Network>) {
|
||||||
|
val userWallet = userWalletsStore.getSyncStrict(userWalletId)
|
||||||
|
when (userWallet) {
|
||||||
|
is UserWallet.Cold -> coldDerivationsRepository.derivePublicKeysByNetworks(userWallet, networks)
|
||||||
|
is UserWallet.Hot -> hotDerivationsRepository.derivePublicKeysByNetworks(userWallet, networks)
|
||||||
|
}.also {
|
||||||
|
userWallet.update(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun derivePublicKeys(
|
||||||
|
userWalletId: UserWalletId,
|
||||||
|
derivations: Map<ByteArrayKey, List<DerivationPath>>,
|
||||||
|
): Map<ByteArrayKey, ExtendedPublicKeysMap> {
|
||||||
|
val userWallet = userWalletsStore.getSyncStrict(userWalletId)
|
||||||
|
return when (userWallet) {
|
||||||
|
is UserWallet.Cold -> coldDerivationsRepository.derivePublicKeys(userWallet, derivations)
|
||||||
|
is UserWallet.Hot -> hotDerivationsRepository.derivePublicKeys(userWallet, derivations)
|
||||||
|
}.let {
|
||||||
|
userWallet.update(it.first)
|
||||||
|
it.second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun hasMissedDerivations(
|
||||||
|
userWalletId: UserWalletId,
|
||||||
|
networksWithDerivationPath: Map<BackendId, String?>,
|
||||||
|
): Boolean {
|
||||||
|
return when (val userWallet = userWalletsStore.getSyncStrict(userWalletId)) {
|
||||||
|
is UserWallet.Cold -> coldDerivationsRepository.hasMissedDerivations(userWallet, networksWithDerivationPath)
|
||||||
|
is UserWallet.Hot -> hotDerivationsRepository.hasMissedDerivations(userWallet, networksWithDerivationPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun UserWallet.update(newUserWallet: UserWallet) = withContext(dispatchers.io) {
|
||||||
|
check(this@update.walletId == newUserWallet.walletId) {
|
||||||
|
"Cannot update UserWallet with different walletId: ${newUserWallet.walletId}"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this@update == newUserWallet) {
|
||||||
|
return@withContext // No update needed
|
||||||
|
}
|
||||||
|
|
||||||
|
val updateResult = userWalletsStore.update(
|
||||||
|
userWalletId = newUserWallet.walletId,
|
||||||
|
update = { userWalletToUpdate -> newUserWallet },
|
||||||
|
)
|
||||||
|
|
||||||
|
when (updateResult) {
|
||||||
|
is CompletionResult.Failure -> throw updateResult.error
|
||||||
|
is CompletionResult.Success -> updateResult.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.tangem.tap.domain.card
|
package com.tangem.data.wallets.derivations
|
||||||
|
|
||||||
import com.tangem.blockchain.blockchains.cardano.CardanoUtils
|
import com.tangem.blockchain.blockchains.cardano.CardanoUtils
|
||||||
import com.tangem.blockchain.common.Blockchain
|
import com.tangem.blockchain.common.Blockchain
|
||||||
|
|
@ -8,23 +8,26 @@ import com.tangem.common.extensions.ByteArrayKey
|
||||||
import com.tangem.common.extensions.toMapKey
|
import com.tangem.common.extensions.toMapKey
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.domain.card.configs.CardConfig
|
import com.tangem.domain.card.configs.CardConfig
|
||||||
import com.tangem.domain.card.common.util.derivationStyleProvider
|
import com.tangem.domain.card.configs.Wallet2CardConfig
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
import com.tangem.domain.models.scan.KeyWalletPublicKey
|
import com.tangem.domain.models.scan.KeyWalletPublicKey
|
||||||
import com.tangem.domain.models.scan.ScanResponse
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
||||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||||
|
import kotlin.collections.forEach
|
||||||
|
|
||||||
private typealias DerivationData = Pair<ByteArrayKey, List<DerivationPath>>
|
private typealias DerivationData = Pair<ByteArrayKey, List<DerivationPath>>
|
||||||
|
internal typealias Derivations = Map<ByteArrayKey, List<DerivationPath>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finder of missed derivations
|
* Finder of missed derivations
|
||||||
*
|
*
|
||||||
* @property scanResponse scanning response
|
* @property userWallet User wallet to find derivations for
|
||||||
*
|
*
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
*/
|
*/
|
||||||
internal class MissedDerivationsFinder(private val scanResponse: ScanResponse) {
|
internal class MissedDerivationsFinder(private val userWallet: UserWallet) {
|
||||||
|
|
||||||
/** Find missed derivations for given currencies [currencies] */
|
/** Find missed derivations for given currencies [currencies] */
|
||||||
fun find(currencies: List<CryptoCurrency>): Derivations {
|
fun find(currencies: List<CryptoCurrency>): Derivations {
|
||||||
|
|
@ -48,30 +51,39 @@ internal class MissedDerivationsFinder(private val scanResponse: ScanResponse) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<Network>.mapToNewDerivations(): List<DerivationData> {
|
private fun List<Network>.mapToNewDerivations(): List<DerivationData> {
|
||||||
val config = CardConfig.createConfig(scanResponse.card)
|
val config = when (userWallet) {
|
||||||
|
is UserWallet.Cold -> CardConfig.createConfig(userWallet.scanResponse.card)
|
||||||
|
is UserWallet.Hot -> Wallet2CardConfig // TODO create config [REDACTED_TASK_KEY]
|
||||||
|
}
|
||||||
return mapNotNull { network ->
|
return mapNotNull { network ->
|
||||||
val blockchain = network.toBlockchain()
|
val blockchain = network.toBlockchain()
|
||||||
val curve = config.primaryCurve(blockchain) ?: return@mapNotNull null
|
val curve = config.primaryCurve(blockchain) ?: return@mapNotNull null
|
||||||
|
|
||||||
findNewDerivations(curve = curve, scanResponse = scanResponse, network = network)
|
val walletPublicKey = when (userWallet) {
|
||||||
|
is UserWallet.Cold -> {
|
||||||
|
val wallet = userWallet.scanResponse.card.wallets.firstOrNull { it.curve == curve }
|
||||||
|
wallet?.publicKey
|
||||||
|
}
|
||||||
|
is UserWallet.Hot -> {
|
||||||
|
val wallet = userWallet.wallets?.firstOrNull { it.curve == curve }
|
||||||
|
wallet?.publicKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findNewDerivations(
|
walletPublicKey?.let {
|
||||||
curve: EllipticCurve,
|
findNewDerivations(curve = curve, publicKey = it, network = network)
|
||||||
scanResponse: ScanResponse,
|
}
|
||||||
network: Network,
|
}
|
||||||
): DerivationData? {
|
}
|
||||||
val wallet = scanResponse.card.wallets.firstOrNull { it.curve == curve } ?: return null
|
|
||||||
val publicKey = wallet.publicKey.toMapKey()
|
|
||||||
|
|
||||||
|
private fun findNewDerivations(curve: EllipticCurve, publicKey: ByteArray, network: Network): DerivationData? {
|
||||||
val derivationCandidates = network
|
val derivationCandidates = network
|
||||||
.getDerivationCandidates(curve)
|
.getDerivationCandidates(curve)
|
||||||
.ifEmpty { return null }
|
.ifEmpty { return null }
|
||||||
.filterAlreadyDerivedKeys(publicKey)
|
.filterAlreadyDerivedKeys(publicKey.toMapKey())
|
||||||
.ifEmpty { return null }
|
.ifEmpty { return null }
|
||||||
|
|
||||||
return publicKey to derivationCandidates
|
return publicKey.toMapKey() to derivationCandidates
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Network.getDerivationCandidates(curve: EllipticCurve): List<DerivationPath> {
|
private fun Network.getDerivationCandidates(curve: EllipticCurve): List<DerivationPath> {
|
||||||
|
|
@ -88,7 +100,7 @@ internal class MissedDerivationsFinder(private val scanResponse: ScanResponse) {
|
||||||
|
|
||||||
private fun Blockchain.getDerivationPath(curve: EllipticCurve): DerivationPath? {
|
private fun Blockchain.getDerivationPath(curve: EllipticCurve): DerivationPath? {
|
||||||
return if (getSupportedCurves().contains(curve)) {
|
return if (getSupportedCurves().contains(curve)) {
|
||||||
derivationPath(style = scanResponse.derivationStyleProvider.getDerivationStyle())
|
derivationPath(style = userWallet.derivationStyleProvider.getDerivationStyle())
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +130,15 @@ internal class MissedDerivationsFinder(private val scanResponse: ScanResponse) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAlreadyDerivedKeys(publicKey: KeyWalletPublicKey): List<DerivationPath> {
|
private fun getAlreadyDerivedKeys(publicKey: KeyWalletPublicKey): List<DerivationPath> {
|
||||||
val extendedPublicKeysMap = scanResponse.derivedKeys[publicKey] ?: ExtendedPublicKeysMap(emptyMap())
|
val extendedPublicKeysMap = when (userWallet) {
|
||||||
|
is UserWallet.Cold -> userWallet.scanResponse.derivedKeys[publicKey] ?: ExtendedPublicKeysMap(emptyMap())
|
||||||
|
is UserWallet.Hot -> {
|
||||||
|
val wallets = userWallet.wallets ?: return emptyList()
|
||||||
|
wallets.firstOrNull { it.publicKey.contentEquals(publicKey.bytes) }?.derivedKeys
|
||||||
|
?: ExtendedPublicKeysMap(emptyMap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return extendedPublicKeysMap.keys.toList()
|
return extendedPublicKeysMap.keys.toList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,14 +2,21 @@ package com.tangem.data.wallets.di
|
||||||
|
|
||||||
import com.tangem.data.wallets.DefaultWalletNamesMigrationRepository
|
import com.tangem.data.wallets.DefaultWalletNamesMigrationRepository
|
||||||
import com.tangem.data.wallets.DefaultWalletsRepository
|
import com.tangem.data.wallets.DefaultWalletsRepository
|
||||||
|
import com.tangem.data.wallets.cold.DefaultColdMapDerivationsRepository
|
||||||
|
import com.tangem.data.wallets.derivations.DefaultDerivationsRepository
|
||||||
|
import com.tangem.data.wallets.hot.DefaultHotMapDerivationsRepository
|
||||||
import com.tangem.datasource.api.common.AuthProvider
|
import com.tangem.datasource.api.common.AuthProvider
|
||||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||||
import com.tangem.datasource.local.datastore.RuntimeStateStore
|
import com.tangem.datasource.local.datastore.RuntimeStateStore
|
||||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||||
|
import com.tangem.domain.wallets.derivations.ColdMapDerivationsRepository
|
||||||
|
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||||
|
import com.tangem.domain.wallets.derivations.HotMapDerivationsRepository
|
||||||
import com.tangem.domain.wallets.repository.WalletNamesMigrationRepository
|
import com.tangem.domain.wallets.repository.WalletNamesMigrationRepository
|
||||||
import com.tangem.domain.wallets.repository.WalletsRepository
|
import com.tangem.domain.wallets.repository.WalletsRepository
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
|
import dagger.Binds
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
|
|
@ -45,3 +52,20 @@ internal object WalletsDataModule {
|
||||||
return DefaultWalletNamesMigrationRepository(appPreferencesStore)
|
return DefaultWalletNamesMigrationRepository(appPreferencesStore)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
internal interface WalletsDataBindsModule {
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
fun bindDerivationsRepository(impl: DefaultDerivationsRepository): DerivationsRepository
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
fun bindHotMapDerivationsRepository(impl: DefaultHotMapDerivationsRepository): HotMapDerivationsRepository
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
fun bindColdMapDerivationsRepository(impl: DefaultColdMapDerivationsRepository): ColdMapDerivationsRepository
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
package com.tangem.data.wallets.hot
|
||||||
|
|
||||||
|
import com.tangem.blockchain.common.Blockchain
|
||||||
|
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||||
|
import com.tangem.common.extensions.ByteArrayKey
|
||||||
|
import com.tangem.common.extensions.toMapKey
|
||||||
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
|
import com.tangem.data.common.network.NetworkFactory
|
||||||
|
import com.tangem.data.wallets.derivations.MissedDerivationsFinder
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.wallets.derivations.HotMapDerivationsRepository
|
||||||
|
import com.tangem.domain.wallets.usecase.BackendId
|
||||||
|
import com.tangem.hot.sdk.model.DeriveWalletRequest
|
||||||
|
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||||
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal class DefaultHotMapDerivationsRepository @Inject constructor(
|
||||||
|
private val networkFactory: NetworkFactory,
|
||||||
|
private val hotWalletAccessor: HotWalletAccessor,
|
||||||
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
|
) : HotMapDerivationsRepository {
|
||||||
|
|
||||||
|
override suspend fun derivePublicKeys(
|
||||||
|
userWallet: UserWallet.Hot,
|
||||||
|
currencies: List<CryptoCurrency>,
|
||||||
|
): UserWallet.Hot {
|
||||||
|
return derivePublicKeysByNetworks(userWallet = userWallet, networks = currencies.map(CryptoCurrency::network))
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun derivePublicKeysByNetworkIds(
|
||||||
|
userWallet: UserWallet.Hot,
|
||||||
|
networkIds: List<Network.RawID>,
|
||||||
|
): UserWallet.Hot {
|
||||||
|
return derivePublicKeysByNetworks(
|
||||||
|
userWallet = userWallet,
|
||||||
|
networks = networkIds.mapNotNull {
|
||||||
|
networkFactory.create(
|
||||||
|
blockchain = Blockchain.fromNetworkId(it.value) ?: return@mapNotNull null,
|
||||||
|
extraDerivationPath = null,
|
||||||
|
userWallet = userWallet,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun derivePublicKeysByNetworks(
|
||||||
|
userWallet: UserWallet.Hot,
|
||||||
|
networks: List<Network>,
|
||||||
|
): UserWallet.Hot = withContext(dispatchers.default) {
|
||||||
|
val derivations = MissedDerivationsFinder(userWallet)
|
||||||
|
.findByNetworks(networks)
|
||||||
|
.ifEmpty {
|
||||||
|
Timber.d("Nothing to derive")
|
||||||
|
return@withContext userWallet
|
||||||
|
}
|
||||||
|
|
||||||
|
derivePublicKeys(userWallet, derivations).first
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun derivePublicKeys(
|
||||||
|
userWallet: UserWallet.Hot,
|
||||||
|
derivations: Map<ByteArrayKey, List<DerivationPath>>,
|
||||||
|
): Pair<UserWallet.Hot, Map<ByteArrayKey, ExtendedPublicKeysMap>> {
|
||||||
|
val wallets = userWallet.wallets ?: return userWallet to emptyMap()
|
||||||
|
|
||||||
|
val request = DeriveWalletRequest(
|
||||||
|
derivations.map { entry ->
|
||||||
|
val wallet = wallets.first { it.publicKey.contentEquals(entry.key.bytes) }
|
||||||
|
DeriveWalletRequest.Request(
|
||||||
|
curve = wallet.curve,
|
||||||
|
paths = entry.value,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
val result = hotWalletAccessor.derivePublicKeys(
|
||||||
|
hotWalletId = userWallet.hotWalletId,
|
||||||
|
request = request,
|
||||||
|
)
|
||||||
|
val newKeys =
|
||||||
|
result.responses.associate { ByteArrayKey(it.seedKey.publicKey) to ExtendedPublicKeysMap(it.publicKeys) }
|
||||||
|
|
||||||
|
return userWallet.updateWithNewKeys(newKeys) to newKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun hasMissedDerivations(
|
||||||
|
userWallet: UserWallet.Hot,
|
||||||
|
networksWithDerivationPath: Map<BackendId, String?>,
|
||||||
|
): Boolean = withContext(dispatchers.default) {
|
||||||
|
val derivations = MissedDerivationsFinder(userWallet)
|
||||||
|
.findByNetworks(
|
||||||
|
networksWithDerivationPath.mapNotNull { (backendId, extraDerivationPath) ->
|
||||||
|
networkFactory.create(
|
||||||
|
blockchain = Blockchain.fromNetworkId(backendId) ?: return@mapNotNull null,
|
||||||
|
extraDerivationPath = extraDerivationPath,
|
||||||
|
userWallet = userWallet,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
derivations.isNotEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun UserWallet.Hot.updateWithNewKeys(newKeys: Map<ByteArrayKey, ExtendedPublicKeysMap>): UserWallet.Hot {
|
||||||
|
val wallets = this.wallets ?: return this
|
||||||
|
val derivedKeys = wallets.associate {
|
||||||
|
it.publicKey.toMapKey() to ExtendedPublicKeysMap(it.derivedKeys)
|
||||||
|
}
|
||||||
|
val updatedKeys = getUpdatedDerivedKeys(
|
||||||
|
oldKeys = derivedKeys,
|
||||||
|
newKeys = newKeys,
|
||||||
|
)
|
||||||
|
|
||||||
|
return copy(
|
||||||
|
wallets = wallets.map { wallet ->
|
||||||
|
wallet.copy(
|
||||||
|
derivedKeys = updatedKeys[wallet.publicKey.toMapKey()] ?: ExtendedPublicKeysMap(emptyMap()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getUpdatedDerivedKeys(
|
||||||
|
oldKeys: Map<ByteArrayKey, ExtendedPublicKeysMap>,
|
||||||
|
newKeys: Map<ByteArrayKey, ExtendedPublicKeysMap>,
|
||||||
|
): Map<ByteArrayKey, ExtendedPublicKeysMap> {
|
||||||
|
return (oldKeys.keys + newKeys.keys).toSet()
|
||||||
|
.associateWith { walletKey ->
|
||||||
|
val oldDerivations = ExtendedPublicKeysMap(oldKeys[walletKey] ?: emptyMap())
|
||||||
|
val newDerivations = newKeys[walletKey] ?: ExtendedPublicKeysMap(emptyMap())
|
||||||
|
|
||||||
|
ExtendedPublicKeysMap(oldDerivations + newDerivations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.tangem.tap.domain.hot
|
package com.tangem.data.wallets.hot
|
||||||
|
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.features.hotwallet.HotWalletPasswordRequester
|
import com.tangem.domain.wallets.hot.HotWalletPasswordRequester
|
||||||
import com.tangem.hot.sdk.TangemHotSdk
|
import com.tangem.hot.sdk.TangemHotSdk
|
||||||
import com.tangem.hot.sdk.exception.WrongPasswordException
|
import com.tangem.hot.sdk.exception.WrongPasswordException
|
||||||
import com.tangem.hot.sdk.model.*
|
import com.tangem.hot.sdk.model.*
|
||||||
|
|
@ -12,7 +12,17 @@ class HotWalletAccessor @Inject constructor(
|
||||||
private val hotWalletPasswordRequester: HotWalletPasswordRequester,
|
private val hotWalletPasswordRequester: HotWalletPasswordRequester,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun signHashes(hotWalletId: HotWalletId, dataToSign: List<DataToSign>): List<SignedData> {
|
suspend fun signHashes(hotWalletId: HotWalletId, dataToSign: List<DataToSign>): List<SignedData> =
|
||||||
|
hotSdkRequest(hotWalletId) { unlock ->
|
||||||
|
tangemHotSdk.signHashes(unlockHotWallet = unlock, dataToSign = dataToSign)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun derivePublicKeys(hotWalletId: HotWalletId, request: DeriveWalletRequest): DerivedPublicKeyResponse =
|
||||||
|
hotSdkRequest(hotWalletId) { unlock ->
|
||||||
|
tangemHotSdk.derivePublicKey(unlockHotWallet = unlock, request = request)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun <T> hotSdkRequest(hotWalletId: HotWalletId, block: suspend (unlock: UnlockHotWallet) -> T): T {
|
||||||
val auth = when (hotWalletId.authType) {
|
val auth = when (hotWalletId.authType) {
|
||||||
HotWalletId.AuthType.NoPassword -> HotAuth.NoAuth
|
HotWalletId.AuthType.NoPassword -> HotAuth.NoAuth
|
||||||
HotWalletId.AuthType.Password -> requestPassword(false)
|
HotWalletId.AuthType.Password -> requestPassword(false)
|
||||||
|
|
@ -20,13 +30,7 @@ class HotWalletAccessor @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
return runCatchingSdkErrors(hotWalletId, auth) {
|
return runCatchingSdkErrors(hotWalletId, auth) {
|
||||||
tangemHotSdk.signHashes(
|
block(UnlockHotWallet(hotWalletId, it)).also {
|
||||||
unlockHotWallet = UnlockHotWallet(
|
|
||||||
walletId = hotWalletId,
|
|
||||||
auth = it,
|
|
||||||
),
|
|
||||||
dataToSign = dataToSign,
|
|
||||||
).also {
|
|
||||||
hotWalletPasswordRequester.dismiss()
|
hotWalletPasswordRequester.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.tangem.tap.domain.hot
|
package com.tangem.data.wallets.hot
|
||||||
|
|
||||||
import com.tangem.blockchain.common.TransactionSigner
|
import com.tangem.blockchain.common.TransactionSigner
|
||||||
import com.tangem.blockchain.common.Wallet
|
import com.tangem.blockchain.common.Wallet
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.tangem.tap.domain.card
|
package com.tangem.data.wallets.derivations
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import com.google.common.truth.Truth
|
import com.google.common.truth.Truth
|
||||||
|
|
@ -7,6 +7,7 @@ import com.tangem.common.CompletionResult
|
||||||
import com.tangem.common.test.domain.card.MockScanResponseFactory
|
import com.tangem.common.test.domain.card.MockScanResponseFactory
|
||||||
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
||||||
import com.tangem.data.common.network.NetworkFactory
|
import com.tangem.data.common.network.NetworkFactory
|
||||||
|
import com.tangem.data.wallets.cold.DefaultColdMapDerivationsRepository
|
||||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||||
import com.tangem.domain.card.ScanCardException
|
import com.tangem.domain.card.ScanCardException
|
||||||
import com.tangem.domain.card.configs.GenericCardConfig
|
import com.tangem.domain.card.configs.GenericCardConfig
|
||||||
|
|
@ -14,7 +15,7 @@ import com.tangem.domain.card.configs.MultiWalletCardConfig
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.operations.derivation.DerivationTaskResponse
|
import com.tangem.operations.derivation.DerivationTaskResponse
|
||||||
import com.tangem.tap.domain.sdk.impl.DefaultTangemSdkManager
|
import com.tangem.sdk.api.TangemSdkManager
|
||||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
|
|
@ -27,13 +28,17 @@ import org.junit.Test
|
||||||
*/
|
*/
|
||||||
internal class DefaultDerivationsRepositoryTest {
|
internal class DefaultDerivationsRepositoryTest {
|
||||||
|
|
||||||
private val tangemSdkManager = mockk<DefaultTangemSdkManager>()
|
private val tangemSdkManager = mockk<TangemSdkManager>()
|
||||||
private val userWalletsStore = mockk<UserWalletsStore>()
|
private val userWalletsStore = mockk<UserWalletsStore>()
|
||||||
private val repository = DefaultDerivationsRepository(
|
private val repository = DefaultDerivationsRepository(
|
||||||
tangemSdkManager = tangemSdkManager,
|
|
||||||
userWalletsStore = userWalletsStore,
|
userWalletsStore = userWalletsStore,
|
||||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||||
|
hotDerivationsRepository = mockk(),
|
||||||
|
coldDerivationsRepository = DefaultColdMapDerivationsRepository(
|
||||||
|
tangemSdkManager = tangemSdkManager,
|
||||||
networkFactory = NetworkFactory(excludedBlockchains = ExcludedBlockchains()),
|
networkFactory = NetworkFactory(excludedBlockchains = ExcludedBlockchains()),
|
||||||
|
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
private val defaultUserWalletId = UserWalletId("011")
|
private val defaultUserWalletId = UserWalletId("011")
|
||||||
|
|
@ -48,7 +53,7 @@ internal class DefaultDerivationsRepositoryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `error if userWalletId not found`() = runTest {
|
fun `error if userWalletId not found`() = runTest {
|
||||||
coEvery { userWalletsStore.getSyncOrNull(defaultUserWalletId) } returns null
|
coEvery { userWalletsStore.getSyncStrict(defaultUserWalletId) } throws IllegalStateException()
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
repository.derivePublicKeys(userWalletId = defaultUserWalletId, currencies = emptyList())
|
repository.derivePublicKeys(userWalletId = defaultUserWalletId, currencies = emptyList())
|
||||||
|
|
@ -56,7 +61,7 @@ internal class DefaultDerivationsRepositoryTest {
|
||||||
.onSuccess { error("Should throws exception") }
|
.onSuccess { error("Should throws exception") }
|
||||||
.onFailure { Truth.assertThat(it).isInstanceOf(IllegalStateException::class.java) }
|
.onFailure { Truth.assertThat(it).isInstanceOf(IllegalStateException::class.java) }
|
||||||
|
|
||||||
coVerify(exactly = 1) { userWalletsStore.getSyncOrNull(defaultUserWalletId) }
|
coVerify(exactly = 1) { userWalletsStore.getSyncStrict(defaultUserWalletId) }
|
||||||
coVerify(inverse = true) { tangemSdkManager.derivePublicKeys(null, any(), any()) }
|
coVerify(inverse = true) { tangemSdkManager.derivePublicKeys(null, any(), any()) }
|
||||||
coVerify(inverse = true) { userWalletsStore.update(defaultUserWalletId, any()) }
|
coVerify(inverse = true) { userWalletsStore.update(defaultUserWalletId, any()) }
|
||||||
}
|
}
|
||||||
|
|
@ -64,13 +69,17 @@ internal class DefaultDerivationsRepositoryTest {
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
@Test
|
@Test
|
||||||
fun `success if card is not supported derivations`() = runTest {
|
fun `success if card is not supported derivations`() = runTest {
|
||||||
coEvery { userWalletsStore.getSyncOrNull(defaultUserWalletId) } returns defaultUserWallet
|
coEvery { userWalletsStore.getSyncStrict(defaultUserWalletId) } returns defaultUserWallet
|
||||||
|
|
||||||
runCatching { repository.derivePublicKeys(userWalletId = defaultUserWalletId, currencies = emptyList()) }
|
repository.derivePublicKeys(userWalletId = defaultUserWalletId, currencies = emptyList())
|
||||||
|
|
||||||
|
runCatching { }
|
||||||
.onSuccess { Truth.assertThat(it) }
|
.onSuccess { Truth.assertThat(it) }
|
||||||
.onFailure { error("Should returns success") }
|
.onFailure {
|
||||||
|
error("Should returns success")
|
||||||
|
}
|
||||||
|
|
||||||
coVerify(exactly = 1) { userWalletsStore.getSyncOrNull(defaultUserWalletId) }
|
coVerify(exactly = 1) { userWalletsStore.getSyncStrict(defaultUserWalletId) }
|
||||||
coVerify(inverse = true) { tangemSdkManager.derivePublicKeys(null, any(), any()) }
|
coVerify(inverse = true) { tangemSdkManager.derivePublicKeys(null, any(), any()) }
|
||||||
coVerify(inverse = true) { userWalletsStore.update(defaultUserWalletId, any()) }
|
coVerify(inverse = true) { userWalletsStore.update(defaultUserWalletId, any()) }
|
||||||
}
|
}
|
||||||
|
|
@ -81,13 +90,13 @@ internal class DefaultDerivationsRepositoryTest {
|
||||||
val userWallet = defaultUserWallet.copy(
|
val userWallet = defaultUserWallet.copy(
|
||||||
scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap()),
|
scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap()),
|
||||||
)
|
)
|
||||||
coEvery { userWalletsStore.getSyncOrNull(defaultUserWalletId) } returns userWallet
|
coEvery { userWalletsStore.getSyncStrict(defaultUserWalletId) } returns userWallet
|
||||||
|
|
||||||
runCatching { repository.derivePublicKeys(userWalletId = defaultUserWalletId, currencies = emptyList()) }
|
runCatching { repository.derivePublicKeys(userWalletId = defaultUserWalletId, currencies = emptyList()) }
|
||||||
.onSuccess { Truth.assertThat(it) }
|
.onSuccess { Truth.assertThat(it) }
|
||||||
.onFailure { error("Should returns success") }
|
.onFailure { error("Should returns success") }
|
||||||
|
|
||||||
coVerify(exactly = 1) { userWalletsStore.getSyncOrNull(defaultUserWalletId) }
|
coVerify(exactly = 1) { userWalletsStore.getSyncStrict(defaultUserWalletId) }
|
||||||
coVerify(inverse = true) { tangemSdkManager.derivePublicKeys(null, any(), any()) }
|
coVerify(inverse = true) { tangemSdkManager.derivePublicKeys(null, any(), any()) }
|
||||||
coVerify(inverse = true) { userWalletsStore.update(defaultUserWalletId, any()) }
|
coVerify(inverse = true) { userWalletsStore.update(defaultUserWalletId, any()) }
|
||||||
}
|
}
|
||||||
|
|
@ -102,7 +111,7 @@ internal class DefaultDerivationsRepositoryTest {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
coEvery { userWalletsStore.getSyncOrNull(defaultUserWalletId) } returns userWallet
|
coEvery { userWalletsStore.getSyncStrict(defaultUserWalletId) } returns userWallet
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
repository.derivePublicKeys(
|
repository.derivePublicKeys(
|
||||||
|
|
@ -113,7 +122,7 @@ internal class DefaultDerivationsRepositoryTest {
|
||||||
.onSuccess { Truth.assertThat(it) }
|
.onSuccess { Truth.assertThat(it) }
|
||||||
.onFailure { error("Should returns success") }
|
.onFailure { error("Should returns success") }
|
||||||
|
|
||||||
coVerify(exactly = 1) { userWalletsStore.getSyncOrNull(defaultUserWalletId) }
|
coVerify(exactly = 1) { userWalletsStore.getSyncStrict(defaultUserWalletId) }
|
||||||
coVerify(inverse = true) { tangemSdkManager.derivePublicKeys(null, any(), any()) }
|
coVerify(inverse = true) { tangemSdkManager.derivePublicKeys(null, any(), any()) }
|
||||||
coVerify(inverse = true) { userWalletsStore.update(defaultUserWalletId, any()) }
|
coVerify(inverse = true) { userWalletsStore.update(defaultUserWalletId, any()) }
|
||||||
}
|
}
|
||||||
|
|
@ -123,7 +132,7 @@ internal class DefaultDerivationsRepositoryTest {
|
||||||
val userWallet = defaultUserWallet.copy(
|
val userWallet = defaultUserWallet.copy(
|
||||||
scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap()),
|
scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap()),
|
||||||
)
|
)
|
||||||
coEvery { userWalletsStore.getSyncOrNull(defaultUserWalletId) } returns userWallet
|
coEvery { userWalletsStore.getSyncStrict(defaultUserWalletId) } returns userWallet
|
||||||
coEvery { tangemSdkManager.derivePublicKeys(null, any(), any()) } throws ScanCardException.UserCancelled
|
coEvery { tangemSdkManager.derivePublicKeys(null, any(), any()) } throws ScanCardException.UserCancelled
|
||||||
|
|
||||||
runCatching {
|
runCatching {
|
||||||
|
|
@ -135,7 +144,7 @@ internal class DefaultDerivationsRepositoryTest {
|
||||||
.onSuccess { error("Should throws exception") }
|
.onSuccess { error("Should throws exception") }
|
||||||
.onFailure { Truth.assertThat(it).isInstanceOf(ScanCardException.UserCancelled::class.java) }
|
.onFailure { Truth.assertThat(it).isInstanceOf(ScanCardException.UserCancelled::class.java) }
|
||||||
|
|
||||||
coVerify(exactly = 1) { userWalletsStore.getSyncOrNull(defaultUserWalletId) }
|
coVerify(exactly = 1) { userWalletsStore.getSyncStrict(defaultUserWalletId) }
|
||||||
coVerify(exactly = 1) { tangemSdkManager.derivePublicKeys(null, any(), any()) }
|
coVerify(exactly = 1) { tangemSdkManager.derivePublicKeys(null, any(), any()) }
|
||||||
coVerify(inverse = true) { userWalletsStore.update(defaultUserWalletId, any()) }
|
coVerify(inverse = true) { userWalletsStore.update(defaultUserWalletId, any()) }
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +155,7 @@ internal class DefaultDerivationsRepositoryTest {
|
||||||
val userWallet = defaultUserWallet.copy(
|
val userWallet = defaultUserWallet.copy(
|
||||||
scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap()),
|
scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap()),
|
||||||
)
|
)
|
||||||
coEvery { userWalletsStore.getSyncOrNull(defaultUserWalletId) } returns userWallet
|
coEvery { userWalletsStore.getSyncStrict(defaultUserWalletId) } returns userWallet
|
||||||
coEvery { tangemSdkManager.derivePublicKeys(null, any(), any()) } returns CompletionResult.Success(
|
coEvery { tangemSdkManager.derivePublicKeys(null, any(), any()) } returns CompletionResult.Success(
|
||||||
DerivationTaskResponse(DerivedKeysMocks.ethereumDerivedKeys),
|
DerivationTaskResponse(DerivedKeysMocks.ethereumDerivedKeys),
|
||||||
)
|
)
|
||||||
|
|
@ -161,7 +170,7 @@ internal class DefaultDerivationsRepositoryTest {
|
||||||
.onSuccess { Truth.assertThat(it) }
|
.onSuccess { Truth.assertThat(it) }
|
||||||
.onFailure { error("Should returns success but $it") }
|
.onFailure { error("Should returns success but $it") }
|
||||||
|
|
||||||
coVerify(exactly = 1) { userWalletsStore.getSyncOrNull(defaultUserWalletId) }
|
coVerify(exactly = 1) { userWalletsStore.getSyncStrict(defaultUserWalletId) }
|
||||||
coVerify(exactly = 1) { tangemSdkManager.derivePublicKeys(null, any(), any()) }
|
coVerify(exactly = 1) { tangemSdkManager.derivePublicKeys(null, any(), any()) }
|
||||||
coVerify(exactly = 1) { userWalletsStore.update(defaultUserWalletId, any()) }
|
coVerify(exactly = 1) { userWalletsStore.update(defaultUserWalletId, any()) }
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.tangem.tap.domain.card
|
package com.tangem.data.wallets.derivations
|
||||||
|
|
||||||
import com.tangem.blockchain.common.Blockchain
|
import com.tangem.blockchain.common.Blockchain
|
||||||
import com.tangem.blockchain.common.derivation.DerivationConfigV2
|
import com.tangem.blockchain.common.derivation.DerivationConfigV2
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.tangem.tap.domain.card
|
package com.tangem.data.wallets.derivations
|
||||||
|
|
||||||
import com.google.common.truth.Truth
|
import com.google.common.truth.Truth
|
||||||
import com.tangem.blockchain.blockchains.cardano.CardanoUtils
|
import com.tangem.blockchain.blockchains.cardano.CardanoUtils
|
||||||
|
|
@ -13,7 +13,7 @@ import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.domain.card.configs.GenericCardConfig
|
import com.tangem.domain.card.configs.GenericCardConfig
|
||||||
import com.tangem.domain.card.configs.MultiWalletCardConfig
|
import com.tangem.domain.card.configs.MultiWalletCardConfig
|
||||||
import com.tangem.domain.card.configs.Wallet2CardConfig
|
import com.tangem.domain.card.configs.Wallet2CardConfig
|
||||||
import com.tangem.domain.card.common.util.derivationStyleProvider
|
import com.tangem.domain.wallets.derivations.derivationStyleProvider
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -24,7 +24,8 @@ internal class MissedDerivationsFinderTest {
|
||||||
@Test
|
@Test
|
||||||
fun `empty derivations for empty currencies`() {
|
fun `empty derivations for empty currencies`() {
|
||||||
val scanResponse = MockScanResponseFactory.create(cardConfig = GenericCardConfig(2), derivedKeys = emptyMap())
|
val scanResponse = MockScanResponseFactory.create(cardConfig = GenericCardConfig(2), derivedKeys = emptyMap())
|
||||||
val finder = MissedDerivationsFinder(scanResponse)
|
val userWallet = MockUserWalletFactory.create(scanResponse)
|
||||||
|
val finder = MissedDerivationsFinder(userWallet)
|
||||||
|
|
||||||
val actual = finder.find(emptyList())
|
val actual = finder.find(emptyList())
|
||||||
|
|
||||||
|
|
@ -36,7 +37,7 @@ internal class MissedDerivationsFinderTest {
|
||||||
// Bls is not supported
|
// Bls is not supported
|
||||||
val scanResponse = MockScanResponseFactory.create(cardConfig = GenericCardConfig(2), derivedKeys = emptyMap())
|
val scanResponse = MockScanResponseFactory.create(cardConfig = GenericCardConfig(2), derivedKeys = emptyMap())
|
||||||
val userWallet = MockUserWalletFactory.create(scanResponse)
|
val userWallet = MockUserWalletFactory.create(scanResponse)
|
||||||
val finder = MissedDerivationsFinder(scanResponse)
|
val finder = MissedDerivationsFinder(userWallet)
|
||||||
|
|
||||||
val currencies = MockCryptoCurrencyFactory(userWallet).chia.let(::listOf)
|
val currencies = MockCryptoCurrencyFactory(userWallet).chia.let(::listOf)
|
||||||
val actual = finder.find(currencies)
|
val actual = finder.find(currencies)
|
||||||
|
|
@ -58,7 +59,7 @@ internal class MissedDerivationsFinderTest {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val userWallet = MockUserWalletFactory.create(scanResponse)
|
val userWallet = MockUserWalletFactory.create(scanResponse)
|
||||||
val finder = MissedDerivationsFinder(scanResponse)
|
val finder = MissedDerivationsFinder(userWallet)
|
||||||
|
|
||||||
val currencies = MockCryptoCurrencyFactory(userWallet).chiaAndEthereum
|
val currencies = MockCryptoCurrencyFactory(userWallet).chiaAndEthereum
|
||||||
val actual = finder.find(currencies)
|
val actual = finder.find(currencies)
|
||||||
|
|
@ -73,7 +74,7 @@ internal class MissedDerivationsFinderTest {
|
||||||
fun `derivations for custom token`() {
|
fun `derivations for custom token`() {
|
||||||
val scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap())
|
val scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap())
|
||||||
val userWallet = MockUserWalletFactory.create(scanResponse)
|
val userWallet = MockUserWalletFactory.create(scanResponse)
|
||||||
val finder = MissedDerivationsFinder(scanResponse)
|
val finder = MissedDerivationsFinder(userWallet)
|
||||||
|
|
||||||
val currencies = MockCryptoCurrencyFactory(userWallet).ethereumTokenWithBinanceDerivation
|
val currencies = MockCryptoCurrencyFactory(userWallet).ethereumTokenWithBinanceDerivation
|
||||||
val actual = finder.find(currencies)
|
val actual = finder.find(currencies)
|
||||||
|
|
@ -91,7 +92,7 @@ internal class MissedDerivationsFinderTest {
|
||||||
fun `derivations for cardano`() {
|
fun `derivations for cardano`() {
|
||||||
val scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap())
|
val scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap())
|
||||||
val userWallet = MockUserWalletFactory.create(scanResponse)
|
val userWallet = MockUserWalletFactory.create(scanResponse)
|
||||||
val finder = MissedDerivationsFinder(scanResponse)
|
val finder = MissedDerivationsFinder(userWallet)
|
||||||
|
|
||||||
val currencies = MockCryptoCurrencyFactory(userWallet).cardano.let(::listOf)
|
val currencies = MockCryptoCurrencyFactory(userWallet).cardano.let(::listOf)
|
||||||
val actual = finder.find(currencies)
|
val actual = finder.find(currencies)
|
||||||
|
|
@ -117,7 +118,7 @@ internal class MissedDerivationsFinderTest {
|
||||||
derivedKeys = DerivedKeysMocks.ethereumDerivedKeys,
|
derivedKeys = DerivedKeysMocks.ethereumDerivedKeys,
|
||||||
)
|
)
|
||||||
val userWallet = MockUserWalletFactory.create(scanResponse)
|
val userWallet = MockUserWalletFactory.create(scanResponse)
|
||||||
val finder = MissedDerivationsFinder(scanResponse)
|
val finder = MissedDerivationsFinder(userWallet)
|
||||||
|
|
||||||
val currencies = MockCryptoCurrencyFactory(userWallet).ethereum.let(::listOf)
|
val currencies = MockCryptoCurrencyFactory(userWallet).ethereum.let(::listOf)
|
||||||
val actual = finder.find(currencies)
|
val actual = finder.find(currencies)
|
||||||
|
|
@ -132,7 +133,7 @@ internal class MissedDerivationsFinderTest {
|
||||||
derivedKeys = DerivedKeysMocks.ethereumDerivedKeys,
|
derivedKeys = DerivedKeysMocks.ethereumDerivedKeys,
|
||||||
)
|
)
|
||||||
val userWallet = MockUserWalletFactory.create(scanResponse)
|
val userWallet = MockUserWalletFactory.create(scanResponse)
|
||||||
val finder = MissedDerivationsFinder(scanResponse)
|
val finder = MissedDerivationsFinder(userWallet)
|
||||||
|
|
||||||
val currencies = MockCryptoCurrencyFactory(userWallet).ethereumAndStellar
|
val currencies = MockCryptoCurrencyFactory(userWallet).ethereumAndStellar
|
||||||
val actual = finder.find(currencies)
|
val actual = finder.find(currencies)
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.tangem.domain.card
|
package com.tangem.domain.card
|
||||||
|
|
||||||
import com.tangem.blockchain.common.Blockchain
|
import com.tangem.blockchain.common.Blockchain
|
||||||
|
import com.tangem.blockchain.common.Blockchain.Companion.fromId
|
||||||
import com.tangem.blockchain.common.Token
|
import com.tangem.blockchain.common.Token
|
||||||
import com.tangem.common.card.EllipticCurve
|
import com.tangem.common.card.EllipticCurve
|
||||||
import com.tangem.common.card.FirmwareVersion
|
import com.tangem.common.card.FirmwareVersion
|
||||||
|
|
@ -76,7 +77,7 @@ internal class TangemCardTypesResolver(
|
||||||
} else {
|
} else {
|
||||||
return Blockchain.Unknown
|
return Blockchain.Unknown
|
||||||
}
|
}
|
||||||
Blockchain.Companion.fromBlockchainName(blockchainName)
|
Blockchain.fromBlockchainName(blockchainName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,7 @@ import com.tangem.common.card.EllipticCurve
|
||||||
import com.tangem.common.extensions.toMapKey
|
import com.tangem.common.extensions.toMapKey
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.domain.card.CardTypesResolver
|
import com.tangem.domain.card.CardTypesResolver
|
||||||
import com.tangem.domain.card.DerivationStyleProvider
|
|
||||||
import com.tangem.domain.card.TangemCardTypesResolver
|
import com.tangem.domain.card.TangemCardTypesResolver
|
||||||
import com.tangem.domain.card.TangemDerivationStyleProvider
|
|
||||||
import com.tangem.domain.card.TangemHotDerivationStyleProvider
|
|
||||||
import com.tangem.domain.card.common.TapWorkarounds.isTangemTwins
|
import com.tangem.domain.card.common.TapWorkarounds.isTangemTwins
|
||||||
import com.tangem.domain.card.common.TapWorkarounds.isTestCard
|
import com.tangem.domain.card.common.TapWorkarounds.isTestCard
|
||||||
import com.tangem.domain.card.configs.CardConfig
|
import com.tangem.domain.card.configs.CardConfig
|
||||||
|
|
@ -25,18 +22,6 @@ val ScanResponse.cardTypesResolver: CardTypesResolver
|
||||||
walletData = walletData,
|
walletData = walletData,
|
||||||
)
|
)
|
||||||
|
|
||||||
val UserWallet.derivationStyleProvider: DerivationStyleProvider
|
|
||||||
get() = when (this) {
|
|
||||||
is UserWallet.Cold -> this.scanResponse.derivationStyleProvider
|
|
||||||
is UserWallet.Hot -> TangemHotDerivationStyleProvider()
|
|
||||||
}
|
|
||||||
|
|
||||||
val ScanResponse.derivationStyleProvider: DerivationStyleProvider
|
|
||||||
get() = card.derivationStyleProvider
|
|
||||||
|
|
||||||
val CardDTO.derivationStyleProvider: DerivationStyleProvider
|
|
||||||
get() = TangemDerivationStyleProvider(this)
|
|
||||||
|
|
||||||
val UserWallet.Cold.cardTypesResolver: CardTypesResolver
|
val UserWallet.Cold.cardTypesResolver: CardTypesResolver
|
||||||
get() = scanResponse.cardTypesResolver
|
get() = scanResponse.cardTypesResolver
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ dependencies {
|
||||||
implementation(projects.domain.staking)
|
implementation(projects.domain.staking)
|
||||||
implementation(projects.domain.tokens)
|
implementation(projects.domain.tokens)
|
||||||
implementation(projects.domain.card)
|
implementation(projects.domain.card)
|
||||||
|
implementation(projects.domain.wallets)
|
||||||
implementation(projects.domain.legacy)
|
implementation(projects.domain.legacy)
|
||||||
|
|
||||||
/* Core */
|
/* Core */
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package com.tangem.domain.managetokens
|
||||||
|
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import arrow.core.flatten
|
import arrow.core.flatten
|
||||||
import com.tangem.domain.card.repository.DerivationsRepository
|
|
||||||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
||||||
import com.tangem.domain.managetokens.repository.CustomTokensRepository
|
import com.tangem.domain.managetokens.repository.CustomTokensRepository
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
|
@ -14,6 +13,7 @@ import com.tangem.domain.staking.StakingIdFactory
|
||||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
|
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
class SaveManagedTokensUseCase(
|
class SaveManagedTokensUseCase(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.tangem.domain.markets
|
package com.tangem.domain.markets
|
||||||
|
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import com.tangem.domain.card.repository.DerivationsRepository
|
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||||
import com.tangem.domain.markets.repositories.MarketsTokenRepository
|
import com.tangem.domain.markets.repositories.MarketsTokenRepository
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ class HotUserWalletBuilder @AssistedInject constructor(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun build(): UserWallet.Hot = withContext(dispatcherProvider.default) {
|
suspend fun build(): UserWallet.Hot = withContext(dispatcherProvider.default) {
|
||||||
val allNetworks = Blockchain.entries
|
val allNetworks = Blockchain.entries // TODO [REDACTED_TASK_KEY] add derivation config
|
||||||
val curves = allNetworks.map { it.getSupportedCurves() }.flatten().toSet()
|
val curves = allNetworks.map { it.getSupportedCurves() }.flatten().toSet()
|
||||||
val requests = curves.sortedBy { it.ordinal }.map { curve ->
|
val requests = curves.sortedBy { it.ordinal }.map { curve ->
|
||||||
val derivationPaths = allNetworks.filter { curve in it.getSupportedCurves() }
|
val derivationPaths = allNetworks.filter { curve in it.getSupportedCurves() }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.tangem.domain.wallets.derivations
|
||||||
|
|
||||||
|
import com.tangem.common.extensions.ByteArrayKey
|
||||||
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.wallets.usecase.BackendId
|
||||||
|
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||||
|
|
||||||
|
interface ColdMapDerivationsRepository {
|
||||||
|
|
||||||
|
@Throws
|
||||||
|
suspend fun derivePublicKeys(userWallet: UserWallet.Cold, currencies: List<CryptoCurrency>): UserWallet.Cold
|
||||||
|
|
||||||
|
suspend fun derivePublicKeysByNetworkIds(
|
||||||
|
userWallet: UserWallet.Cold,
|
||||||
|
networkIds: List<Network.RawID>,
|
||||||
|
): UserWallet.Cold
|
||||||
|
|
||||||
|
@Throws
|
||||||
|
suspend fun derivePublicKeysByNetworks(userWallet: UserWallet.Cold, networks: List<Network>): UserWallet.Cold
|
||||||
|
|
||||||
|
@Throws
|
||||||
|
suspend fun derivePublicKeys(
|
||||||
|
userWallet: UserWallet.Cold,
|
||||||
|
derivations: Map<ByteArrayKey, List<DerivationPath>>,
|
||||||
|
): Pair<UserWallet.Cold, Map<ByteArrayKey, ExtendedPublicKeysMap>>
|
||||||
|
|
||||||
|
/** Check if user [userWallet] has missed derivations using map of [Network.ID] with extraDerivationPath */
|
||||||
|
suspend fun hasMissedDerivations(
|
||||||
|
userWallet: UserWallet.Cold,
|
||||||
|
networksWithDerivationPath: Map<BackendId, String?>,
|
||||||
|
): Boolean
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.tangem.domain.card
|
package com.tangem.domain.wallets.derivations
|
||||||
|
|
||||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||||
import com.tangem.domain.card.common.TapWorkarounds.isWallet2
|
import com.tangem.domain.card.common.TapWorkarounds.isWallet2
|
||||||
|
|
@ -25,7 +25,6 @@ internal class TangemDerivationStyleProvider(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove this class [REDACTED_TASK_KEY]
|
|
||||||
internal class TangemHotDerivationStyleProvider : DerivationStyleProvider {
|
internal class TangemHotDerivationStyleProvider : DerivationStyleProvider {
|
||||||
override fun getDerivationStyle(): DerivationStyle? = DerivationStyle.V3
|
override fun getDerivationStyle(): DerivationStyle? = DerivationStyle.V3
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.tangem.domain.wallets.derivations
|
||||||
|
|
||||||
|
import com.tangem.domain.models.scan.CardDTO
|
||||||
|
import com.tangem.domain.models.scan.ScanResponse
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
|
||||||
|
val UserWallet.derivationStyleProvider: DerivationStyleProvider
|
||||||
|
get() = when (this) {
|
||||||
|
is UserWallet.Cold -> scanResponse.derivationStyleProvider
|
||||||
|
is UserWallet.Hot -> TangemHotDerivationStyleProvider()
|
||||||
|
}
|
||||||
|
|
||||||
|
val ScanResponse.derivationStyleProvider: DerivationStyleProvider
|
||||||
|
get() = card.derivationStyleProvider
|
||||||
|
|
||||||
|
val CardDTO.derivationStyleProvider: DerivationStyleProvider
|
||||||
|
get() = TangemDerivationStyleProvider(this)
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
package com.tangem.domain.card.repository
|
package com.tangem.domain.wallets.derivations
|
||||||
|
|
||||||
import com.tangem.common.extensions.ByteArrayKey
|
import com.tangem.common.extensions.ByteArrayKey
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.domain.card.BackendId
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.wallets.usecase.BackendId
|
||||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||||
|
|
||||||
interface DerivationsRepository {
|
interface DerivationsRepository {
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.tangem.domain.wallets.derivations
|
||||||
|
|
||||||
|
import com.tangem.common.extensions.ByteArrayKey
|
||||||
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
import com.tangem.domain.models.network.Network
|
||||||
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
|
import com.tangem.domain.wallets.usecase.BackendId
|
||||||
|
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||||
|
|
||||||
|
interface HotMapDerivationsRepository {
|
||||||
|
|
||||||
|
@Throws
|
||||||
|
suspend fun derivePublicKeys(userWallet: UserWallet.Hot, currencies: List<CryptoCurrency>): UserWallet.Hot
|
||||||
|
|
||||||
|
suspend fun derivePublicKeysByNetworkIds(
|
||||||
|
userWallet: UserWallet.Hot,
|
||||||
|
networkIds: List<Network.RawID>,
|
||||||
|
): UserWallet.Hot
|
||||||
|
|
||||||
|
@Throws
|
||||||
|
suspend fun derivePublicKeysByNetworks(userWallet: UserWallet.Hot, networks: List<Network>): UserWallet.Hot
|
||||||
|
|
||||||
|
@Throws
|
||||||
|
suspend fun derivePublicKeys(
|
||||||
|
userWallet: UserWallet.Hot,
|
||||||
|
derivations: Map<ByteArrayKey, List<DerivationPath>>,
|
||||||
|
): Pair<UserWallet.Hot, Map<ByteArrayKey, ExtendedPublicKeysMap>>
|
||||||
|
|
||||||
|
/** Check if user [userWallet] has missed derivations using map of [Network.ID] with extraDerivationPath */
|
||||||
|
suspend fun hasMissedDerivations(
|
||||||
|
userWallet: UserWallet.Hot,
|
||||||
|
networksWithDerivationPath: Map<BackendId, String?>,
|
||||||
|
): Boolean
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.tangem.features.hotwallet
|
package com.tangem.domain.wallets.hot
|
||||||
|
|
||||||
import com.tangem.hot.sdk.model.HotAuth
|
import com.tangem.hot.sdk.model.HotAuth
|
||||||
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package com.tangem.domain.wallets.repository
|
|
||||||
|
|
||||||
import com.tangem.domain.models.network.Network
|
|
||||||
|
|
||||||
interface HotDerivationsRepository {
|
|
||||||
|
|
||||||
fun getAllSupportedNetworks(): Set<Network>
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
package com.tangem.domain.card
|
|
||||||
|
package com.tangem.domain.wallets.usecase
|
||||||
|
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import com.tangem.domain.card.repository.DerivationsRepository
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||||
|
|
||||||
class DerivePublicKeysUseCase(
|
class DerivePublicKeysUseCase(
|
||||||
private val derivationsRepository: DerivationsRepository,
|
private val derivationsRepository: DerivationsRepository,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend operator fun invoke(userWalletId: UserWalletId, currencies: List<CryptoCurrency>): Either<Throwable, Unit> {
|
suspend operator fun invoke(userWalletId: UserWalletId, currencies: List<CryptoCurrency>): Either<Throwable, Unit> {
|
||||||
return Either.catch {
|
return Either.Companion.catch {
|
||||||
derivationsRepository.derivePublicKeys(userWalletId, currencies)
|
derivationsRepository.derivePublicKeys(userWalletId, currencies)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.tangem.domain.card
|
package com.tangem.domain.wallets.usecase
|
||||||
|
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import arrow.core.right
|
import arrow.core.right
|
||||||
|
|
@ -10,10 +10,10 @@ import com.tangem.common.extensions.calculateSha256
|
||||||
import com.tangem.crypto.NetworkType
|
import com.tangem.crypto.NetworkType
|
||||||
import com.tangem.crypto.hdWallet.DerivationPath
|
import com.tangem.crypto.hdWallet.DerivationPath
|
||||||
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
|
||||||
import com.tangem.domain.card.repository.DerivationsRepository
|
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
|
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1,22 +1,20 @@
|
||||||
package com.tangem.domain.card
|
package com.tangem.domain.wallets.usecase
|
||||||
|
|
||||||
import com.tangem.domain.card.repository.DerivationsRepository
|
|
||||||
import com.tangem.domain.models.network.Network
|
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.wallets.derivations.DerivationsRepository
|
||||||
|
|
||||||
|
typealias BackendId = String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use case to check if user has missed derivations
|
* Use case to check if user has missed derivations
|
||||||
*
|
*
|
||||||
[REDACTED_AUTHOR]
|
[REDACTED_AUTHOR]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typealias BackendId = String
|
|
||||||
|
|
||||||
class HasMissedDerivationsUseCase(
|
class HasMissedDerivationsUseCase(
|
||||||
private val derivationsRepository: DerivationsRepository,
|
private val derivationsRepository: DerivationsRepository,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/** Check if user [userWalletId] has missed derivations using map of [Network.ID] with extraDerivationPath */
|
/** Check if user [userWalletId] has missed derivations using map of [com.tangem.domain.models.network.Network.ID] with extraDerivationPath */
|
||||||
suspend operator fun invoke(
|
suspend operator fun invoke(
|
||||||
userWalletId: UserWalletId,
|
userWalletId: UserWalletId,
|
||||||
networksWithDerivationPath: Map<BackendId, String?>,
|
networksWithDerivationPath: Map<BackendId, String?>,
|
||||||
|
|
@ -12,6 +12,7 @@ dependencies {
|
||||||
|
|
||||||
/* Project - Domain */
|
/* Project - Domain */
|
||||||
implementation(projects.domain.models)
|
implementation(projects.domain.models)
|
||||||
|
implementation(projects.domain.wallets)
|
||||||
implementation(projects.domain.wallets.models)
|
implementation(projects.domain.wallets.models)
|
||||||
|
|
||||||
/* Project - Core */
|
/* Project - Core */
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.tangem.features.hotwallet
|
||||||
|
|
||||||
import com.tangem.core.decompose.factory.ComponentFactory
|
import com.tangem.core.decompose.factory.ComponentFactory
|
||||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||||
|
import com.tangem.domain.wallets.hot.HotWalletPasswordRequester
|
||||||
|
|
||||||
interface HotAccessCodeRequestComponent : ComposableContentComponent, HotWalletPasswordRequester {
|
interface HotAccessCodeRequestComponent : ComposableContentComponent, HotWalletPasswordRequester {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
package com.tangem.features.hotwallet.accesscoderequest
|
package com.tangem.features.hotwallet.accesscoderequest
|
||||||
|
|
||||||
import androidx.compose.foundation.focusable
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.tangem.core.decompose.context.AppComponentContext
|
import com.tangem.core.decompose.context.AppComponentContext
|
||||||
import com.tangem.core.decompose.model.getOrCreateModel
|
import com.tangem.core.decompose.model.getOrCreateModel
|
||||||
import com.tangem.core.ui.components.FullScreen
|
import com.tangem.core.ui.components.FullScreen
|
||||||
|
import com.tangem.domain.wallets.hot.HotWalletPasswordRequester
|
||||||
import com.tangem.features.hotwallet.HotAccessCodeRequestComponent
|
import com.tangem.features.hotwallet.HotAccessCodeRequestComponent
|
||||||
import com.tangem.features.hotwallet.HotWalletPasswordRequester
|
|
||||||
import com.tangem.features.hotwallet.accesscoderequest.ui.HotAccessCodeRequestFullScreenContent
|
import com.tangem.features.hotwallet.accesscoderequest.ui.HotAccessCodeRequestFullScreenContent
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package com.tangem.features.hotwallet.accesscoderequest
|
||||||
|
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.model.Model
|
import com.tangem.core.decompose.model.Model
|
||||||
import com.tangem.features.hotwallet.HotWalletPasswordRequester
|
import com.tangem.domain.wallets.hot.HotWalletPasswordRequester
|
||||||
import com.tangem.features.hotwallet.accesscoderequest.entity.HotAccessCodeRequestUM
|
import com.tangem.features.hotwallet.accesscoderequest.entity.HotAccessCodeRequestUM
|
||||||
import com.tangem.hot.sdk.model.HotAuth
|
import com.tangem.hot.sdk.model.HotAuth
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package com.tangem.features.hotwallet.accesscoderequest.di
|
package com.tangem.features.hotwallet.accesscoderequest.di
|
||||||
|
|
||||||
import com.tangem.core.decompose.model.Model
|
import com.tangem.core.decompose.model.Model
|
||||||
|
import com.tangem.domain.wallets.hot.HotWalletPasswordRequester
|
||||||
import com.tangem.features.hotwallet.HotAccessCodeRequestComponent
|
import com.tangem.features.hotwallet.HotAccessCodeRequestComponent
|
||||||
import com.tangem.features.hotwallet.HotWalletPasswordRequester
|
|
||||||
import com.tangem.features.hotwallet.accesscoderequest.DefaultHotAccessCodeRequestComponent
|
import com.tangem.features.hotwallet.accesscoderequest.DefaultHotAccessCodeRequestComponent
|
||||||
import com.tangem.features.hotwallet.accesscoderequest.HotAccessCodeRequestModel
|
import com.tangem.features.hotwallet.accesscoderequest.HotAccessCodeRequestModel
|
||||||
import com.tangem.features.hotwallet.accesscoderequest.proxy.HotWalletPasswordRequesterProxy
|
import com.tangem.features.hotwallet.accesscoderequest.proxy.HotWalletPasswordRequesterProxy
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package com.tangem.features.hotwallet.accesscoderequest.proxy
|
package com.tangem.features.hotwallet.accesscoderequest.proxy
|
||||||
|
|
||||||
import com.tangem.features.hotwallet.HotWalletPasswordRequester
|
import com.tangem.domain.wallets.hot.HotWalletPasswordRequester
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ dependencies {
|
||||||
implementation(projects.domain.manageTokens)
|
implementation(projects.domain.manageTokens)
|
||||||
implementation(projects.domain.tokens)
|
implementation(projects.domain.tokens)
|
||||||
implementation(projects.domain.tokens.models)
|
implementation(projects.domain.tokens.models)
|
||||||
|
implementation(projects.domain.wallets)
|
||||||
implementation(projects.domain.wallets.models)
|
implementation(projects.domain.wallets.models)
|
||||||
implementation(projects.domain.swap.models)
|
implementation(projects.domain.swap.models)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ import com.tangem.core.decompose.ui.UiMessageSender
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.core.ui.extensions.stringReference
|
import com.tangem.core.ui.extensions.stringReference
|
||||||
import com.tangem.core.ui.message.DialogMessage
|
import com.tangem.core.ui.message.DialogMessage
|
||||||
import com.tangem.domain.card.DerivePublicKeysUseCase
|
|
||||||
import com.tangem.domain.card.HasMissedDerivationsUseCase
|
|
||||||
import com.tangem.domain.managetokens.model.exceptoin.CustomTokenFormValidationException
|
import com.tangem.domain.managetokens.model.exceptoin.CustomTokenFormValidationException
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.models.network.Network
|
import com.tangem.domain.models.network.Network
|
||||||
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
||||||
|
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
|
||||||
|
import com.tangem.domain.wallets.usecase.HasMissedDerivationsUseCase
|
||||||
import com.tangem.features.managetokens.analytics.CustomTokenAnalyticsEvent
|
import com.tangem.features.managetokens.analytics.CustomTokenAnalyticsEvent
|
||||||
import com.tangem.features.managetokens.component.CustomTokenFormComponent
|
import com.tangem.features.managetokens.component.CustomTokenFormComponent
|
||||||
import com.tangem.features.managetokens.entity.customtoken.ClickableFieldUM
|
import com.tangem.features.managetokens.entity.customtoken.ClickableFieldUM
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@ import com.tangem.core.ui.event.triggeredEvent
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.core.ui.extensions.stringReference
|
import com.tangem.core.ui.extensions.stringReference
|
||||||
import com.tangem.core.ui.message.SnackbarMessage
|
import com.tangem.core.ui.message.SnackbarMessage
|
||||||
import com.tangem.domain.card.HasMissedDerivationsUseCase
|
|
||||||
import com.tangem.domain.managetokens.SaveManagedTokensUseCase
|
import com.tangem.domain.managetokens.SaveManagedTokensUseCase
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.wallets.usecase.HasMissedDerivationsUseCase
|
||||||
import com.tangem.features.managetokens.analytics.CustomTokenAnalyticsEvent
|
import com.tangem.features.managetokens.analytics.CustomTokenAnalyticsEvent
|
||||||
import com.tangem.features.managetokens.analytics.ManageTokensAnalyticEvent
|
import com.tangem.features.managetokens.analytics.ManageTokensAnalyticEvent
|
||||||
import com.tangem.features.managetokens.component.ManageTokensComponent
|
import com.tangem.features.managetokens.component.ManageTokensComponent
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ import com.tangem.core.ui.event.triggeredEvent
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.core.ui.extensions.stringReference
|
import com.tangem.core.ui.extensions.stringReference
|
||||||
import com.tangem.core.ui.message.SnackbarMessage
|
import com.tangem.core.ui.message.SnackbarMessage
|
||||||
import com.tangem.domain.card.HasMissedDerivationsUseCase
|
|
||||||
import com.tangem.domain.managetokens.SaveManagedTokensUseCase
|
import com.tangem.domain.managetokens.SaveManagedTokensUseCase
|
||||||
import com.tangem.domain.redux.OnboardingManageTokensAction
|
import com.tangem.domain.redux.OnboardingManageTokensAction
|
||||||
import com.tangem.domain.redux.ReduxStateHolder
|
import com.tangem.domain.redux.ReduxStateHolder
|
||||||
|
import com.tangem.domain.wallets.usecase.HasMissedDerivationsUseCase
|
||||||
import com.tangem.features.managetokens.analytics.ManageTokensAnalyticEvent
|
import com.tangem.features.managetokens.analytics.ManageTokensAnalyticEvent
|
||||||
import com.tangem.features.managetokens.component.ManageTokensSource
|
import com.tangem.features.managetokens.component.ManageTokensSource
|
||||||
import com.tangem.features.managetokens.component.OnboardingManageTokensComponent
|
import com.tangem.features.managetokens.component.OnboardingManageTokensComponent
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import com.tangem.core.ui.message.DialogMessage
|
||||||
import com.tangem.core.ui.message.SnackbarMessage
|
import com.tangem.core.ui.message.SnackbarMessage
|
||||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
import com.tangem.domain.card.HasMissedDerivationsUseCase
|
import com.tangem.domain.wallets.usecase.HasMissedDerivationsUseCase
|
||||||
import com.tangem.domain.managetokens.CheckCurrencyUnsupportedUseCase
|
import com.tangem.domain.managetokens.CheckCurrencyUnsupportedUseCase
|
||||||
import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
|
import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
|
||||||
import com.tangem.domain.markets.SaveMarketTokensUseCase
|
import com.tangem.domain.markets.SaveMarketTokensUseCase
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import arrow.core.getOrElse
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.model.Model
|
import com.tangem.core.decompose.model.Model
|
||||||
import com.tangem.core.decompose.model.ParamsContainer
|
import com.tangem.core.decompose.model.ParamsContainer
|
||||||
import com.tangem.domain.card.DerivePublicKeysUseCase
|
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
|
||||||
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package com.tangem.feature.referral.domain
|
||||||
|
|
||||||
import arrow.core.getOrElse
|
import arrow.core.getOrElse
|
||||||
import com.tangem.common.core.TangemSdkError
|
import com.tangem.common.core.TangemSdkError
|
||||||
import com.tangem.domain.card.DerivePublicKeysUseCase
|
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
|
||||||
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package com.tangem.feature.referral.domain.di
|
||||||
|
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.decompose.di.ModelComponent
|
import com.tangem.core.decompose.di.ModelComponent
|
||||||
import com.tangem.domain.card.DerivePublicKeysUseCase
|
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
|
||||||
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
||||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
import com.tangem.feature.referral.domain.ReferralInteractor
|
import com.tangem.feature.referral.domain.ReferralInteractor
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ import com.tangem.core.ui.message.SnackbarMessage
|
||||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||||
import com.tangem.domain.card.GetExtendedPublicKeyForCurrencyUseCase
|
|
||||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
|
|
@ -69,6 +68,7 @@ import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
|
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
|
||||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
|
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
|
||||||
import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase
|
import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase
|
||||||
|
import com.tangem.domain.wallets.usecase.GetExtendedPublicKeyForCurrencyUseCase
|
||||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||||
import com.tangem.domain.wallets.usecase.NetworkHasDerivationUseCase
|
import com.tangem.domain.wallets.usecase.NetworkHasDerivationUseCase
|
||||||
import com.tangem.feature.tokendetails.deeplink.TokenDetailsDeepLinkActionListener
|
import com.tangem.feature.tokendetails.deeplink.TokenDetailsDeepLinkActionListener
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import com.tangem.core.analytics.models.AnalyticsParam
|
||||||
import com.tangem.core.decompose.di.ModelScoped
|
import com.tangem.core.decompose.di.ModelScoped
|
||||||
import com.tangem.core.navigation.url.UrlOpener
|
import com.tangem.core.navigation.url.UrlOpener
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.domain.card.DerivePublicKeysUseCase
|
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
|
||||||
import com.tangem.domain.card.SetCardWasScannedUseCase
|
import com.tangem.domain.card.SetCardWasScannedUseCase
|
||||||
import com.tangem.domain.feedback.GetCardInfoUseCase
|
import com.tangem.domain.feedback.GetCardInfoUseCase
|
||||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue