diff --git a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt index d03a7956e9..df4bd27c47 100644 --- a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt @@ -10,12 +10,17 @@ import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.ByteArrayKey import com.tangem.common.extensions.toMapKey import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.data.tokens.utils.CryptoCurrencyFactory import com.tangem.domain.common.BlockchainNetwork +import com.tangem.domain.common.DerivationStyleProvider import com.tangem.domain.common.configs.CardConfig 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.domain.tokens.model.CryptoCurrency +import com.tangem.domain.tokens.repository.CurrenciesRepository +import com.tangem.domain.wallets.models.UserWalletId import com.tangem.lib.crypto.DerivationManager import com.tangem.lib.crypto.models.Currency import com.tangem.lib.crypto.models.Currency.NonNativeToken @@ -28,6 +33,7 @@ import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TapError import com.tangem.tap.features.tokens.legacy.redux.TokensMiddleware import com.tangem.tap.scope +import com.tangem.tap.userWalletsListManager import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlin.coroutines.suspendCoroutine @@ -35,21 +41,14 @@ import com.tangem.tap.features.wallet.models.Currency as WalletModelCurrency class DerivationManagerImpl( private val appStateHolder: AppStateHolder, + private val currenciesRepository: CurrenciesRepository, ) : DerivationManager { override suspend fun deriveMissingBlockchains(currency: Currency) = suspendCoroutine { continuation -> val blockchain = Blockchain.fromNetworkId(currency.networkId) val card = appStateHolder.getActualCard() if (blockchain != null && card != null) { - val appToken = if (currency is NonNativeToken) { - Token( - symbol = currency.symbol, - contractAddress = currency.contractAddress, - decimals = currency.decimalCount, - ) - } else { - null - } + val appToken = getAppToken(currency) val scanResponse = appStateHolder.scanResponse if (scanResponse != null) { val blockchainNetwork = BlockchainNetwork(blockchain, scanResponse.derivationStyleProvider) @@ -70,6 +69,64 @@ class DerivationManagerImpl( } } + override suspend fun deriveAndAddTokens(currency: Currency) = suspendCoroutine { continuation -> + val selectedUserWallet = requireNotNull( + userWalletsListManager.selectedUserWalletSync, + ) { "selectedUserWallet shouldn't be null" } + val scanResponse = selectedUserWallet.scanResponse + val blockchain = requireNotNull( + Blockchain.fromNetworkId(currency.networkId), + ) { "unsupported blockchain" } + val derivationStyleProvider = scanResponse.derivationStyleProvider + val derivationPath = requireNotNull( + blockchain.derivationPath(derivationStyleProvider.getDerivationStyle())?.rawPath, + ) { "derivationPath shouldn't be null" } + val hasDerivation = scanResponse.hasDerivation( + blockchain, + derivationPath, + ) + if (hasDerivation) { + scope.launch { + addToken( + userWalletId = selectedUserWallet.walletId, + blockchain = blockchain, + currency = currency, + derivationPath = derivationPath, + derivationStyleProvider = derivationStyleProvider, + ) + } + } else { + val blockchainNetwork = BlockchainNetwork(blockchain, scanResponse.derivationStyleProvider) + val appCurrency = WalletModelCurrency.fromBlockchainNetwork( + blockchainNetwork, + getAppToken(currency), + ) + deriveMissingBlockchains( + scanResponse = scanResponse, + currencyList = listOf(appCurrency), + onSuccess = { updatedScanResponse -> + scope.launch { + userWalletsListManager.update( + userWalletId = selectedUserWallet.walletId, + update = { it.copy(scanResponse = updatedScanResponse) }, + ) + addToken( + userWalletId = selectedUserWallet.walletId, + blockchain = blockchain, + currency = currency, + derivationPath = derivationPath, + derivationStyleProvider = derivationStyleProvider, + ) + continuation.resumeWith(Result.success(derivationPath)) + } + }, + onFailure = { + continuation.resumeWith(Result.failure(it)) + }, + ) + } + } + override fun getDerivationPathForBlockchain(networkId: String): String? { val scanResponse = appStateHolder.scanResponse val blockchain = Blockchain.fromNetworkId(networkId) @@ -91,6 +148,57 @@ class DerivationManagerImpl( return false } + private suspend fun addToken( + userWalletId: UserWalletId, + blockchain: Blockchain, + currency: Currency, + derivationPath: String, + derivationStyleProvider: DerivationStyleProvider, + ) { + currenciesRepository.addCurrencies( + userWalletId, + listOf( + convertCurrency( + blockchain = blockchain, + currency = currency, + derivationPath = derivationPath, + derivationStyleProvider = derivationStyleProvider, + ), + ), + ) + } + + private fun convertCurrency( + blockchain: Blockchain, + currency: Currency, + derivationPath: String, + derivationStyleProvider: DerivationStyleProvider, + ): CryptoCurrency { + val cryptoCurrencyFactory = CryptoCurrencyFactory() + return when (currency) { + is Currency.NativeToken -> { + cryptoCurrencyFactory.createCoin( + blockchain = blockchain, + extraDerivationPath = derivationPath, + derivationStyleProvider = derivationStyleProvider, + ) + } + is NonNativeToken -> { + val sdkToken = Token( + symbol = currency.symbol, + contractAddress = currency.contractAddress, + decimals = currency.decimalCount, + ) + cryptoCurrencyFactory.createToken( + sdkToken = sdkToken, + blockchain = blockchain, + extraDerivationPath = derivationPath, + derivationStyleProvider = derivationStyleProvider, + ) + } + } as CryptoCurrency + } + private fun deriveMissingBlockchains( scanResponse: ScanResponse, currencyList: List, @@ -204,6 +312,17 @@ class DerivationManagerImpl( return TokensMiddleware.DerivationData(derivations = mapKeyOfWalletPublicKey to toDerive) } + private fun getAppToken(currency: Currency): Token? { + return if (currency is NonNativeToken) { + Token( + symbol = currency.symbol, + contractAddress = currency.contractAddress, + decimals = currency.decimalCount, + ) + } else { + null + } + } /** * Simple error handler * for now specifically handle only UserCancelled diff --git a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt index ae87ca5aec..6165cbd367 100644 --- a/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/UserWalletManagerImpl.kt @@ -94,8 +94,7 @@ class UserWalletManagerImpl( UserWalletIdBuilder.card(it) .build() ?.stringValue - } - ?: "" + } ?: "" } override suspend fun isTokenAdded(currency: Currency, derivationPath: String?): Boolean { diff --git a/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt b/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt index c4b935a3d5..8d2154c795 100644 --- a/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt +++ b/app/src/main/java/com/tangem/tap/proxy/di/ProxyModule.kt @@ -6,6 +6,7 @@ import com.tangem.core.featuretoggle.manager.FeatureTogglesManager import com.tangem.domain.card.repository.CardSdkConfigRepository import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.util.cardTypesResolver +import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.feature.learn2earn.domain.api.Learn2earnDependencyProvider import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles @@ -66,9 +67,13 @@ class ProxyModule { @Provides @Singleton - fun provideDerivationManager(appStateHolder: AppStateHolder): DerivationManager { + fun provideDerivationManager( + appStateHolder: AppStateHolder, + currenciesRepository: CurrenciesRepository, + ): DerivationManager { return DerivationManagerImpl( appStateHolder = appStateHolder, + currenciesRepository = currenciesRepository, ) } diff --git a/features/referral/domain/build.gradle.kts b/features/referral/domain/build.gradle.kts index 6f335c1221..036c5995f8 100644 --- a/features/referral/domain/build.gradle.kts +++ b/features/referral/domain/build.gradle.kts @@ -1,16 +1,26 @@ plugins { - alias(deps.plugins.kotlin.jvm) + alias(deps.plugins.android.library) + alias(deps.plugins.kotlin.android) alias(deps.plugins.kotlin.kapt) + alias(deps.plugins.kotlin.serialization) id("configuration") } +android { + namespace = "com.tangem.domain.referral" +} dependencies { /** Libs */ - implementation(project(":core:utils")) - implementation(project(":libs:crypto")) + implementation(projects.core.utils) - /** Time */ + /** Core modules */ + implementation(projects.libs.crypto) + + /** Feature Apis */ + implementation(projects.features.wallet.api) + + /** Dependencies */ implementation(deps.jodatime) /** DI */ diff --git a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralInteractorImpl.kt b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralInteractorImpl.kt index a62fbcca35..5beacce884 100644 --- a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralInteractorImpl.kt +++ b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralInteractorImpl.kt @@ -3,6 +3,7 @@ package com.tangem.feature.referral.domain import com.tangem.feature.referral.domain.converter.TokensConverter import com.tangem.feature.referral.domain.models.ReferralData import com.tangem.feature.referral.domain.models.TokenData +import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import com.tangem.lib.crypto.DerivationManager import com.tangem.lib.crypto.UserWalletManager import com.tangem.lib.crypto.models.Currency @@ -12,6 +13,7 @@ internal class ReferralInteractorImpl( private val derivationManager: DerivationManager, private val userWalletManager: UserWalletManager, private val tokensConverter: TokensConverter, + private val walletFeatureToggles: WalletFeatureToggles, ) : ReferralInteractor { private val tokensForReferral = mutableListOf() @@ -30,7 +32,11 @@ internal class ReferralInteractorImpl( override suspend fun startReferral(): ReferralData { if (tokensForReferral.isNotEmpty()) { val currency = tokensConverter.convert(tokensForReferral.first()) - val derivationPath = deriveOrAddTokens(currency) + val derivationPath = if (walletFeatureToggles.isRedesignedScreenEnabled) { + derivationManager.deriveAndAddTokens(currency) + } else { + deriveAndAddTokens(currency) + } val publicAddress = userWalletManager.getWalletAddress(currency.networkId, derivationPath) return repository.startReferral( walletId = userWalletManager.getWalletId(), @@ -43,7 +49,7 @@ internal class ReferralInteractorImpl( } } - private suspend fun deriveOrAddTokens(currency: Currency): String { + private suspend fun deriveAndAddTokens(currency: Currency): String { val derivationPath = derivationManager.getDerivationPathForBlockchain(currency.networkId) if (derivationPath.isNullOrEmpty()) error("derivationPath shouldn't be empty") if (!derivationManager.hasDerivation(currency.networkId, derivationPath)) { diff --git a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/di/ReferralDomainModule.kt b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/di/ReferralDomainModule.kt index f991068cd5..8e6b9fbe88 100644 --- a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/di/ReferralDomainModule.kt +++ b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/di/ReferralDomainModule.kt @@ -4,6 +4,7 @@ import com.tangem.feature.referral.domain.ReferralInteractor import com.tangem.feature.referral.domain.ReferralInteractorImpl import com.tangem.feature.referral.domain.ReferralRepository import com.tangem.feature.referral.domain.converter.TokensConverter +import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles import com.tangem.lib.crypto.DerivationManager import com.tangem.lib.crypto.UserWalletManager import dagger.Module @@ -23,12 +24,14 @@ class ReferralDomainModule { derivationManager: DerivationManager, userWalletManager: UserWalletManager, tokensConverter: TokensConverter, + walletFeatureToggles: WalletFeatureToggles, ): ReferralInteractor { return ReferralInteractorImpl( repository = referralRepository, derivationManager = derivationManager, userWalletManager = userWalletManager, tokensConverter = tokensConverter, + walletFeatureToggles = walletFeatureToggles, ) } } \ No newline at end of file diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/DerivationManager.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/DerivationManager.kt index 7dd3d51970..bf9803cbb2 100644 --- a/libs/crypto/src/main/java/com/tangem/lib/crypto/DerivationManager.kt +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/DerivationManager.kt @@ -22,4 +22,9 @@ interface DerivationManager { * Checks that given [networkId] has derivations for [derivationPath] */ fun hasDerivation(networkId: String, derivationPath: String): Boolean + + /** + * Makes derivation for [Currency] if it is missing and adds token to wallet + */ + suspend fun deriveAndAddTokens(currency: Currency): String } \ No newline at end of file