Updated on 2026-08-14
This commit is contained in:
commit
4771312415
326 changed files with 6051 additions and 3487 deletions
|
|
@ -5,8 +5,8 @@ import androidx.lifecycle.LifecycleOwner
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.wallets.legacy.asLockable
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.domain.userWalletList.asLockable
|
||||
import kotlinx.coroutines.*
|
||||
import timber.log.Timber
|
||||
import kotlin.time.Duration
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ fun Blockchain.getGreyedOutIconRes(): Int {
|
|||
Blockchain.Telos, Blockchain.TelosTestnet -> R.drawable.ic_telos_no_color
|
||||
Blockchain.AlephZero, Blockchain.AlephZeroTestnet -> R.drawable.ic_azero_no_color
|
||||
Blockchain.OctaSpace, Blockchain.OctaSpaceTestnet -> R.drawable.ic_octaspace_no_color
|
||||
Blockchain.Chia, Blockchain.ChiaTestnet -> R.drawable.ic_chia_no_color
|
||||
else -> R.drawable.ic_tangem_logo
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ internal class RuntimeUserWalletsStore(
|
|||
private val walletsStateHolder: WalletsStateHolder,
|
||||
) : UserWalletsStore {
|
||||
|
||||
override val selectedUserWalletOrNull: UserWallet?
|
||||
get() = walletsStateHolder.userWalletsListManager?.selectedUserWalletSync
|
||||
|
||||
override suspend fun getSyncOrNull(key: UserWalletId): UserWallet? {
|
||||
return walletsStateHolder.userWalletsListManager
|
||||
?.userWallets
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
|
||||
@Module
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
internal object AppCurrencyDomainModule {
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetSelectedAppCurrencyUseCase(
|
||||
appCurrencyRepository: AppCurrencyRepository,
|
||||
): GetSelectedAppCurrencyUseCase {
|
||||
return GetSelectedAppCurrencyUseCase(appCurrencyRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.tokens.repository.TokensRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -18,23 +18,34 @@ internal object TokensDomainModule {
|
|||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetTokenListUseCase(
|
||||
tokensRepository: TokensRepository,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetTokenListUseCase {
|
||||
return GetTokenListUseCase(tokensRepository, quotesRepository, networksRepository, dispatchers)
|
||||
return GetTokenListUseCase(currenciesRepository, quotesRepository, networksRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetCurrencyUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetCurrencyUseCase {
|
||||
return GetCurrencyUseCase(currenciesRepository, quotesRepository, networksRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideGetPrimaryCurrencyUseCase(
|
||||
tokensRepository: TokensRepository,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetPrimaryCurrencyUseCase {
|
||||
return GetPrimaryCurrencyUseCase(tokensRepository, quotesRepository, networksRepository, dispatchers)
|
||||
return GetPrimaryCurrencyUseCase(currenciesRepository, quotesRepository, networksRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -55,9 +66,9 @@ internal object TokensDomainModule {
|
|||
@Provides
|
||||
@ViewModelScoped
|
||||
fun provideApplyTokenListSortingUseCase(
|
||||
tokensRepository: TokensRepository,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): ApplyTokenListSortingUseCase {
|
||||
return ApplyTokenListSortingUseCase(tokensRepository, dispatchers)
|
||||
return ApplyTokenListSortingUseCase(currenciesRepository, dispatchers)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,7 @@ package com.tangem.tap.di.domain
|
|||
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.legacy.WalletsStateHolder
|
||||
import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.domain.wallets.usecase.SaveWalletUseCase
|
||||
import com.tangem.domain.wallets.usecase.*
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -21,6 +19,12 @@ internal object WalletsDomainModule {
|
|||
return GetWalletsUseCase(walletsStateHolder = walletsStateHolder)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesGetSelectedWalletUseCase(walletsStateHolder: WalletsStateHolder): GetSelectedWalletUseCase {
|
||||
return GetSelectedWalletUseCase(walletsStateHolder = walletsStateHolder)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesSaveWalletUseCase(walletsStateHolder: WalletsStateHolder): SaveWalletUseCase {
|
||||
|
|
@ -32,4 +36,16 @@ internal object WalletsDomainModule {
|
|||
fun providesGetExploreUrlUseCase(walletsManagersFacade: WalletManagersFacade): GetExploreUrlUseCase {
|
||||
return GetExploreUrlUseCase(walletsManagersFacade = walletsManagersFacade)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesUnlockWalletUseCase(walletsStateHolder: WalletsStateHolder): UnlockWalletsUseCase {
|
||||
return UnlockWalletsUseCase(walletsStateHolder = walletsStateHolder)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ViewModelScoped
|
||||
fun providesSelectWalletUseCase(walletsStateHolder: WalletsStateHolder): SelectWalletUseCase {
|
||||
return SelectWalletUseCase(walletsStateHolder = walletsStateHolder)
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ import com.tangem.crypto.bip39.DefaultMnemonic
|
|||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.card.repository.CardSdkConfigRepository
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.ScanTask
|
||||
|
|
@ -80,7 +81,10 @@ class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigReposit
|
|||
|
||||
suspend fun createProductWallet(scanResponse: ScanResponse): CompletionResult<CreateProductWalletTaskResponse> {
|
||||
return runTaskAsync(
|
||||
CreateProductWalletTask(scanResponse.cardTypesResolver),
|
||||
CreateProductWalletTask(
|
||||
cardTypesResolver = scanResponse.cardTypesResolver,
|
||||
derivationStyleProvider = scanResponse.derivationStyleProvider,
|
||||
),
|
||||
scanResponse.card.cardId,
|
||||
Message(resources.getString(R.string.initial_message_create_wallet_body)),
|
||||
)
|
||||
|
|
@ -90,15 +94,20 @@ class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigReposit
|
|||
scanResponse: ScanResponse,
|
||||
mnemonic: String,
|
||||
): CompletionResult<CreateProductWalletTaskResponse> {
|
||||
return when (val seedResult = DefaultMnemonic(mnemonic, tangemSdk.wordlist).generateSeed()) {
|
||||
is CompletionResult.Success -> runTaskAsync(
|
||||
CreateProductWalletTask(scanResponse.cardTypesResolver, seedResult.data),
|
||||
scanResponse.card.cardId,
|
||||
Message(resources.getString(R.string.initial_message_create_wallet_body)),
|
||||
)
|
||||
|
||||
is CompletionResult.Failure -> CompletionResult.Failure(seedResult.error)
|
||||
val mnemonic = try {
|
||||
DefaultMnemonic(mnemonic, tangemSdk.wordlist)
|
||||
} catch (e: TangemSdkError.MnemonicException) {
|
||||
return CompletionResult.Failure(e)
|
||||
}
|
||||
return runTaskAsync(
|
||||
CreateProductWalletTask(
|
||||
scanResponse.cardTypesResolver,
|
||||
derivationStyleProvider = scanResponse.derivationStyleProvider,
|
||||
mnemonic,
|
||||
),
|
||||
scanResponse.card.cardId,
|
||||
Message(resources.getString(R.string.initial_message_create_wallet_body)),
|
||||
)
|
||||
}
|
||||
|
||||
private fun sendScanResultsToAnalytics(result: CompletionResult<ScanResponse>) {
|
||||
|
|
@ -246,12 +255,13 @@ class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigReposit
|
|||
}
|
||||
|
||||
companion object {
|
||||
@Deprecated("Use [DefaultCardSdkProvider] instead")
|
||||
val config = Config(
|
||||
linkedTerminal = true,
|
||||
allowUntrustedCards = true,
|
||||
filter = CardFilter(
|
||||
allowedCardTypes = FirmwareVersion.FirmwareType.values().toList(),
|
||||
maxFirmwareVersion = FirmwareVersion(major = 6, minor = 21),
|
||||
maxFirmwareVersion = FirmwareVersion(major = 6, minor = 33),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,8 @@ sealed class TapError(
|
|||
val stateError: String,
|
||||
) : TapError(R.string.common_custom_string, listOf("Unsupported state: $stateError"))
|
||||
|
||||
object ScanCardError : TapError(R.string.scan_card_error)
|
||||
object UnknownBlockchain : TapError(R.string.wallet_error_unsupported_blockchain_subtitle)
|
||||
object NoInternetConnection : TapError(R.string.wallet_notification_no_internet)
|
||||
object BlockchainInternalError : TapError(R.string.send_error_blockchain_internal)
|
||||
object AmountExceedsBalance : TapError(R.string.send_validation_amount_exceeds_balance)
|
||||
data class AmountLowerExistentialDeposit(
|
||||
override val args: List<Any>,
|
||||
|
|
@ -43,7 +41,7 @@ sealed class TapError(
|
|||
object DustChange : TapError(R.string.send_error_dust_change)
|
||||
|
||||
sealed class WalletManager {
|
||||
object CreationError : CustomError("Can't create wallet manager")
|
||||
object CreationError : CustomError(customMessage = "Can't create wallet manager")
|
||||
class NoAccountError(amountToCreateAccount: String) : CustomError(amountToCreateAccount)
|
||||
class InternalError(message: String) : CustomError(message)
|
||||
object BlockchainIsUnreachableTryLater : TapError(R.string.wallet_balance_blockchain_unreachable_try_later)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.tangem.common.doOnFailure
|
|||
import com.tangem.common.doOnSuccess
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.datasource.config.ConfigManager
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -20,6 +21,8 @@ import com.tangem.tap.common.extensions.dispatchWithMain
|
|||
import com.tangem.tap.common.extensions.setContext
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.walletStores.WalletStoresError
|
||||
import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor
|
||||
import com.tangem.tap.domain.walletconnect2.domain.models.Account
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
import com.tangem.tap.features.disclaimer.createDisclaimer
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
||||
|
|
@ -92,7 +95,8 @@ class TapWalletManager(
|
|||
null
|
||||
}
|
||||
scope.launch {
|
||||
store.state.daggerGraphState.walletConnectInteractor?.startListening(
|
||||
val wcInteractor = store.state.daggerGraphState.walletConnectInteractor ?: return@launch
|
||||
wcInteractor.startListening(
|
||||
userWalletId = userWallet.walletId.stringValue,
|
||||
cardId = cardId,
|
||||
)
|
||||
|
|
@ -106,6 +110,9 @@ class TapWalletManager(
|
|||
store.dispatchOnMain(WalletAction.LoadData.Success)
|
||||
store.state.globalState.topUpController?.loadDataSuccess()
|
||||
store.dispatchWithMain(WalletAction.Warnings.CheckHashesCount.VerifyOnlineIfNeeded)
|
||||
|
||||
val wcInteractor = store.state.daggerGraphState.walletConnectInteractor
|
||||
wcInteractor?.setUserChains(getAccountsForWc(wcInteractor))
|
||||
}
|
||||
.doOnFailure { error ->
|
||||
val errorAction = when (error) {
|
||||
|
|
@ -135,6 +142,23 @@ class TapWalletManager(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getAccountsForWc(wcInteractor: WalletConnectInteractor): List<Account> {
|
||||
return store.state.walletState.walletManagers
|
||||
.mapNotNull {
|
||||
val wallet = it.wallet
|
||||
val chainId = wcInteractor.blockchainHelper.networkIdToChainIdOrNull(
|
||||
wallet.blockchain.toNetworkId(),
|
||||
)
|
||||
chainId?.let {
|
||||
Account(
|
||||
chainId,
|
||||
wallet.address,
|
||||
wallet.publicKey.derivationPath?.rawPath,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateConfigManager(data: ScanResponse) {
|
||||
val configManager = store.state.globalState.configManager
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.domain.configurable.warningMessage
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.utils.extensions.removeByReplace
|
||||
import com.tangem.utils.extensions.removeBy
|
||||
import com.tangem.wallet.R
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
|
|
@ -44,12 +44,12 @@ class WarningMessagesManager {
|
|||
}
|
||||
|
||||
fun removeWarnings(origin: WarningMessage.Origin) {
|
||||
warningsList.removeByReplace { it.origin == origin }
|
||||
warningsList.removeBy { it.origin == origin }
|
||||
sortByPriority()
|
||||
}
|
||||
|
||||
fun removeWarnings(messageRes: Int) {
|
||||
warningsList.removeByReplace { it.messageResId == messageRes }
|
||||
warningsList.removeBy { it.messageResId == messageRes }
|
||||
}
|
||||
|
||||
fun containsWarning(warning: WarningMessage) = warning in warningsList
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
package com.tangem.tap.domain.model.builders
|
||||
|
||||
import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider
|
||||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.domain.model.WalletStoreModel
|
||||
|
|
@ -47,7 +51,7 @@ private class BlockchainNetworkWalletStoreBuilderImpl(
|
|||
}
|
||||
|
||||
override fun build(): WalletStoreModel {
|
||||
val cardDerivationStyle = userWallet.scanResponse.card.derivationStyle
|
||||
val cardDerivationStyle = userWallet.scanResponse.derivationStyleProvider.getDerivationStyle()
|
||||
val blockchainWalletData = blockchainNetwork.getBlockchainWalletData(walletManager, cardDerivationStyle)
|
||||
val tokensWalletsData = blockchainNetwork.getTokensWalletsData(
|
||||
walletManager = walletManager,
|
||||
|
|
|
|||
|
|
@ -11,10 +11,13 @@ import com.tangem.common.extensions.ByteArrayKey
|
|||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.extensions.toMapKey
|
||||
import com.tangem.common.map
|
||||
import com.tangem.crypto.bip39.Mnemonic
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.CardTypesResolver
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.TapWorkarounds.isTestCard
|
||||
import com.tangem.domain.common.extensions.derivationPath
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.KeyWalletPublicKey
|
||||
import com.tangem.operations.CommandResponse
|
||||
|
|
@ -56,7 +59,8 @@ private data class CreateWalletResponse(
|
|||
|
||||
class CreateProductWalletTask(
|
||||
private val cardTypesResolver: CardTypesResolver,
|
||||
private val seed: ByteArray? = null,
|
||||
private val derivationStyleProvider: DerivationStyleProvider,
|
||||
private val mnemonic: Mnemonic? = null,
|
||||
) : CardSessionRunnable<CreateProductWalletTaskResponse> {
|
||||
|
||||
override val allowsRequestAccessCodeFromRepository: Boolean = false
|
||||
|
|
@ -76,7 +80,7 @@ class CreateProductWalletTask(
|
|||
cardTypesResolver.isTangemTwins() ->
|
||||
throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
|
||||
|
||||
else -> CreateWalletTangemWallet(seed)
|
||||
else -> CreateWalletTangemWallet(mnemonic, derivationStyleProvider)
|
||||
}
|
||||
commandProcessor.proceed(cardDto, session) {
|
||||
when (it) {
|
||||
|
|
@ -131,8 +135,12 @@ private class CreateWalletTangemNote(private val cardTypesResolver: CardTypesRes
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses for multiWallet 1st and 2nd
|
||||
*/
|
||||
private class CreateWalletTangemWallet(
|
||||
private val seed: ByteArray?,
|
||||
private val mnemonic: Mnemonic?,
|
||||
private val derivationStyleProvider: DerivationStyleProvider,
|
||||
) : ProductCommandProcessor<CreateProductWalletTaskResponse> {
|
||||
|
||||
private var primaryCard: PrimaryCard? = null
|
||||
|
|
@ -142,8 +150,9 @@ private class CreateWalletTangemWallet(
|
|||
session: CardSession,
|
||||
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
|
||||
) {
|
||||
val config = CardConfig.createConfig(card)
|
||||
val walletsOnCard = card.wallets.map { it.curve }.toSet()
|
||||
val curves = card.supportedCurves.intersect(CURVES_FOR_WALLETS).subtract(walletsOnCard).toList()
|
||||
val curves = card.supportedCurves.intersect(config.mandatoryCurves.toSet()).subtract(walletsOnCard).toList()
|
||||
|
||||
if (curves.isEmpty()) {
|
||||
val createWalletResponses = card.wallets.map { wallet ->
|
||||
|
|
@ -152,8 +161,7 @@ private class CreateWalletTangemWallet(
|
|||
proceedWithCreatedWallets(card, createWalletResponses, session, callback)
|
||||
return
|
||||
}
|
||||
|
||||
CreateWalletsTask(curves, seed).run(session) { result ->
|
||||
CreateWalletsTask(curves, mnemonic).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
proceedWithCreatedWallets(
|
||||
|
|
@ -242,9 +250,9 @@ private class CreateWalletTangemWallet(
|
|||
val blockchainsForCurve = getBlockchains(response.cardId, card).filter {
|
||||
it.getSupportedCurves().contains(response.wallet.curve)
|
||||
}
|
||||
val derivationPaths = blockchainsForCurve.mapNotNull {
|
||||
val derivationPaths = blockchainsForCurve.mapNotNull { blockchain ->
|
||||
isBlockchainsForCurvesExist = true
|
||||
it.derivationPath(card.derivationStyle)
|
||||
blockchain.derivationPath(derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
if (derivationPaths.isNotEmpty()) {
|
||||
map[response.wallet.publicKey.toMapKey()] = derivationPaths
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import com.tangem.common.card.EllipticCurve
|
|||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.crypto.bip39.Mnemonic
|
||||
import com.tangem.crypto.hdWallet.masterkey.AnyMasterKeyFactory
|
||||
import com.tangem.operations.CommandResponse
|
||||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.operations.wallet.CreateWalletTask
|
||||
|
|
@ -18,7 +20,7 @@ class CreateWalletsResponse(
|
|||
|
||||
class CreateWalletsTask(
|
||||
private val curves: List<EllipticCurve>,
|
||||
private val seed: ByteArray? = null,
|
||||
private val mnemonic: Mnemonic? = null,
|
||||
) : CardSessionRunnable<CreateWalletsResponse> {
|
||||
|
||||
private val createdWalletsResponses = mutableListOf<CreateWalletResponse>()
|
||||
|
|
@ -38,7 +40,10 @@ class CreateWalletsTask(
|
|||
session: CardSession,
|
||||
callback: (result: CompletionResult<CreateWalletsResponse>) -> Unit,
|
||||
) {
|
||||
CreateWalletTask(curve, seed).run(session) { result ->
|
||||
val extendedPrivateKey = mnemonic?.let {
|
||||
AnyMasterKeyFactory(mnemonic = it, passphrase = "").makeMasterKey(curve)
|
||||
}
|
||||
CreateWalletTask(curve, extendedPrivateKey).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
createdWalletsResponses.add(result.data)
|
||||
|
|
|
|||
|
|
@ -14,13 +14,15 @@ import com.tangem.common.tlv.TlvDecoder
|
|||
import com.tangem.crypto.CryptoUtils
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.TapWorkarounds.isExcluded
|
||||
import com.tangem.domain.common.TapWorkarounds.isNotSupportedInThatRelease
|
||||
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
|
||||
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
|
||||
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
|
||||
import com.tangem.domain.common.TwinsHelper
|
||||
import com.tangem.domain.common.extensions.getPrimaryCurve
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -51,7 +53,7 @@ class ScanProductTask(
|
|||
}
|
||||
val cardDto = CardDTO(card)
|
||||
|
||||
val error = getErrorIfExcludedCard(cardDto, card)
|
||||
val error = getErrorIfExcludedCard(cardDto)
|
||||
if (error != null) {
|
||||
callback(CompletionResult.Failure(error))
|
||||
return
|
||||
|
|
@ -81,11 +83,9 @@ class ScanProductTask(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getErrorIfExcludedCard(cardDto: CardDTO, card: Card): TangemError? {
|
||||
private fun getErrorIfExcludedCard(cardDto: CardDTO): TangemError? {
|
||||
if (cardDto.isExcluded) return TapSdkError.CardForDifferentApp
|
||||
if (cardDto.isNotSupportedInThatRelease) return TapSdkError.CardNotSupportedByRelease
|
||||
// todo check isImported to prevent using old app with imported wallet, remove before wallet 2.0 enabled ([REDACTED_TASK_KEY])
|
||||
if (card.wallets.any { it.isImported }) return TapSdkError.CardNotSupportedByRelease
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
|
@ -209,32 +209,24 @@ private class ScanWalletProcessor(
|
|||
callback: (result: CompletionResult<ScanResponse>) -> Unit,
|
||||
) {
|
||||
val productType = ProductType.Wallet
|
||||
val config = CardConfig.createConfig(card)
|
||||
scope.launch {
|
||||
val derivations = collectDerivations(card)
|
||||
val scanResponse = ScanResponse(
|
||||
card = card,
|
||||
productType = productType,
|
||||
walletData = session.environment.walletData,
|
||||
primaryCard = primaryCard,
|
||||
)
|
||||
val derivations = collectDerivations(card, config, scanResponse.derivationStyleProvider)
|
||||
if (derivations.isEmpty() || !card.settings.isHDWalletAllowed) {
|
||||
callback(
|
||||
CompletionResult.Success(
|
||||
ScanResponse(
|
||||
card = card,
|
||||
productType = productType,
|
||||
walletData = session.environment.walletData,
|
||||
primaryCard = primaryCard,
|
||||
),
|
||||
),
|
||||
)
|
||||
callback(CompletionResult.Success(scanResponse))
|
||||
return@launch
|
||||
}
|
||||
|
||||
DeriveMultipleWalletPublicKeysTask(derivations).run(session) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
val response = ScanResponse(
|
||||
card = card,
|
||||
productType = productType,
|
||||
walletData = session.environment.walletData,
|
||||
derivedKeys = result.data.entries,
|
||||
primaryCard = primaryCard,
|
||||
)
|
||||
val response = scanResponse.copy(derivedKeys = result.data.entries)
|
||||
callback(CompletionResult.Success(response))
|
||||
}
|
||||
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
|
||||
|
|
@ -243,7 +235,10 @@ private class ScanWalletProcessor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun getBlockchainsToDerive(card: CardDTO): List<BlockchainNetwork> {
|
||||
private suspend fun getBlockchainsToDerive(
|
||||
card: CardDTO,
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
): List<BlockchainNetwork> {
|
||||
val userTokensRepository = userTokensRepository ?: return emptyList()
|
||||
val blockchainsToDerive = userTokensRepository.loadBlockchainsToDerive(card)
|
||||
.toMutableList()
|
||||
|
|
@ -251,11 +246,11 @@ private class ScanWalletProcessor(
|
|||
mutableListOf(
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Bitcoin,
|
||||
card = card,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
),
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Ethereum,
|
||||
card = card,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -265,11 +260,11 @@ private class ScanWalletProcessor(
|
|||
listOf(
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Ethereum,
|
||||
card = card,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
),
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.EthereumTestnet,
|
||||
card = card,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -279,7 +274,7 @@ private class ScanWalletProcessor(
|
|||
additionalBlockchainsToDerive.map {
|
||||
BlockchainNetwork(
|
||||
blockchain = it,
|
||||
card = card,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -295,7 +290,7 @@ private class ScanWalletProcessor(
|
|||
).map {
|
||||
BlockchainNetwork(
|
||||
blockchain = it,
|
||||
card = card,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -303,12 +298,16 @@ private class ScanWalletProcessor(
|
|||
return blockchainsToDerive.distinct()
|
||||
}
|
||||
|
||||
private suspend fun collectDerivations(card: CardDTO): Map<ByteArrayKey, List<DerivationPath>> {
|
||||
val blockchains = getBlockchainsToDerive(card)
|
||||
private suspend fun collectDerivations(
|
||||
card: CardDTO,
|
||||
config: CardConfig,
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
): Map<ByteArrayKey, List<DerivationPath>> {
|
||||
val blockchains = getBlockchainsToDerive(card, derivationStyleProvider)
|
||||
val derivations = mutableMapOf<ByteArrayKey, List<DerivationPath>>()
|
||||
|
||||
blockchains.forEach { blockchain ->
|
||||
val curve = blockchain.blockchain.getPrimaryCurve()
|
||||
val curve = config.primaryCurve(blockchain.blockchain)
|
||||
val wallet = card.wallets.firstOrNull { it.curve == curve } ?: return@forEach
|
||||
if (wallet.chainCode == null) return@forEach
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
package com.tangem.tap.domain.tokens
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.card.FirmwareVersion
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
|
||||
object CurrenciesRepository {
|
||||
fun getBlockchains(cardFirmware: CardDTO.FirmwareVersion, isTestNet: Boolean = false): List<Blockchain> {
|
||||
val blockchains = if (cardFirmware < FirmwareVersion.MultiWalletAvailable) {
|
||||
Blockchain.secp256k1Blockchains(isTestNet)
|
||||
} else {
|
||||
Blockchain.secp256k1Blockchains(isTestNet) + Blockchain.ed25519OnlyBlockchains(isTestNet)
|
||||
}
|
||||
return excludeUnsupportedBlockchains(blockchains)
|
||||
}
|
||||
|
||||
// Use this list to temporarily exclude a blockchain from the list of tokens.
|
||||
private fun excludeUnsupportedBlockchains(blockchains: List<Blockchain>): List<Blockchain> {
|
||||
return blockchains.toMutableList().apply {
|
||||
removeAll(
|
||||
listOf(
|
||||
// Any blockchain
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -34,6 +34,11 @@ class CreateSecondTwinWalletTask(
|
|||
return
|
||||
}
|
||||
|
||||
if (!TwinsHelper.isTwinsCompatible(firstCardId, card.cardId)) {
|
||||
callback(CompletionResult.Failure(IncompatibleTwinCard))
|
||||
return
|
||||
}
|
||||
|
||||
session.setMessage(preparingMessage)
|
||||
PurgeWalletCommand(publicKey).run(session) { response ->
|
||||
when (response) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.tap.domain.twins
|
||||
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.wallet.R
|
||||
|
||||
object IncompatibleTwinCard : TangemError(code = 50005) {
|
||||
override var customMessage: String = tangemSdkManager.getString(
|
||||
R.string.twin_error_wrong_twin,
|
||||
)
|
||||
override val messageResId: Int? = null
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
package com.tangem.tap.domain.userWalletList
|
||||
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.wallet.R
|
||||
|
||||
sealed class UserWalletsListError(code: Int) : TangemError(code) {
|
||||
|
||||
override val silent: Boolean
|
||||
get() = (cause as? TangemError)?.silent == true
|
||||
|
||||
override val messageResId: Int? = null
|
||||
|
||||
object WalletAlreadySaved : UserWalletsListError(code = 60001) {
|
||||
override var customMessage: String = "This wallet has already been saved, you can add another one"
|
||||
override val messageResId: Int = R.string.user_wallet_list_error_wallet_already_saved
|
||||
}
|
||||
|
||||
object EncryptionKeyInvalidated : UserWalletsListError(code = 60002) {
|
||||
override var customMessage: String = "Encryption key invalidated"
|
||||
}
|
||||
|
||||
object BiometricsAuthenticationDisabled : UserWalletsListError(code = 60005) {
|
||||
override var customMessage: String = "Biometrics authentication disabled"
|
||||
}
|
||||
|
||||
data class BiometricsAuthenticationLockout(val isPermanent: Boolean) : UserWalletsListError(code = 60003) {
|
||||
override var customMessage: String = "Biometric authentication lockout, permanent: $isPermanent"
|
||||
}
|
||||
|
||||
data class UnableToUnlockUserWallets(override val cause: Throwable? = null) : UserWalletsListError(code = 60004) {
|
||||
override var customMessage: String = "An error has occurred, please scan your card to log in"
|
||||
override val messageResId: Int = R.string.user_wallet_list_error_unable_to_unlock
|
||||
}
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
package com.tangem.tap.domain.userWalletList
|
||||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
/**
|
||||
* Indicates that the [UserWalletsListManager] implements [UserWalletsListManager.Lockable]
|
||||
* */
|
||||
val UserWalletsListManager.isLockable: Boolean
|
||||
get() = this is UserWalletsListManager.Lockable
|
||||
|
||||
/**
|
||||
* Indicates that the [UserWalletsListManager] is locked
|
||||
*
|
||||
* @return If [UserWalletsListManager] not implements [UserWalletsListManager.Lockable] returns [Flow] which
|
||||
* produces only one false value
|
||||
*
|
||||
* @see UserWalletsListManager.Lockable.isLockedSync
|
||||
* */
|
||||
val UserWalletsListManager.isLocked: Flow<Boolean>
|
||||
get() = asLockable()?.isLocked ?: flowOf(false)
|
||||
|
||||
/**
|
||||
* Indicates that the [UserWalletsListManager] is locked
|
||||
*
|
||||
* @return If [UserWalletsListManager] not implements [UserWalletsListManager.Lockable] returns false
|
||||
*
|
||||
* @see UserWalletsListManager.Lockable.isLockedSync
|
||||
* */
|
||||
val UserWalletsListManager.isLockedSync: Boolean
|
||||
get() = asLockable()?.isLockedSync ?: false
|
||||
|
||||
/**
|
||||
* Call [UserWalletsListManager.Lockable.unlock] if [UserWalletsListManager] implements [UserWalletsListManager.Lockable]
|
||||
*
|
||||
* @return If [UserWalletsListManager] not implements [UserWalletsListManager.Lockable]
|
||||
* returns [CompletionResult.Failure] with [UserWalletsListError.UnableToUnlockUserWallets]
|
||||
*
|
||||
* If [UserWalletsListManager] implements [UserWalletsListManager.Lockable]
|
||||
* returns [CompletionResult.Success] with selected [UserWallet]
|
||||
*
|
||||
* @see UserWalletsListManager.Lockable.unlock
|
||||
* */
|
||||
suspend fun UserWalletsListManager.unlockIfLockable(): CompletionResult<UserWallet> {
|
||||
return asLockable()?.unlock() ?: CompletionResult.Failure(UserWalletsListError.UnableToUnlockUserWallets())
|
||||
}
|
||||
|
||||
/**
|
||||
* Call [UserWalletsListManager.Lockable.lock] if [UserWalletsListManager] implements [UserWalletsListManager.Lockable]
|
||||
* or do nothing otherwise
|
||||
*
|
||||
* @see UserWalletsListManager.Lockable.lock
|
||||
* */
|
||||
fun UserWalletsListManager.lockIfLockable() {
|
||||
asLockable()?.lock()
|
||||
}
|
||||
|
||||
/**
|
||||
* Safe cast [UserWalletsListManager] to [UserWalletsListManager.Lockable]
|
||||
*
|
||||
* @return If [UserWalletsListManager] not implements [UserWalletsListManager.Lockable] then returns null or
|
||||
* [UserWalletsListManager.Lockable] otherwise
|
||||
* */
|
||||
fun UserWalletsListManager.asLockable(): UserWalletsListManager.Lockable? {
|
||||
return this as? UserWalletsListManager.Lockable
|
||||
}
|
||||
|
|
@ -2,10 +2,10 @@ package com.tangem.tap.domain.userWalletList.implementation
|
|||
|
||||
import com.tangem.common.*
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletsListError
|
||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||
import com.tangem.tap.domain.userWalletList.repository.SelectedUserWalletRepository
|
||||
import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ package com.tangem.tap.domain.userWalletList.implementation
|
|||
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.catching
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletsListError
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import com.tangem.common.biometric.BiometricManager
|
|||
import com.tangem.common.biometric.BiometricStorage
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.common.services.secure.SecureStorage
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletsListError
|
||||
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
|
||||
import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import com.tangem.domain.wallets.models.UserWalletId
|
|||
import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
|
||||
import com.tangem.tap.domain.userWalletList.repository.UserWalletsPublicInformationRepository
|
||||
import com.tangem.tap.domain.userWalletList.utils.publicInformation
|
||||
import com.tangem.utils.extensions.plusOrReplace
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ internal class DefaultUserWalletsPublicInformationRepository(
|
|||
getAll()
|
||||
.flatMap { savedInformation ->
|
||||
val infoToSave = withContext(Dispatchers.Default) {
|
||||
savedInformation.plusOrReplace(userWallet.publicInformation) {
|
||||
savedInformation.addOrReplace(userWallet.publicInformation) {
|
||||
userWallet.walletId == it.walletId
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package com.tangem.tap.domain.walletCurrencies.implementation
|
||||
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.common.*
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.extensions.derivationPath
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.wallets.legacy.WalletManagersRepository
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
|
|
@ -61,7 +63,9 @@ internal class DefaultWalletCurrenciesManager(
|
|||
}
|
||||
|
||||
val card = userWallet.scanResponse.card
|
||||
val currenciesToAddWithMissingBlockchains = currenciesToAdd.addMissingBlockchainsIfNeeded(card)
|
||||
val currenciesToAddWithMissingBlockchains = currenciesToAdd.addMissingBlockchainsIfNeeded(
|
||||
userWallet.scanResponse.derivationStyleProvider,
|
||||
)
|
||||
listeners.forEach { it.willCurrenciesAdd(userWallet, currenciesToAddWithMissingBlockchains) }
|
||||
|
||||
updateWalletStores(
|
||||
|
|
@ -167,13 +171,15 @@ internal class DefaultWalletCurrenciesManager(
|
|||
return networks
|
||||
}
|
||||
|
||||
private fun List<Currency>.addMissingBlockchainsIfNeeded(card: CardDTO): List<Currency> {
|
||||
private fun List<Currency>.addMissingBlockchainsIfNeeded(
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
): List<Currency> {
|
||||
if (this.isEmpty()) return this
|
||||
val currencies = this.asSequence()
|
||||
|
||||
return currencies
|
||||
.groupBy { currency ->
|
||||
findBlockchainCurrency(currency, currencies, card.derivationStyle)
|
||||
findBlockchainCurrency(currency, currencies, derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
.mapValues { (blockchainCurrency, blockchainCurrencies) ->
|
||||
findBlockchainTokens(blockchainCurrency, blockchainCurrencies)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import com.tangem.tap.features.wallet.models.getPendingTransactions
|
|||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.plusOrReplace
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import timber.log.Timber
|
||||
|
|
@ -429,7 +429,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
withContext(Dispatchers.Default) {
|
||||
WalletManagerStorage.update { prevManagers ->
|
||||
val newManagersForUserWallet = prevManagers[userWalletId].orEmpty()
|
||||
.plusOrReplace(walletManager) {
|
||||
.addOrReplace(walletManager) {
|
||||
it.wallet.blockchain == walletManager.wallet.blockchain
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,28 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
Timber.d("sessionProposal: $sessionProposal")
|
||||
this@WalletConnectRepositoryImpl.sessionProposal = sessionProposal
|
||||
|
||||
val missingNetworks = findMissingNetworks(
|
||||
namespaces = sessionProposal.requiredNamespaces,
|
||||
userNamespaces = this@WalletConnectRepositoryImpl.userNamespaces ?: emptyMap(),
|
||||
)
|
||||
|
||||
if (missingNetworks.isNotEmpty()) {
|
||||
Timber.w("Not added blockchains: $missingNetworks")
|
||||
scope.launch {
|
||||
_events.emit(
|
||||
WalletConnectEvents.SessionApprovalError(
|
||||
WalletConnectError.ApprovalErrorMissingNetworks(missingNetworks.toList()),
|
||||
),
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val optionalWithoutMissingNetworks = removeMissingNetworks(
|
||||
namespaces = sessionProposal.optionalNamespaces,
|
||||
userNamespaces = this@WalletConnectRepositoryImpl.userNamespaces ?: emptyMap(),
|
||||
)
|
||||
|
||||
scope.launch {
|
||||
_events.emit(
|
||||
WalletConnectEvents.SessionProposal(
|
||||
|
|
@ -108,7 +130,7 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
sessionProposal.url,
|
||||
sessionProposal.icons,
|
||||
sessionProposal.requiredNamespaces.values.flatMap { it.chains ?: emptyList() },
|
||||
sessionProposal.optionalNamespaces.values.flatMap { it.chains ?: emptyList() },
|
||||
optionalWithoutMissingNetworks.toList(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -211,6 +233,10 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun setUserNamespaces(userNamespaces: Map<NetworkNamespace, List<Account>>) {
|
||||
this.userNamespaces = userNamespaces
|
||||
}
|
||||
|
||||
override fun pair(uri: String) {
|
||||
Web3Wallet.pair(Wallet.Params.Pair(uri))
|
||||
}
|
||||
|
|
@ -220,23 +246,6 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
|
||||
val sessionProposal: Wallet.Model.SessionProposal = requireNotNull(this.sessionProposal)
|
||||
|
||||
val missingNetworks = findMissingNetworks(
|
||||
namespaces = sessionProposal.requiredNamespaces,
|
||||
userNamespaces = userNamespaces,
|
||||
)
|
||||
|
||||
if (missingNetworks.isNotEmpty()) {
|
||||
Timber.e("Not added blockchains: $missingNetworks")
|
||||
scope.launch {
|
||||
_events.emit(
|
||||
WalletConnectEvents.SessionApprovalError(
|
||||
WalletConnectError.ApprovalErrorMissingNetworks(missingNetworks.toList()),
|
||||
),
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val userChains = userNamespaces.flatMap { namespace ->
|
||||
namespace.value.map { it.chainId to "${it.chainId}:${it.walletAddress}" }
|
||||
}.groupBy { pair -> pair.first }
|
||||
|
|
@ -433,4 +442,13 @@ class WalletConnectRepositoryImpl @Inject constructor(
|
|||
val userChains = userNamespaces.flatMap { it.value.map { account -> account.chainId } }
|
||||
return requiredChains.subtract(userChains.toSet())
|
||||
}
|
||||
|
||||
private fun removeMissingNetworks(
|
||||
namespaces: Map<String, Wallet.Model.Namespace.Proposal>,
|
||||
userNamespaces: Map<NetworkNamespace, List<Account>>,
|
||||
): Collection<String> {
|
||||
val wcProvidedChains = namespaces.values.flatMap { it.chains ?: emptyList() }
|
||||
val userChains = userNamespaces.flatMap { it.value.map { account -> account.chainId } }
|
||||
return wcProvidedChains.intersect(userChains.toSet())
|
||||
}
|
||||
}
|
||||
|
|
@ -44,6 +44,15 @@ class WalletConnectInteractor(
|
|||
}
|
||||
}
|
||||
|
||||
fun setUserChains(accounts: List<Account>) {
|
||||
val userNamespaces: Map<NetworkNamespace, List<Account>> = accounts
|
||||
.groupBy { account ->
|
||||
blockchainHelper.getNamespaceFromFullChainIdOrNull(account.chainId)
|
||||
?.let { NetworkNamespace(it) }
|
||||
}.filterNotNull()
|
||||
walletConnectRepository.setUserNamespaces(userNamespaces)
|
||||
}
|
||||
|
||||
private suspend fun subscribeToEvents() {
|
||||
events
|
||||
.onEach { wcEvent ->
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ interface WalletConnectRepository {
|
|||
|
||||
fun init(projectId: String)
|
||||
|
||||
fun setUserNamespaces(userNamespaces: Map<NetworkNamespace, List<Account>>)
|
||||
|
||||
fun updateSessions()
|
||||
|
||||
fun pair(uri: String)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@ import com.tangem.common.extensions.guard
|
|||
import com.tangem.common.extensions.toMapKey
|
||||
import com.tangem.common.flatMap
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.common.extensions.derivationPath
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.util.hasDerivation
|
||||
import com.tangem.domain.features.addCustomToken.CustomCurrency
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
|
|
@ -68,10 +70,11 @@ class DefaultCustomTokenInteractor(
|
|||
currencyList: List<Currency>,
|
||||
onSuccess: suspend (ScanResponse) -> Unit,
|
||||
) {
|
||||
val derivationDataList = listOfNotNull(
|
||||
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencyList),
|
||||
getDerivations(EllipticCurve.Ed25519, scanResponse, currencyList),
|
||||
)
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivationDataList = currencyList.mapNotNull {
|
||||
val curve = config.primaryCurve(it.blockchain)
|
||||
curve?.let { getDerivations(curve, scanResponse, currencyList) }
|
||||
}
|
||||
|
||||
val derivations = derivationDataList.associate(TokensMiddleware.DerivationData::derivations)
|
||||
if (derivations.isEmpty()) {
|
||||
|
|
@ -114,7 +117,7 @@ class DefaultCustomTokenInteractor(
|
|||
val manageTokensCandidates = currencyList.map { it.blockchain }.distinct().filter {
|
||||
it.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull {
|
||||
it.derivationPath(scanResponse.card.derivationStyle)
|
||||
it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
|
||||
val customTokensCandidates = currencyList.filter {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ internal fun AddCustomTokenFloatingButton(model: AddCustomTokenFloatingButton, m
|
|||
.imePadding()
|
||||
.padding(horizontal = TangemTheme.dimens.spacing16)
|
||||
.fillMaxWidth(),
|
||||
text = stringResource(id = R.string.common_add),
|
||||
text = stringResource(id = R.string.custom_token_add_token),
|
||||
iconResId = R.drawable.ic_plus_24,
|
||||
enabled = model.isEnabled,
|
||||
onClick = model.onClick,
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@ import androidx.lifecycle.LifecycleOwner
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.HDWalletError
|
||||
import com.tangem.domain.AddCustomTokenError
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.extensions.*
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.features.addCustomToken.CustomCurrency
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.features.customtoken.impl.domain.CustomTokenInteractor
|
||||
|
|
@ -599,7 +599,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
if (blockchain == null) return null
|
||||
|
||||
val derivationStyle = if (!isDerivationPathSelected()) {
|
||||
reduxStateHolder.scanResponse?.card?.derivationStyle
|
||||
reduxStateHolder.scanResponse?.derivationStyleProvider?.getDerivationStyle()
|
||||
} else {
|
||||
DerivationStyle.LEGACY
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.tangem.domain.models.scan.ScanResponse
|
|||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.userwallets.UserWalletIdBuilder
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.legacy.isLockedSync
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Settings
|
||||
|
|
@ -27,7 +28,6 @@ import com.tangem.tap.common.redux.AppState
|
|||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
|
||||
import com.tangem.tap.domain.userWalletList.di.provideRuntimeImplementation
|
||||
import com.tangem.tap.domain.userWalletList.isLockedSync
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
package com.tangem.tap.features.details.redux.walletconnect
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.extensions.derivationPath
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.common.extensions.toNetworkId
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
|
|
@ -357,9 +358,13 @@ class WalletConnectMiddleware {
|
|||
handleScanResponse(scanResponse = scanResponse, session = session, blockchain = blockchain)
|
||||
}
|
||||
|
||||
private fun getAvailableBlockchains(card: CardDTO, walletState: WalletState): List<Blockchain> {
|
||||
private fun getAvailableBlockchains(
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
walletState: WalletState,
|
||||
): List<Blockchain> {
|
||||
return walletState.currencies.filter {
|
||||
it.isBlockchain() && !it.isCustomCurrency(card.derivationStyle) && it.blockchain.isEvm()
|
||||
it.isBlockchain() &&
|
||||
!it.isCustomCurrency(derivationStyleProvider.getDerivationStyle()) && it.blockchain.isEvm()
|
||||
}.map { it.blockchain }
|
||||
}
|
||||
|
||||
|
|
@ -390,7 +395,7 @@ class WalletConnectMiddleware {
|
|||
walletPublicKey = wallet.publicKey.seedKey,
|
||||
derivedPublicKey = derivedKey,
|
||||
derivationPath = wallet.publicKey.derivationPath,
|
||||
derivationStyle = scanResponse.card.derivationStyle,
|
||||
derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle(),
|
||||
blockchain = wallet.blockchain,
|
||||
)
|
||||
|
||||
|
|
@ -403,7 +408,6 @@ class WalletConnectMiddleware {
|
|||
}
|
||||
|
||||
private fun handleScanResponse(scanResponse: ScanResponse, session: WalletConnectSession, blockchain: Blockchain) {
|
||||
val card = scanResponse.card
|
||||
if (!scanResponse.cardTypesResolver.isMultiwalletAllowed()) {
|
||||
store.dispatchOnMain(WalletConnectAction.UnsupportedCard)
|
||||
return
|
||||
|
|
@ -415,7 +419,11 @@ class WalletConnectMiddleware {
|
|||
NewWcSessionData(session = updatedSession, scanResponse = scanResponse, blockchain = blockchain),
|
||||
),
|
||||
)
|
||||
val blockchains = if (blockchain.isEvm()) getAvailableBlockchains(card, walletState) else emptyList()
|
||||
val blockchains = if (blockchain.isEvm()) {
|
||||
getAvailableBlockchains(scanResponse.derivationStyleProvider, walletState)
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
store.dispatch(
|
||||
GlobalAction.ShowDialog(
|
||||
WalletConnectDialog.ApproveWcSession(session = updatedSession, networks = blockchains),
|
||||
|
|
@ -433,8 +441,9 @@ class WalletConnectMiddleware {
|
|||
} else {
|
||||
blockchain
|
||||
}
|
||||
val derivation = blockchainToMake.derivationPath(store.state.globalState.scanResponse?.card?.derivationStyle)
|
||||
?.rawPath
|
||||
val derivation = blockchainToMake.derivationPath(
|
||||
style = store.state.globalState.scanResponse?.derivationStyleProvider?.getDerivationStyle(),
|
||||
)?.rawPath
|
||||
val blockchainNetwork = BlockchainNetwork(
|
||||
blockchain = blockchainToMake,
|
||||
derivationPath = derivation,
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ package com.tangem.tap.features.details.redux.walletconnect
|
|||
|
||||
import com.squareup.moshi.JsonClass
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import com.tangem.wallet.R
|
|||
object ClipboardOrScanQrDialog {
|
||||
fun create(wcUri: String, context: Context): AlertDialog {
|
||||
return AlertDialog.Builder(context).apply {
|
||||
setTitle(context.getString(R.string.wallet_connect_title))
|
||||
setTitle(context.getString(R.string.common_select_action))
|
||||
setMessage(context.getText(R.string.wallet_connect_clipboard_alert))
|
||||
setPositiveButton(context.getText(R.string.wallet_connect_paste_from_clipboard)) { _, _ ->
|
||||
store.dispatch(WalletConnectAction.OpenSession(wcUri))
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ fun StoriesScreen(
|
|||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
text = stringResource(id = R.string.search_tokens_title),
|
||||
text = stringResource(id = R.string.common_search_tokens),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,6 @@
|
|||
package com.tangem.tap.features.home.compose.views
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
|
|
@ -51,7 +46,7 @@ fun HomeButtons(
|
|||
},
|
||||
content = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.welcome_unlock_card),
|
||||
text = stringResource(id = R.string.home_button_scan),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import com.tangem.common.extensions.guard
|
|||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.TapWorkarounds.canSkipBackup
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.models.scan.ProductType
|
||||
|
|
@ -38,10 +37,7 @@ object OnboardingHelper {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO for Shiba disabled check wallet 2, and only check canSkipBackup, enable when release wallet 2
|
||||
// ([REDACTED_TASK_KEY])
|
||||
// response.cardTypesResolver.isWallet2() -> {
|
||||
!response.card.canSkipBackup -> {
|
||||
response.cardTypesResolver.isWallet2() -> {
|
||||
val emptyWallets = response.card.wallets.isEmpty()
|
||||
val activationInProgress = cardInfoStorage.isActivationInProgress(cardId)
|
||||
val backupNotActive = response.card.backupStatus?.isActive != true
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ class OnboardingNoteFragment : BaseOnboardingFragment<OnboardingNoteState>() {
|
|||
btnAlternativeAction.isVisible = false
|
||||
}
|
||||
|
||||
tvHeader.setText(R.string.onboarding_top_up_header)
|
||||
tvHeader.setText(R.string.onboarding_topup_title)
|
||||
if (state.balanceNonCriticalError == null) {
|
||||
tvBody.setText(R.string.onboarding_top_up_body)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.core.analytics.Analytics
|
|||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
import com.tangem.tap.common.postUi
|
||||
|
|
@ -92,7 +93,7 @@ private fun handleOtherCardsAction(action: Action) {
|
|||
val blockchainNetwork =
|
||||
BlockchainNetwork(
|
||||
blockchain = primaryBlockchain,
|
||||
card = updatedCard,
|
||||
derivationStyleProvider = updatedResponse.derivationStyleProvider,
|
||||
)
|
||||
.updateTokens(
|
||||
listOfNotNull(primaryToken),
|
||||
|
|
@ -102,11 +103,11 @@ private fun handleOtherCardsAction(action: Action) {
|
|||
listOf(
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Bitcoin,
|
||||
card = updatedCard,
|
||||
derivationStyleProvider = updatedResponse.derivationStyleProvider,
|
||||
),
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Ethereum,
|
||||
card = updatedCard,
|
||||
derivationStyleProvider = updatedResponse.derivationStyleProvider,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.domain.common.extensions.withMainContext
|
|||
import com.tangem.domain.common.util.twinsIsTwinned
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.UserWalletIdBuilder
|
||||
import com.tangem.domain.wallets.legacy.isLockedSync
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
|
|
@ -21,7 +22,6 @@ import com.tangem.tap.common.redux.AppState
|
|||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.twins.TwinCardsManager
|
||||
import com.tangem.tap.domain.userWalletList.isLockedSync
|
||||
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
|
||||
import com.tangem.tap.features.onboarding.OnboardingDialog
|
||||
import com.tangem.tap.features.onboarding.OnboardingHelper
|
||||
|
|
@ -50,7 +50,7 @@ private val twinsWalletMiddleware: Middleware<AppState> = { dispatch, state ->
|
|||
|
||||
@Suppress("LongMethod", "ComplexMethod", "MagicNumber")
|
||||
private fun handle(action: Action, dispatch: DispatchFunction) {
|
||||
val action = action as? TwinCardsAction ?: return
|
||||
if (action !is TwinCardsAction) return
|
||||
|
||||
val globalState = store.state.globalState
|
||||
val onboardingManager = globalState.onboardingState.onboardingManager
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ class TwinsCardsFragment : BaseOnboardingFragment<TwinCardsState>() {
|
|||
btnAlternativeAction.isVisible = false
|
||||
}
|
||||
|
||||
tvHeader.setText(R.string.onboarding_top_up_header)
|
||||
tvHeader.setText(R.string.onboarding_topup_title)
|
||||
tvBody.setText(R.string.onboarding_top_up_body)
|
||||
|
||||
btnRefreshBalanceWidget.changeState(state.walletBalance.state)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.domain.common.BlockchainNetwork
|
|||
import com.tangem.domain.common.TapWorkarounds.canSkipBackup
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.Artwork
|
||||
|
|
@ -125,7 +126,10 @@ private fun handleWalletAction(action: Action) {
|
|||
} else {
|
||||
listOf(Blockchain.Bitcoin, Blockchain.Ethereum)
|
||||
}.map { blockchain ->
|
||||
BlockchainNetwork(blockchain, result.data.card)
|
||||
BlockchainNetwork(
|
||||
blockchain = blockchain,
|
||||
derivationStyleProvider = updatedResponse.derivationStyleProvider,
|
||||
)
|
||||
}
|
||||
|
||||
scope.launch {
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ package com.tangem.tap.features.onboarding.products.wallet.ui
|
|||
import androidx.compose.runtime.collectAsState
|
||||
import com.tangem.feature.onboarding.api.OnboardingSeedPhrase
|
||||
import com.tangem.feature.onboarding.api.OnboardingSeedPhraseApi
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseScreen
|
||||
import com.tangem.feature.onboarding.presentation.wallet2.viewmodel.SeedPhraseViewModel
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletStep
|
||||
import com.tangem.wallet.R
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -44,11 +46,27 @@ internal class OnboardingSeedPhraseStateHandler(
|
|||
walletFragment.binding.onboardingWalletContainer.hide()
|
||||
walletFragment.bindingSeedPhrase.onboardingSeedPhraseContainer.show()
|
||||
walletFragment.bindingSeedPhrase.onboardingSeedPhraseContainer.setContent {
|
||||
val subScreen = viewModel.currentScreen.collectAsState().value
|
||||
setMainScreenToolbarTitle(walletFragment, subScreen)
|
||||
|
||||
onboardingSeedPhraseApi.ScreenContent(
|
||||
uiState = viewModel.uiState,
|
||||
subScreen = viewModel.currentScreen.collectAsState().value,
|
||||
subScreen = subScreen,
|
||||
progress = viewModel.progress.collectAsState(0).value.toFloat() / onboardingWalletMaxProgress,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMainScreenToolbarTitle(walletFragment: OnboardingWalletFragment, subScreen: SeedPhraseScreen) {
|
||||
val titleResId = when (subScreen) {
|
||||
SeedPhraseScreen.Intro,
|
||||
SeedPhraseScreen.AboutSeedPhrase,
|
||||
SeedPhraseScreen.YourSeedPhrase,
|
||||
SeedPhraseScreen.CheckSeedPhrase,
|
||||
-> R.string.onboarding_create_wallet_header
|
||||
SeedPhraseScreen.ImportSeedPhrase -> R.string.onboarding_seed_intro_button_import
|
||||
}
|
||||
|
||||
walletFragment.binding.toolbar.title = walletFragment.getString(titleResId)
|
||||
}
|
||||
}
|
||||
|
|
@ -257,7 +257,7 @@ class OnboardingWalletFragment :
|
|||
prepareBackupView()
|
||||
tvHeader.text = getText(R.string.onboarding_title_scan_origin_card)
|
||||
tvBody.text = getString(
|
||||
R.string.onboarding_subtitle_scan_origin_card,
|
||||
R.string.onboarding_subtitle_scan_primary,
|
||||
)
|
||||
|
||||
with(layoutButtonsCommon) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.core.navigation.AppScreen
|
|||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListManager
|
||||
import com.tangem.domain.wallets.legacy.isLockable
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.MainScreen
|
||||
|
|
@ -20,7 +21,6 @@ import com.tangem.tap.common.extensions.dispatchWithMain
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
|
||||
import com.tangem.tap.domain.userWalletList.isLockable
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import com.tangem.core.navigation.NavigationAction
|
|||
import com.tangem.tap.common.GlobalLayoutStateHandler
|
||||
import com.tangem.tap.common.KeyboardObserver
|
||||
import com.tangem.tap.common.extensions.getQuantityString
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.features.BaseStoreFragment
|
||||
import com.tangem.tap.features.shop.domain.models.ProductState
|
||||
|
|
@ -153,11 +152,12 @@ internal class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSu
|
|||
animateProductSelection(state.selectedProduct)
|
||||
handlePriceState(state)
|
||||
handlePromoCodeState(state)
|
||||
if (shopifyFeatureToggleManager.isDynamicSalesProductsEnabled) {
|
||||
handleNotificationBlock(state)
|
||||
} else {
|
||||
handleOrderingDelayBlock(isVisible = state.isOrderingDelayBlockVisible)
|
||||
}
|
||||
// TODO: https://tangem.slack.com/archives/C01HARKDLQ0/p1691421861756069
|
||||
// if (shopifyFeatureToggleManager.isDynamicSalesProductsEnabled) {
|
||||
// handleNotificationBlock(state)
|
||||
// } else {
|
||||
// handleOrderingDelayBlock(isVisible = state.isOrderingDelayBlockVisible)
|
||||
// }
|
||||
handleButtonsState(state)
|
||||
}
|
||||
|
||||
|
|
@ -198,20 +198,20 @@ internal class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSu
|
|||
pbPromoCode.show(state.promoCodeLoading)
|
||||
}
|
||||
|
||||
private fun handleOrderingDelayBlock(isVisible: Boolean) {
|
||||
if (isVisible) binding.tvSoldOutDesc.show() else binding.tvSoldOutDesc.hide()
|
||||
}
|
||||
|
||||
private fun handleNotificationBlock(state: ShopState) {
|
||||
if (isVisible) {
|
||||
binding.tvSoldOutDesc.show()
|
||||
getSelectedSalesProduct(state)?.notification?.let { notification ->
|
||||
binding.tvSoldOutDesc.text = notification.description
|
||||
}
|
||||
} else {
|
||||
binding.tvSoldOutDesc.hide()
|
||||
}
|
||||
}
|
||||
// private fun handleOrderingDelayBlock(isVisible: Boolean) {
|
||||
// if (isVisible) binding.tvSoldOutDesc.show() else binding.tvSoldOutDesc.hide()
|
||||
// }
|
||||
//
|
||||
// private fun handleNotificationBlock(state: ShopState) {
|
||||
// if (isVisible) {
|
||||
// binding.tvSoldOutDesc.show()
|
||||
// getSelectedSalesProduct(state)?.notification?.let { notification ->
|
||||
// binding.tvSoldOutDesc.text = notification.description
|
||||
// }
|
||||
// } else {
|
||||
// binding.tvSoldOutDesc.hide()
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun handleButtonsState(state: ShopState) = with(binding) {
|
||||
btnPayGooglePay.root.show(state.isGooglePayAvailable)
|
||||
|
|
|
|||
|
|
@ -2,18 +2,20 @@ package com.tangem.tap.features.tokens.impl.domain
|
|||
|
||||
import androidx.paging.PagingData
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.extensions.toMapKey
|
||||
import com.tangem.common.flatMap
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.common.extensions.derivationPath
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.util.supportsHdWallet
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
|
|
@ -24,10 +26,6 @@ import com.tangem.tap.features.tokens.legacy.redux.TokenWithBlockchain
|
|||
import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.proxy.AppStateHolder
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.tap.userWalletsListManager
|
||||
import com.tangem.tap.walletCurrenciesManager
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import timber.log.Timber
|
||||
|
|
@ -51,11 +49,12 @@ internal class DefaultTokensListInteractor(
|
|||
override suspend fun saveChanges(tokens: List<TokenWithBlockchain>, blockchains: List<Blockchain>) {
|
||||
val scanResponse = requireNotNull(reduxStateHolder.scanResponse)
|
||||
|
||||
val derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle()
|
||||
val currentTokens = store.state.tokensState.addedWallets
|
||||
.toNonCustomTokensWithBlockchains(style = scanResponse.card.derivationStyle)
|
||||
.toNonCustomTokensWithBlockchains(derivationStyle = derivationStyle)
|
||||
|
||||
val currentBlockchains = store.state.tokensState.addedWallets
|
||||
.toNonCustomBlockchains(derivationStyle = scanResponse.card.derivationStyle)
|
||||
.toNonCustomBlockchains(derivationStyle = derivationStyle)
|
||||
|
||||
val blockchainsToAdd = blockchains.filterNot(currentBlockchains::contains)
|
||||
val blockchainsToRemove = currentBlockchains.filterNot(blockchains::contains)
|
||||
|
|
@ -73,18 +72,18 @@ internal class DefaultTokensListInteractor(
|
|||
remove(
|
||||
tokens = tokensToRemove,
|
||||
blockchains = blockchainsToRemove,
|
||||
derivationStyle = scanResponse.card.derivationStyle,
|
||||
derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle(),
|
||||
)
|
||||
|
||||
add(tokens = tokensToAdd, blockchains = blockchainsToAdd, scanResponse = scanResponse)
|
||||
}
|
||||
|
||||
private fun List<WalletDataModel>.toNonCustomTokensWithBlockchains(
|
||||
style: DerivationStyle?,
|
||||
derivationStyle: DerivationStyle?,
|
||||
): List<TokenWithBlockchain> {
|
||||
return this.map(WalletDataModel::currency)
|
||||
.mapNotNull { currency ->
|
||||
if (currency !is Currency.Token || currency.isCustomCurrency(style)) return@mapNotNull null
|
||||
if (currency !is Currency.Token || currency.isCustomCurrency(derivationStyle)) return@mapNotNull null
|
||||
TokenWithBlockchain(token = currency.token, blockchain = currency.blockchain)
|
||||
}
|
||||
.distinct()
|
||||
|
|
@ -123,7 +122,7 @@ internal class DefaultTokensListInteractor(
|
|||
val currenciesToAdd = convertToCurrencies(
|
||||
tokens = tokens,
|
||||
blockchains = blockchains,
|
||||
derivationStyle = scanResponse.card.derivationStyle,
|
||||
derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle(),
|
||||
)
|
||||
|
||||
// TODO("[REDACTED_TASK_KEY] use DerivationManager")
|
||||
|
|
@ -136,10 +135,11 @@ internal class DefaultTokensListInteractor(
|
|||
}
|
||||
|
||||
private suspend fun deriveMissingBlockchains(scanResponse: ScanResponse, currencies: List<Currency>) {
|
||||
val derivations = listOfNotNull(
|
||||
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencies),
|
||||
getDerivations(EllipticCurve.Ed25519, scanResponse, currencies),
|
||||
).associate(transform = TokensMiddleware.DerivationData::derivations)
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivations = currencies.mapNotNull {
|
||||
val curve = config.primaryCurve(it.blockchain)
|
||||
curve?.let { getDerivations(curve, scanResponse, currencies) }
|
||||
}.associate(transform = TokensMiddleware.DerivationData::derivations)
|
||||
|
||||
if (derivations.isEmpty()) {
|
||||
submitAdd(scanResponse, currencies)
|
||||
|
|
@ -184,7 +184,7 @@ internal class DefaultTokensListInteractor(
|
|||
.map(Currency::blockchain)
|
||||
.distinct()
|
||||
.filter { it.getSupportedCurves().contains(curve) }
|
||||
.mapNotNull { it.derivationPath(scanResponse.card.derivationStyle) }
|
||||
.mapNotNull { it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle()) }
|
||||
|
||||
val customTokensCandidates = currencyList
|
||||
.filter { it.blockchain.getSupportedCurves().contains(curve) }
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ private fun Preview_TokensListScreen_Read() {
|
|||
TokensListScreen(
|
||||
stateHolder = TokensListStateHolder.ReadContent(
|
||||
toolbarState = TokensListToolbarState.Title.Read(
|
||||
titleResId = R.string.search_tokens_title,
|
||||
titleResId = R.string.common_search_tokens,
|
||||
onBackButtonClick = {},
|
||||
onSearchButtonClick = {},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -11,12 +11,7 @@ import androidx.compose.material.Icon
|
|||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -186,7 +181,7 @@ private fun Preview_AddTokensToolbar_ReadAccess() {
|
|||
TangemTheme {
|
||||
TokensListToolbar(
|
||||
state = Title.Read(
|
||||
titleResId = R.string.search_tokens_title,
|
||||
titleResId = R.string.common_search_tokens,
|
||||
onBackButtonClick = {},
|
||||
onSearchButtonClick = {},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -102,14 +102,14 @@ internal class TokensListViewModel @Inject constructor(
|
|||
private fun getInitialToolbarState(): TokensListToolbarState {
|
||||
return if (args.isManageAccess) {
|
||||
TokensListToolbarState.Title.Manage(
|
||||
titleResId = R.string.main_manage_tokens,
|
||||
titleResId = R.string.add_tokens_title,
|
||||
onBackButtonClick = actionsHandler::onBackButtonClick,
|
||||
onSearchButtonClick = actionsHandler::onSearchButtonClick,
|
||||
onAddCustomTokenClick = actionsHandler::onAddCustomTokenClick,
|
||||
)
|
||||
} else {
|
||||
TokensListToolbarState.Title.Read(
|
||||
titleResId = R.string.search_tokens_title,
|
||||
titleResId = R.string.common_search_tokens,
|
||||
onBackButtonClick = actionsHandler::onBackButtonClick,
|
||||
onSearchButtonClick = actionsHandler::onSearchButtonClick,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.features.tokens.legacy.redux
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import org.rekotlin.Action
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.features.tokens.legacy.redux
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
import com.tangem.common.extensions.ByteArrayKey
|
||||
|
|
@ -13,7 +13,9 @@ import com.tangem.core.navigation.AppScreen
|
|||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.DomainWrapped
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.common.extensions.derivationPath
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.util.hasDerivation
|
||||
import com.tangem.domain.common.util.supportsHdWallet
|
||||
import com.tangem.domain.features.addCustomToken.CustomCurrency
|
||||
|
|
@ -21,7 +23,7 @@ import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenAction
|
|||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.redux.domainStore
|
||||
import com.tangem.operations.derivation.ExtendedPublicKeysMap
|
||||
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.ManageTokens
|
||||
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
|
|
@ -30,11 +32,6 @@ import com.tangem.tap.common.redux.global.GlobalAction
|
|||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.scope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
import com.tangem.tap.userWalletsListManager
|
||||
import com.tangem.tap.walletCurrenciesManager
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.rekotlin.Middleware
|
||||
|
|
@ -72,7 +69,7 @@ object TokensMiddleware {
|
|||
currencies = convertToCurrencies(
|
||||
blockchains = blockchainsToRemove,
|
||||
tokens = tokensToRemove,
|
||||
derivationStyle = scanResponse.card.derivationStyle,
|
||||
derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle(),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -87,7 +84,7 @@ object TokensMiddleware {
|
|||
val currencyList = convertToCurrencies(
|
||||
blockchains = blockchainsToAdd,
|
||||
tokens = tokensToAdd,
|
||||
derivationStyle = scanResponse.card.derivationStyle,
|
||||
derivationStyle = scanResponse.derivationStyleProvider.getDerivationStyle(),
|
||||
)
|
||||
|
||||
if (scanResponse.supportsHdWallet()) {
|
||||
|
|
@ -123,10 +120,11 @@ object TokensMiddleware {
|
|||
currencyList: List<Currency>,
|
||||
onSuccess: (ScanResponse) -> Unit,
|
||||
) {
|
||||
val derivationDataList = listOfNotNull(
|
||||
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencyList),
|
||||
getDerivations(EllipticCurve.Ed25519, scanResponse, currencyList),
|
||||
)
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivationDataList = currencyList.mapNotNull {
|
||||
val curve = config.primaryCurve(it.blockchain)
|
||||
curve?.let { getDerivations(curve, scanResponse, currencyList) }
|
||||
}
|
||||
val derivations = derivationDataList.associate { it.derivations }
|
||||
if (derivations.isEmpty()) {
|
||||
onSuccess(scanResponse)
|
||||
|
|
@ -175,7 +173,7 @@ object TokensMiddleware {
|
|||
val manageTokensCandidates = currencyList.map { it.blockchain }.distinct().filter {
|
||||
it.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull {
|
||||
it.derivationPath(scanResponse.card.derivationStyle)
|
||||
it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
|
||||
val customTokensCandidates = currencyList.filter {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.features.tokens.legacy.redux
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package com.tangem.tap.features.wallet.models
|
||||
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.extensions.derivationPath
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.common.extensions.toCoinId
|
||||
import com.tangem.domain.features.addCustomToken.CustomCurrency
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.tangem.core.navigation.AppScreen
|
|||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.datasource.connection.NetworkConnectionManager
|
||||
import com.tangem.domain.userwallets.GetCardImageUseCase
|
||||
import com.tangem.domain.wallets.legacy.lockIfLockable
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Basic
|
||||
|
|
@ -24,7 +25,6 @@ import com.tangem.tap.common.redux.global.GlobalAction
|
|||
import com.tangem.tap.domain.TapError
|
||||
import com.tangem.tap.domain.model.WalletDataModel
|
||||
import com.tangem.tap.domain.model.WalletStoreModel
|
||||
import com.tangem.tap.domain.userWalletList.lockIfLockable
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.send.redux.PrepareSendScreen
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
package com.tangem.tap.features.wallet.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.*
|
||||
import android.widget.TextView
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.annotation.ColorRes
|
||||
|
|
@ -23,8 +19,8 @@ import com.tangem.common.doOnResult
|
|||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.extensions.withMainContext
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.feature.swap.api.SwapFeatureToggleManager
|
||||
import com.tangem.feature.swap.domain.SwapInteractor
|
||||
import com.tangem.sdk.extensions.dpToPx
|
||||
|
|
@ -32,14 +28,7 @@ import com.tangem.tap.common.SnackbarHandler
|
|||
import com.tangem.tap.common.TestActions
|
||||
import com.tangem.tap.common.analytics.events.DetailsScreen
|
||||
import com.tangem.tap.common.analytics.events.Token
|
||||
import com.tangem.tap.common.extensions.appendIfNotNull
|
||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
||||
import com.tangem.tap.common.extensions.fitChipsByGroupWidth
|
||||
import com.tangem.tap.common.extensions.getColor
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.extensions.toQrCode
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.recyclerView.SpaceItemDecoration
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.utils.SafeStoreSubscriber
|
||||
|
|
@ -57,15 +46,7 @@ import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter
|
|||
import com.tangem.tap.features.wallet.ui.adapters.WalletDetailWarningMessagesAdapter
|
||||
import com.tangem.tap.features.wallet.ui.images.load
|
||||
import com.tangem.tap.features.wallet.ui.test.TestWallet
|
||||
import com.tangem.tap.features.wallet.ui.utils.assembleWarnings
|
||||
import com.tangem.tap.features.wallet.ui.utils.getAvailableActions
|
||||
import com.tangem.tap.features.wallet.ui.utils.getFormattedCryptoAmount
|
||||
import com.tangem.tap.features.wallet.ui.utils.getFormattedFiatAmount
|
||||
import com.tangem.tap.features.wallet.ui.utils.isAvailableToBuy
|
||||
import com.tangem.tap.features.wallet.ui.utils.isAvailableToSell
|
||||
import com.tangem.tap.features.wallet.ui.utils.isAvailableToSwap
|
||||
import com.tangem.tap.features.wallet.ui.utils.mainButton
|
||||
import com.tangem.tap.features.wallet.ui.utils.shouldShowMultipleAddress
|
||||
import com.tangem.tap.features.wallet.ui.utils.*
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.userWalletsListManagerSafe
|
||||
import com.tangem.tap.walletCurrenciesManager
|
||||
|
|
@ -336,10 +317,8 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), SafeSt
|
|||
private fun handleCurrencyIcon(currency: Currency) = with(binding.lWalletDetails.lBalance) {
|
||||
ivCurrency.load(
|
||||
currency = currency,
|
||||
derivationStyle = store.state.globalState
|
||||
.scanResponse
|
||||
?.card
|
||||
?.derivationStyle,
|
||||
derivationStyle = store.state.globalState.scanResponse
|
||||
?.derivationStyleProvider?.getDerivationStyle(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import androidx.recyclerview.widget.DiffUtil
|
|||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.tap.common.analytics.events.Portfolio
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
|
|
@ -77,10 +77,8 @@ class WalletAdapter : ListAdapter<WalletDataModel, WalletAdapter.WalletsViewHold
|
|||
|
||||
ivCurrency.load(
|
||||
currency = wallet.currency,
|
||||
derivationStyle = store.state.globalState
|
||||
.scanResponse
|
||||
?.card
|
||||
?.derivationStyle,
|
||||
derivationStyle = store.state.globalState.scanResponse
|
||||
?.derivationStyleProvider?.getDerivationStyle(),
|
||||
)
|
||||
|
||||
lContent.tvCurrency.text = wallet.currency.currencyName
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import android.widget.TextView
|
|||
import androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isVisible
|
||||
import com.tangem.blockchain.common.DerivationStyle
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.sdk.extensions.dpToPx
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.wallet.databinding.ViewCurrencyIconBinding
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.badoo.mvicore.modelWatcher
|
|||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.tap.common.analytics.events.MainScreen
|
||||
import com.tangem.tap.common.analytics.events.Portfolio
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
|
|
@ -104,13 +104,13 @@ class MultiWalletView : WalletView() {
|
|||
watcher.invoke(state)
|
||||
|
||||
binding.btnAddToken.setOnClickListener {
|
||||
val card = store.state.globalState.scanResponse!!.card
|
||||
Analytics.send(Portfolio.ButtonManageTokens())
|
||||
|
||||
store.dispatch(
|
||||
TokensAction.SetArgs.ManageAccess(
|
||||
wallets = state.walletsDataFromStores,
|
||||
derivationStyle = card.derivationStyle,
|
||||
derivationStyle = store.state.globalState.scanResponse
|
||||
?.derivationStyleProvider?.getDerivationStyle(),
|
||||
),
|
||||
)
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.AddTokens))
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.tangem.core.navigation.NavigationAction
|
|||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.userwallets.UserWalletIdBuilder
|
||||
import com.tangem.domain.wallets.legacy.unlockIfLockable
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.*
|
||||
|
|
@ -20,7 +21,6 @@ import com.tangem.tap.common.extensions.onUserWalletSelected
|
|||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.domain.model.TotalFiatBalance
|
||||
import com.tangem.tap.domain.model.WalletStoreModel
|
||||
import com.tangem.tap.domain.userWalletList.unlockIfLockable
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.domain.wallets.legacy.isLocked
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.tap.common.analytics.events.MyWallets
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletsListError
|
||||
import com.tangem.tap.domain.userWalletList.isLocked
|
||||
import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||
import com.tangem.tap.features.walletSelector.redux.WalletSelectorAction
|
||||
import com.tangem.tap.features.walletSelector.redux.WalletSelectorState
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ private fun LoadedTokensInfo(
|
|||
SpacerH2()
|
||||
Text(
|
||||
text = pluralStringResource(
|
||||
id = R.plurals.tokens_count,
|
||||
id = R.plurals.token_count,
|
||||
count = tokensCount,
|
||||
tokensCount,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.core.navigation.AppScreen
|
|||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.userwallets.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.legacy.unlockIfLockable
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.Basic
|
||||
|
|
@ -16,7 +17,6 @@ import com.tangem.tap.common.extensions.dispatchOnMain
|
|||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
import com.tangem.tap.common.extensions.onUserWalletSelected
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.domain.userWalletList.unlockIfLockable
|
||||
import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler
|
||||
import com.tangem.tap.features.signin.redux.SignInAction
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package com.tangem.tap.features.welcome.ui
|
|||
import androidx.lifecycle.ViewModel
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.domain.wallets.legacy.UserWalletsListError
|
||||
import com.tangem.tap.common.analytics.events.SignIn
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.userWalletList.UserWalletsListError
|
||||
import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeAction
|
||||
import com.tangem.tap.features.welcome.redux.WelcomeState
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@ import com.tangem.common.extensions.ByteArrayKey
|
|||
import com.tangem.common.extensions.toMapKey
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.configs.CardConfig
|
||||
import com.tangem.domain.common.extensions.derivationPath
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
import com.tangem.domain.common.util.hasDerivation
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.lib.crypto.DerivationManager
|
||||
|
|
@ -46,13 +48,13 @@ class DerivationManagerImpl(
|
|||
} else {
|
||||
null
|
||||
}
|
||||
val blockchainNetwork = BlockchainNetwork(blockchain, card)
|
||||
val appCurrency = com.tangem.tap.features.wallet.models.Currency.fromBlockchainNetwork(
|
||||
blockchainNetwork,
|
||||
appToken,
|
||||
)
|
||||
val scanResponse = appStateHolder.scanResponse
|
||||
if (scanResponse != null) {
|
||||
val blockchainNetwork = BlockchainNetwork(blockchain, scanResponse.derivationStyleProvider)
|
||||
val appCurrency = com.tangem.tap.features.wallet.models.Currency.fromBlockchainNetwork(
|
||||
blockchainNetwork,
|
||||
appToken,
|
||||
)
|
||||
deriveMissingBlockchains(
|
||||
scanResponse = scanResponse,
|
||||
currencyList = listOf(appCurrency),
|
||||
|
|
@ -70,7 +72,7 @@ class DerivationManagerImpl(
|
|||
val scanResponse = appStateHolder.scanResponse
|
||||
val blockchain = Blockchain.fromNetworkId(networkId)
|
||||
if (scanResponse != null && blockchain != null) {
|
||||
return blockchain.derivationPath(appStateHolder.getActualCard()?.derivationStyle)?.rawPath
|
||||
return blockchain.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())?.rawPath
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
|
@ -93,10 +95,11 @@ class DerivationManagerImpl(
|
|||
onSuccess: (ScanResponse) -> Unit,
|
||||
onFailure: (Exception) -> Unit,
|
||||
) {
|
||||
val derivationDataList = listOfNotNull(
|
||||
getDerivations(EllipticCurve.Secp256k1, scanResponse, currencyList),
|
||||
getDerivations(EllipticCurve.Ed25519, scanResponse, currencyList),
|
||||
)
|
||||
val config = CardConfig.createConfig(scanResponse.card)
|
||||
val derivationDataList = currencyList.mapNotNull {
|
||||
val curve = config.primaryCurve(it.blockchain)
|
||||
curve?.let { getDerivations(curve, scanResponse, currencyList) }
|
||||
}
|
||||
val derivations = derivationDataList.associate { it.derivations }
|
||||
if (derivations.isEmpty()) {
|
||||
onSuccess(scanResponse)
|
||||
|
|
@ -162,7 +165,7 @@ class DerivationManagerImpl(
|
|||
val manageTokensCandidates = currencyList.map { it.blockchain }.distinct().filter {
|
||||
it.getSupportedCurves().contains(curve)
|
||||
}.mapNotNull {
|
||||
it.derivationPath(scanResponse.card.derivationStyle)
|
||||
it.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())
|
||||
}
|
||||
|
||||
val customTokensCandidates = currencyList.filter {
|
||||
|
|
|
|||
|
|
@ -1,86 +0,0 @@
|
|||
package com.tangem.tap.proxy
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.TransactionStatus
|
||||
import com.tangem.blockchain.common.WalletManager
|
||||
import com.tangem.blockchain.common.txhistory.TransactionHistoryItem
|
||||
import com.tangem.blockchain.common.txhistory.TransactionHistoryState
|
||||
import com.tangem.blockchain.extensions.Result
|
||||
import com.tangem.domain.common.BlockchainNetwork
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.lib.crypto.TxHistoryManager
|
||||
import com.tangem.lib.crypto.models.ProxyAmount
|
||||
import com.tangem.lib.crypto.models.txhistory.ProxyTransactionHistoryItem
|
||||
import com.tangem.lib.crypto.models.txhistory.ProxyTransactionHistoryState
|
||||
import com.tangem.lib.crypto.models.txhistory.ProxyTransactionStatus
|
||||
|
||||
class TxHistoryManagerImpl(
|
||||
private val appStateHolder: AppStateHolder,
|
||||
) : TxHistoryManager {
|
||||
|
||||
override suspend fun checkTxHistoryState(networkId: String, derivationPath: String?): ProxyTransactionHistoryState {
|
||||
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
|
||||
val walletManager = getActualWalletManager(blockchain, derivationPath)
|
||||
val state = walletManager.getTransactionHistoryState(address = walletManager.wallet.address)
|
||||
return state.mapToProxy()
|
||||
}
|
||||
|
||||
override suspend fun getTxHistoryItems(
|
||||
networkId: String,
|
||||
derivationPath: String?,
|
||||
page: Int,
|
||||
pageSize: Int,
|
||||
): List<ProxyTransactionHistoryItem> {
|
||||
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
|
||||
val walletManager = getActualWalletManager(blockchain, derivationPath)
|
||||
val itemsResult = walletManager.getTransactionsHistory(
|
||||
address = walletManager.wallet.address,
|
||||
page = page,
|
||||
pageSize = pageSize,
|
||||
)
|
||||
|
||||
return when (itemsResult) {
|
||||
is Result.Success -> itemsResult.data.items.map { historyItem -> historyItem.mapToProxy() }
|
||||
is Result.Failure -> error(itemsResult.error.message ?: itemsResult.error.customMessage)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getActualWalletManager(blockchain: Blockchain, derivationPath: String?): WalletManager {
|
||||
val blockchainNetwork = BlockchainNetwork(blockchain, derivationPath, emptyList())
|
||||
val walletManager = appStateHolder.walletState?.getWalletManager(blockchainNetwork)
|
||||
return requireNotNull(walletManager) { "no wallet manager found" }
|
||||
}
|
||||
|
||||
private fun TransactionHistoryState.mapToProxy(): ProxyTransactionHistoryState {
|
||||
return when (this) {
|
||||
TransactionHistoryState.Success.Empty -> ProxyTransactionHistoryState.Success.Empty
|
||||
is TransactionHistoryState.Failed.FetchError -> ProxyTransactionHistoryState.Failed.FetchError(exception)
|
||||
TransactionHistoryState.NotImplemented -> ProxyTransactionHistoryState.NotImplemented
|
||||
is TransactionHistoryState.Success.HasTransactions ->
|
||||
ProxyTransactionHistoryState.Success.HasTransactions(txCount)
|
||||
}
|
||||
}
|
||||
|
||||
private fun TransactionHistoryItem.mapToProxy() = ProxyTransactionHistoryItem(
|
||||
txHash = txHash,
|
||||
timestamp = timestamp,
|
||||
direction = when (val direction = direction) {
|
||||
is TransactionHistoryItem.TransactionDirection.Incoming ->
|
||||
ProxyTransactionHistoryItem.TransactionDirection.Incoming(direction.from)
|
||||
is TransactionHistoryItem.TransactionDirection.Outgoing ->
|
||||
ProxyTransactionHistoryItem.TransactionDirection.Outgoing(direction.to)
|
||||
},
|
||||
status = when (status) {
|
||||
TransactionStatus.Confirmed -> ProxyTransactionStatus.Confirmed
|
||||
TransactionStatus.Unconfirmed -> ProxyTransactionStatus.Unconfirmed
|
||||
},
|
||||
type = when (type) {
|
||||
TransactionHistoryItem.TransactionType.Transfer -> ProxyTransactionHistoryItem.TransactionType.Transfer
|
||||
},
|
||||
amount = ProxyAmount(
|
||||
currencySymbol = amount.currencySymbol,
|
||||
value = requireNotNull(amount.value) { "Amount value must not be null" },
|
||||
decimals = amount.decimals,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ import com.tangem.domain.common.util.cardTypesResolver
|
|||
import com.tangem.feature.learn2earn.domain.api.Learn2earnDependencyProvider
|
||||
import com.tangem.lib.crypto.DerivationManager
|
||||
import com.tangem.lib.crypto.TransactionManager
|
||||
import com.tangem.lib.crypto.TxHistoryManager
|
||||
import com.tangem.lib.crypto.UserWalletManager
|
||||
import com.tangem.tap.proxy.*
|
||||
import dagger.Module
|
||||
|
|
@ -59,12 +58,6 @@ class ProxyModule {
|
|||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideTxHistoryManager(appStateHolder: AppStateHolder): TxHistoryManager {
|
||||
return TxHistoryManagerImpl(appStateHolder = appStateHolder)
|
||||
}
|
||||
|
||||
// regions FeatureConsumers
|
||||
@Provides
|
||||
@Singleton
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue