diff --git a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt index 36dfe253b5..6665cab485 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt @@ -5,9 +5,9 @@ import com.tangem.blockchain.common.BlockchainSdkError import com.tangem.blockchain.common.Wallet import com.tangem.blockchain.common.WalletManager import com.tangem.common.services.Result +import com.tangem.domain.common.extensions.amountToCreateAccount import com.tangem.tap.common.TestActions import com.tangem.tap.domain.TapError -import com.tangem.tap.domain.extensions.amountToCreateAccount import com.tangem.tap.domain.getFirstToken import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.features.demo.isDemoCard diff --git a/app/src/main/java/com/tangem/tap/di/domain/WalletManagersFacadeModule.kt b/app/src/main/java/com/tangem/tap/di/domain/WalletManagersFacadeModule.kt new file mode 100644 index 0000000000..2af3b68c76 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/di/domain/WalletManagersFacadeModule.kt @@ -0,0 +1,29 @@ +package com.tangem.tap.di.domain + +import com.tangem.datasource.config.ConfigManager +import com.tangem.datasource.local.userwallet.UserWalletsStore +import com.tangem.datasource.local.walletmanager.WalletManagersStore +import com.tangem.domain.demo.DemoConfig +import com.tangem.domain.walletmanager.DefaultWalletManagersFacade +import com.tangem.domain.walletmanager.WalletManagerFacade +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object WalletManagersFacadeModule { + + @Provides + @Singleton + fun provideWalletManagersFacade( + walletManagersStore: WalletManagersStore, + userWalletsStore: UserWalletsStore, + demoConfig: DemoConfig, + configManager: ConfigManager, + ): WalletManagerFacade { + return DefaultWalletManagersFacade(walletManagersStore, userWalletsStore, demoConfig, configManager) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt b/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt deleted file mode 100644 index 9adb6b24aa..0000000000 --- a/app/src/main/java/com/tangem/tap/domain/extensions/Blockchain.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.tangem.tap.domain.extensions - -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.Token -import com.tangem.common.card.EllipticCurve -import java.math.BigDecimal - -@Suppress("MagicNumber") -fun Blockchain.amountToCreateAccount(token: Token? = null): BigDecimal? { - return when (this) { - Blockchain.Stellar -> if (token?.symbol == NODL) BigDecimal(1.5) else BigDecimal.ONE - Blockchain.XRP -> BigDecimal(10) - else -> null - } -} - -fun Blockchain.minimalAmount(): BigDecimal { - return 1.toBigDecimal().movePointLeft(decimals()) -} - -fun Blockchain.getPrimaryCurve(): EllipticCurve? { - return when { - getSupportedCurves().contains(EllipticCurve.Secp256k1) -> { - EllipticCurve.Secp256k1 - } - getSupportedCurves().contains(EllipticCurve.Ed25519) -> { - EllipticCurve.Ed25519 - } - else -> { - null - } - } -} - -private const val NODL = "NODL" \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index c3f23eb9b4..5bef94e017 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -20,6 +20,7 @@ import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.common.TapWorkarounds.isTangemTwins import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation import com.tangem.domain.common.TwinsHelper +import com.tangem.domain.common.extensions.getPrimaryCurve import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ProductType import com.tangem.domain.models.scan.ScanResponse @@ -30,7 +31,6 @@ import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask import com.tangem.operations.files.ReadFilesTask import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand import com.tangem.tap.domain.TapSdkError -import com.tangem.tap.domain.extensions.getPrimaryCurve import com.tangem.tap.domain.tokens.UserTokensRepository import com.tangem.tap.preferencesStorage import com.tangem.tap.scope diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt index 7a51a18e10..2fbd1e0624 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt @@ -9,13 +9,13 @@ import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.domain.common.BlockchainNetwork import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation +import com.tangem.domain.common.extensions.makeWalletManagerForApp import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.wallets.legacy.WalletManagersRepository import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.tap.domain.extensions.makeWalletManagerForApp import com.tangem.tap.domain.walletStores.WalletStoresError import com.tangem.tap.domain.walletStores.storage.WalletManagerStorage import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt index 85fd9d5c8e..c7eef5a974 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt @@ -5,7 +5,7 @@ import com.tangem.blockchain.common.BlockchainSdkError import com.tangem.blockchain.common.Wallet import com.tangem.blockchain.common.address.AddressType import com.tangem.common.core.TangemError -import com.tangem.tap.domain.extensions.amountToCreateAccount +import com.tangem.domain.common.extensions.amountToCreateAccount import com.tangem.tap.domain.getFirstToken import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.features.demo.DemoHelper diff --git a/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt index cb02be1422..ae1cf2fa2a 100644 --- a/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/demo/DemoOnboardingNoteMiddleware.kt @@ -1,10 +1,10 @@ package com.tangem.tap.features.demo import com.tangem.common.extensions.guard +import com.tangem.domain.common.extensions.makePrimaryWalletManager import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.demo.DemoConfig import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.domain.extensions.makePrimaryWalletManager import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.redux.ProgressState diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt index 0006840098..711c5acc69 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt @@ -4,6 +4,7 @@ import com.tangem.common.CompletionResult import com.tangem.common.extensions.guard import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.NavigationAction +import com.tangem.domain.common.extensions.makePrimaryWalletManager import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.common.analytics.events.AnalyticsParam @@ -14,7 +15,6 @@ import com.tangem.tap.common.redux.AppDialog 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.extensions.makePrimaryWalletManager import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE import com.tangem.tap.features.onboarding.OnboardingDialog diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index b768c53091..023e3137c4 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -6,6 +6,7 @@ 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.extensions.makePrimaryWalletManager import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.models.scan.ScanResponse @@ -19,7 +20,6 @@ import com.tangem.tap.common.redux.AppDialog 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.extensions.makePrimaryWalletManager import com.tangem.tap.domain.twins.TwinCardsManager import com.tangem.tap.domain.userWalletList.isLockedSync import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt index a76724c7c3..628e934435 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt @@ -16,6 +16,7 @@ import com.tangem.common.services.Result import com.tangem.core.analytics.Analytics import com.tangem.core.navigation.NavigationAction import com.tangem.domain.common.TapWorkarounds.isStart2Coin +import com.tangem.domain.common.extensions.minimalAmount import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.models.scan.CardDTO import com.tangem.tap.* @@ -31,7 +32,6 @@ import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TangemSigner import com.tangem.tap.domain.TapError import com.tangem.tap.domain.configurable.warningMessage.WarningMessage -import com.tangem.tap.domain.extensions.minimalAmount import com.tangem.tap.features.demo.DemoTransactionSender import com.tangem.tap.features.demo.isDemoCard import com.tangem.tap.features.send.redux.* diff --git a/domain/legacy/build.gradle.kts b/domain/legacy/build.gradle.kts index 525d2c8504..a649d1ced1 100644 --- a/domain/legacy/build.gradle.kts +++ b/domain/legacy/build.gradle.kts @@ -9,7 +9,9 @@ dependencies { implementation(project(":core:utils")) implementation(project(":common")) implementation(project(":libs:auth")) - implementation(project(":domain:models")) + implementation(projects.domain.demo) + implementation(projects.domain.models) + implementation(projects.domain.tokens) implementation(projects.domain.wallets.models) /** Tangem libraries */ diff --git a/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt index da1221c137..c54218c39a 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/Blockchain.kt @@ -1,6 +1,9 @@ package com.tangem.domain.common.extensions import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.Token +import com.tangem.common.card.EllipticCurve +import java.math.BigDecimal @Suppress("ComplexMethod") fun Blockchain.Companion.fromNetworkId(networkId: String): Blockchain? { @@ -187,6 +190,35 @@ fun Blockchain.isSupportedInApp(): Boolean { return !excludedBlockchains.contains(this) } +fun Blockchain.amountToCreateAccount(token: Token? = null): BigDecimal? { + return when (this) { + Blockchain.Stellar -> if (token?.symbol == NODL) BigDecimal(NODL_AMOUNT_TO_CREATE_ACCOUNT) else BigDecimal.ONE + Blockchain.XRP -> BigDecimal.TEN + else -> null + } +} + +fun Blockchain.minimalAmount(): BigDecimal { + return 1.toBigDecimal().movePointLeft(decimals()) +} + +fun Blockchain.getPrimaryCurve(): EllipticCurve? { + return when { + getSupportedCurves().contains(EllipticCurve.Secp256k1) -> { + EllipticCurve.Secp256k1 + } + getSupportedCurves().contains(EllipticCurve.Ed25519) -> { + EllipticCurve.Ed25519 + } + else -> { + null + } + } +} + +private const val NODL = "NODL" +private const val NODL_AMOUNT_TO_CREATE_ACCOUNT = 1.5 + private val excludedBlockchains = listOf( Blockchain.Unknown, Blockchain.Ducatus, diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/WalletManagerFactory.kt similarity index 67% rename from app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt rename to domain/legacy/src/main/java/com/tangem/domain/common/extensions/WalletManagerFactory.kt index 7253b1fccf..86ce14a4f4 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/common/extensions/WalletManagerFactory.kt @@ -1,17 +1,14 @@ -package com.tangem.tap.domain.extensions +package com.tangem.domain.common.extensions import com.tangem.blockchain.common.* import com.tangem.common.card.EllipticCurve import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toMapKey -import com.tangem.crypto.hdWallet.DerivationPath -import com.tangem.domain.common.BlockchainNetwork import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.features.wallet.models.Currency fun WalletManagerFactory.makeWalletManagerForApp( scanResponse: ScanResponse, @@ -38,7 +35,7 @@ fun WalletManagerFactory.makeWalletManagerForApp( curve = wallet.curve, ) } - scanResponse.card.isHdWalletAllowedByApp && seedKey != null && derivationParams != null -> { + scanResponse.card.settings.isHDWalletAllowed && seedKey != null && derivationParams != null -> { val derivedKeys = scanResponse.derivedKeys[wallet.publicKey.toMapKey()] val derivationPath = when (derivationParams) { is DerivationParams.Default -> blockchain.derivationPath(derivationParams.style) @@ -64,23 +61,8 @@ fun WalletManagerFactory.makeWalletManagerForApp( } } -fun WalletManagerFactory.makeWalletManagerForApp( - scanResponse: ScanResponse, - blockchainNetwork: BlockchainNetwork, -): WalletManager? { - return makeWalletManagerForApp( - scanResponse, - blockchain = blockchainNetwork.blockchain, - derivationParams = getDerivationParams(blockchainNetwork.derivationPath, scanResponse.card), - ) -} - -private fun getDerivationParams(derivationPath: String?, card: CardDTO): DerivationParams? { - return derivationPath?.let { - DerivationParams.Custom( - DerivationPath(it), - ) - } ?: if (!card.settings.isHDWalletAllowed) { +private fun getDerivationParams(card: CardDTO): DerivationParams? { + return if (!card.settings.isHDWalletAllowed) { null } else if (card.useOldStyleDerivation) { DerivationParams.Default(DerivationStyle.LEGACY) @@ -89,30 +71,13 @@ private fun getDerivationParams(derivationPath: String?, card: CardDTO): Derivat } } -fun WalletManagerFactory.makeWalletManagerForApp(scanResponse: ScanResponse, currency: Currency): WalletManager? { - return makeWalletManagerForApp( - scanResponse, - blockchain = currency.blockchain, - derivationParams = getDerivationParams(currency.derivationPath, scanResponse.card), - ) -} - -fun WalletManagerFactory.makeWalletManagersForApp( - scanResponse: ScanResponse, - blockchains: List, -): List { - return blockchains - .filter { it.isBlockchain() } - .mapNotNull { this.makeWalletManagerForApp(scanResponse, it) } -} - fun WalletManagerFactory.makePrimaryWalletManager(scanResponse: ScanResponse): WalletManager? { val blockchain = if (scanResponse.card.isTestCard) { scanResponse.cardTypesResolver.getBlockchain().getTestnetVersion() ?: return null } else { scanResponse.cardTypesResolver.getBlockchain() } - val derivationParams = getDerivationParams(null, scanResponse.card) + val derivationParams = getDerivationParams(scanResponse.card) return makeWalletManagerForApp( scanResponse = scanResponse, blockchain = blockchain, diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt new file mode 100644 index 0000000000..59f6379645 --- /dev/null +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/DefaultWalletManagersFacade.kt @@ -0,0 +1,140 @@ +package com.tangem.domain.walletmanager + +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.BlockchainSdkError +import com.tangem.blockchain.common.WalletManager +import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.datasource.config.ConfigManager +import com.tangem.datasource.local.userwallet.UserWalletsStore +import com.tangem.datasource.local.walletmanager.WalletManagersStore +import com.tangem.domain.common.TapWorkarounds.derivationStyle +import com.tangem.domain.common.util.hasDerivation +import com.tangem.domain.demo.DemoConfig +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.tokens.model.Network +import com.tangem.domain.walletmanager.model.UpdateWalletManagerResult +import com.tangem.domain.walletmanager.utils.SdkTokenConverter +import com.tangem.domain.walletmanager.utils.UpdateWalletManagerResultFactory +import com.tangem.domain.walletmanager.utils.WalletManagerFactory +import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.models.UserWalletId +import timber.log.Timber + +// FIXME: Move to its own module and make internal +@Deprecated("Inject the WalletManagerFacade interface using DI instead") +class DefaultWalletManagersFacade( + private val walletManagersStore: WalletManagersStore, + private val userWalletsStore: UserWalletsStore, + private val demoConfig: DemoConfig, + configManager: ConfigManager, +) : WalletManagerFacade { + + private val resultFactory by lazy { UpdateWalletManagerResultFactory() } + private val walletManagerFactory by lazy { WalletManagerFactory(configManager) } + private val sdkTokenConverter by lazy { SdkTokenConverter() } + + override suspend fun update( + userWalletId: UserWalletId, + networkId: Network.ID, + extraTokens: Set, + ): UpdateWalletManagerResult { + val userWallet = requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) { + "Unable to find a user wallet with provided ID: $userWalletId" + } + val blockchain = Blockchain.fromId(networkId.value) + + return getAndUpdateWalletManager(userWallet, blockchain, extraTokens) + } + + private suspend fun getAndUpdateWalletManager( + userWallet: UserWallet, + blockchain: Blockchain, + extraTokens: Set, + ): UpdateWalletManagerResult { + val scanResponse = userWallet.scanResponse + val derivationPath = blockchain.derivationPath(scanResponse.card.derivationStyle) + + if (derivationPath != null && !scanResponse.hasDerivation(blockchain, derivationPath.rawPath)) { + Timber.e("Derivation missed for: $blockchain") + return UpdateWalletManagerResult.MissedDerivation + } + + val walletManager = getOrCreateWalletManager(userWallet, blockchain, derivationPath) + if (walletManager == null || blockchain == Blockchain.Unknown) { + Timber.e("Unable to get a wallet manager for blockchain: $blockchain") + return UpdateWalletManagerResult.Unreachable + } + + updateWalletManagerTokensIfNeeded(walletManager, extraTokens) + + return try { + if (demoConfig.isDemoCardId(userWallet.scanResponse.card.cardId)) { + updateDemoWalletManager(walletManager, extraTokens) + } else { + updateWalletManager(walletManager) + } + } finally { + walletManagersStore.store(userWallet.walletId, walletManager) + } + } + + private fun updateDemoWalletManager( + walletManager: WalletManager, + tokens: Set, + ): UpdateWalletManagerResult { + val amount = demoConfig.getBalance(walletManager.wallet.blockchain) + walletManager.wallet.setAmount(amount) + + return resultFactory.getDemoResult(amount, tokens) + } + + private suspend fun updateWalletManager(walletManager: WalletManager): UpdateWalletManagerResult { + return try { + walletManager.update() + + resultFactory.getResult(walletManager) + } catch (e: BlockchainSdkError.AccountNotFound) { + resultFactory.getNoAccountResult(walletManager) + } catch (e: Throwable) { + Timber.e(e, "Unable to update a wallet manager for: ${walletManager.wallet.blockchain}") + + UpdateWalletManagerResult.Unreachable + } + } + + private suspend fun getOrCreateWalletManager( + userWallet: UserWallet, + blockchain: Blockchain, + derivationPath: DerivationPath?, + ): WalletManager? { + val userWalletId = userWallet.walletId + + var walletManager = walletManagersStore.getSyncOrNull( + userWalletId = userWalletId, + blockchain = blockchain, + derivationPath = derivationPath?.rawPath, + ) + + if (walletManager == null) { + walletManager = walletManagerFactory.createWalletManager( + scanResponse = userWallet.scanResponse, + blockchain = blockchain, + derivationPath = derivationPath, + ) ?: return null + + walletManagersStore.store(userWalletId, walletManager) + } + + return walletManager + } + + private fun updateWalletManagerTokensIfNeeded(walletManager: WalletManager, tokens: Set) { + if (tokens.isEmpty()) return + + val tokensToAdd = sdkTokenConverter + .convertList(tokens.toList()) + .filter { it !in walletManager.cardTokens } + + walletManager.addTokens(tokensToAdd) + } +} \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagerFacade.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagerFacade.kt new file mode 100644 index 0000000000..bbfbd71dbd --- /dev/null +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/WalletManagerFacade.kt @@ -0,0 +1,27 @@ +package com.tangem.domain.walletmanager + +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.tokens.model.Network +import com.tangem.domain.walletmanager.model.UpdateWalletManagerResult +import com.tangem.domain.wallets.models.UserWalletId + +// TODO: Move to its own module +/** + * A facade for managing wallets. + */ +interface WalletManagerFacade { + + /** + * Updates the wallet manager associated with a user's wallet and network. + * + * @param userWalletId The ID of the user's wallet. + * @param networkId The network ID. + * @param extraTokens Additional tokens. + * @return The result of updating the wallet manager. + */ + suspend fun update( + userWalletId: UserWalletId, + networkId: Network.ID, + extraTokens: Set, + ): UpdateWalletManagerResult +} \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/model/CryptoCurrencyAmount.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/model/CryptoCurrencyAmount.kt new file mode 100644 index 0000000000..192be587e5 --- /dev/null +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/model/CryptoCurrencyAmount.kt @@ -0,0 +1,15 @@ +package com.tangem.domain.walletmanager.model + +import java.math.BigDecimal + +sealed class CryptoCurrencyAmount { + + abstract val value: BigDecimal + + data class Coin(override val value: BigDecimal) : CryptoCurrencyAmount() + + data class Token( + val tokenContractAddress: String, + override val value: BigDecimal, + ) : CryptoCurrencyAmount() +} \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/model/UpdateWalletManagerResult.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/model/UpdateWalletManagerResult.kt new file mode 100644 index 0000000000..a516c03d0a --- /dev/null +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/model/UpdateWalletManagerResult.kt @@ -0,0 +1,17 @@ +package com.tangem.domain.walletmanager.model + +import java.math.BigDecimal + +sealed class UpdateWalletManagerResult { + + object MissedDerivation : UpdateWalletManagerResult() + + object Unreachable : UpdateWalletManagerResult() + + data class Verified( + val tokensAmounts: Set, + val hasTransactionsInProgress: Boolean, // TODO: May be add recent transactions + ) : UpdateWalletManagerResult() + + data class NoAccount(val amountToCreateAccount: BigDecimal) : UpdateWalletManagerResult() +} \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/SdkTokenConverter.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/SdkTokenConverter.kt new file mode 100644 index 0000000000..8fe4bdc174 --- /dev/null +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/SdkTokenConverter.kt @@ -0,0 +1,18 @@ +package com.tangem.domain.walletmanager.utils + +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.utils.converter.Converter +import com.tangem.blockchain.common.Token as SdkToken + +internal class SdkTokenConverter : Converter { + + override fun convert(value: CryptoCurrency.Token): SdkToken { + return SdkToken( + id = value.id.value.takeUnless { value.isCustom }, + name = value.name, + symbol = value.symbol, + contractAddress = value.contractAddress, + decimals = value.decimals, + ) + } +} \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt new file mode 100644 index 0000000000..bdf864f4fe --- /dev/null +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/UpdateWalletManagerResultFactory.kt @@ -0,0 +1,87 @@ +package com.tangem.domain.walletmanager.utils + +import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.AmountType +import com.tangem.blockchain.common.TransactionStatus +import com.tangem.blockchain.common.WalletManager +import com.tangem.domain.common.extensions.amountToCreateAccount +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.walletmanager.model.CryptoCurrencyAmount +import com.tangem.domain.walletmanager.model.UpdateWalletManagerResult +import timber.log.Timber +import java.math.BigDecimal + +internal class UpdateWalletManagerResultFactory { + + fun getResult(walletManager: WalletManager): UpdateWalletManagerResult.Verified { + val hasNotConfirmedTransactions = walletManager.wallet + .recentTransactions + .any { it.status != TransactionStatus.Confirmed } + + val amounts = walletManager.wallet.amounts + + return UpdateWalletManagerResult.Verified( + tokensAmounts = getTokensAmounts(amounts.values.toSet()), + hasTransactionsInProgress = hasNotConfirmedTransactions, + ) + } + + fun getDemoResult(demoAmount: Amount, tokens: Set): UpdateWalletManagerResult.Verified { + return UpdateWalletManagerResult.Verified( + tokensAmounts = getDemoTokensAmounts(demoAmount, tokens), + hasTransactionsInProgress = false, + ) + } + + fun getNoAccountResult(walletManager: WalletManager): UpdateWalletManagerResult.NoAccount { + val wallet = walletManager.wallet + val blockchain = wallet.blockchain + val amountToCreateAccount = blockchain.amountToCreateAccount( + token = wallet.getTokens().firstOrNull(), + ) + + requireNotNull(amountToCreateAccount) { + "Unable to get required amount to create account for: $blockchain" + } + + return UpdateWalletManagerResult.NoAccount(amountToCreateAccount) + } + + private fun getTokensAmounts(amounts: Set): Set { + val mutableAmounts = hashSetOf() + + return amounts.mapNotNullTo(mutableAmounts, ::getTokenAmount) + } + + private fun getDemoTokensAmounts(demoAmount: Amount, tokens: Set): Set { + val amountValue = demoAmount.value ?: BigDecimal.ZERO + val demoAmounts = hashSetOf(CryptoCurrencyAmount.Coin(amountValue)) + + return tokens.mapTo(demoAmounts) { token -> + CryptoCurrencyAmount.Token(token.contractAddress, amountValue) + } + } + + private fun getTokenAmount(amount: Amount): CryptoCurrencyAmount? { + return when (val type = amount.type) { + is AmountType.Token -> CryptoCurrencyAmount.Token( + tokenContractAddress = type.token.contractAddress, + value = getAmountValue(amount) ?: return null, + ) + is AmountType.Coin -> CryptoCurrencyAmount.Coin( + value = getAmountValue(amount) ?: return null, + ) + is AmountType.Reserve -> null + } + } + + private fun getAmountValue(amount: Amount): BigDecimal? { + val value = amount.value + + if (value == null) { + Timber.e("Amount not found for currency: ${amount.currencySymbol}") + } + + return value + } +} \ No newline at end of file diff --git a/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/WalletManagerFactory.kt b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/WalletManagerFactory.kt new file mode 100644 index 0000000000..f588b47702 --- /dev/null +++ b/domain/legacy/src/main/java/com/tangem/domain/walletmanager/utils/WalletManagerFactory.kt @@ -0,0 +1,47 @@ +package com.tangem.domain.walletmanager.utils + +import com.tangem.blockchain.common.* +import com.tangem.blockchain.common.WalletManagerFactory +import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.datasource.config.ConfigManager +import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation +import com.tangem.domain.common.extensions.makeWalletManagerForApp +import com.tangem.domain.models.scan.CardDTO +import com.tangem.domain.models.scan.ScanResponse + +internal class WalletManagerFactory( + private val configManager: ConfigManager, +) { + + private val sdkWalletManagerFactory by lazy { + WalletManagerFactory(configManager.config.blockchainSdkConfig) + } + + fun createWalletManager( + scanResponse: ScanResponse, + blockchain: Blockchain, + derivationPath: DerivationPath?, + ): WalletManager? { + val derivationParams = getDerivationParams(derivationPath, scanResponse.card) + + return sdkWalletManagerFactory.makeWalletManagerForApp( + scanResponse = scanResponse, + blockchain = blockchain, + derivationParams = derivationParams, + ) + } + + private fun getDerivationParams(derivationPath: DerivationPath?, card: CardDTO): DerivationParams? { + val derivationStyle = when { + !card.settings.isHDWalletAllowed -> return null + card.useOldStyleDerivation -> DerivationStyle.LEGACY + else -> DerivationStyle.NEW + } + + return if (derivationPath == null) { + DerivationParams.Default(derivationStyle) + } else { + DerivationParams.Custom(derivationPath) + } + } +} \ No newline at end of file