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 288774a29f..63b07213d1 100644 --- a/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt +++ b/app/src/main/java/com/tangem/tap/proxy/DerivationManagerImpl.kt @@ -52,31 +52,6 @@ class DerivationManagerImpl( AddCryptoCurrenciesUseCase(currenciesRepository, networksRepository) } - 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 = getAppToken(currency) - val scanResponse = appStateHolder.scanResponse - if (scanResponse != null) { - val blockchainNetwork = BlockchainNetwork(blockchain, scanResponse.derivationStyleProvider) - val appCurrency = com.tangem.tap.domain.model.Currency.fromBlockchainNetwork( - blockchainNetwork, - appToken, - ) - deriveMissingBlockchains( - scanResponse = scanResponse, - currencyList = listOf(appCurrency), - onSuccess = { continuation.resumeWith(Result.success(true)) }, - ) { - continuation.resumeWith(Result.failure(it)) - } - } - } else { - continuation.resumeWith(Result.failure(IllegalStateException("no blockchain or card found"))) - } - } - override suspend fun deriveAndAddTokens(currency: Currency) = suspendCoroutine { continuation -> val selectedUserWallet = requireNotNull( userWalletsListManager.selectedUserWalletSync, @@ -136,27 +111,6 @@ class DerivationManagerImpl( } } - override fun getDerivationPathForBlockchain(networkId: String): String? { - val scanResponse = appStateHolder.scanResponse - val blockchain = Blockchain.fromNetworkId(networkId) - if (scanResponse != null && blockchain != null) { - return blockchain.derivationPath(scanResponse.derivationStyleProvider.getDerivationStyle())?.rawPath - } - return null - } - - override fun hasDerivation(networkId: String, derivationPath: String): Boolean { - val scanResponse = appStateHolder.scanResponse - val blockchain = Blockchain.fromNetworkId(networkId) - if (scanResponse != null && blockchain != null) { - return scanResponse.hasDerivation( - blockchain, - derivationPath, - ) - } - return false - } - private suspend fun addToken( userWalletId: UserWalletId, blockchain: Blockchain, diff --git a/features/referral/data/build.gradle.kts b/features/referral/data/build.gradle.kts index 15aaa39fdf..76c384d6d6 100644 --- a/features/referral/data/build.gradle.kts +++ b/features/referral/data/build.gradle.kts @@ -8,14 +8,22 @@ plugins { dependencies { - /** Project*/ - implementation(project(":core:datasource")) - implementation(project(":core:utils")) - implementation(project(":features:referral:domain")) - + /** Project */ + implementation(projects.core.datasource) + implementation(projects.core.utils) + + /** Data modules */ + implementation(projects.data.tokens) + + /** Domain modules */ + implementation(projects.domain.legacy) + implementation(projects.domain.models) + implementation(projects.domain.tokens.models) + implementation(projects.domain.wallets.models) + implementation(projects.features.referral.domain) /** Libs */ - implementation(project(":libs:auth")) + implementation(projects.libs.auth) /** Time */ implementation(deps.jodatime) @@ -23,4 +31,7 @@ dependencies { /** DI */ implementation(deps.hilt.android) kapt(deps.hilt.kapt) + + /** Tangem deps */ + implementation(deps.tangem.blockchain) } \ No newline at end of file diff --git a/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt b/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt index 8f8d3a5c42..2496fde6e8 100644 --- a/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt +++ b/features/referral/data/src/main/java/com/tangem/feature/referral/data/ReferralRepositoryImpl.kt @@ -1,11 +1,20 @@ package com.tangem.feature.referral.data +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.Token +import com.tangem.data.tokens.utils.CryptoCurrencyFactory import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.api.tangemTech.models.StartReferralBody import com.tangem.datasource.demo.DemoModeDatasource +import com.tangem.datasource.local.userwallet.UserWalletsStore +import com.tangem.domain.common.extensions.fromNetworkId +import com.tangem.domain.common.util.derivationStyleProvider +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.referral.converters.ReferralConverter import com.tangem.feature.referral.domain.ReferralRepository import com.tangem.feature.referral.domain.models.ReferralData +import com.tangem.feature.referral.domain.models.TokenData import com.tangem.lib.auth.AuthProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.withContext @@ -17,6 +26,7 @@ internal class ReferralRepositoryImpl @Inject constructor( private val coroutineDispatcher: CoroutineDispatcherProvider, private val demoModeDatasource: DemoModeDatasource, private val authProvider: AuthProvider, + private val userWalletsStore: UserWalletsStore, ) : ReferralRepository { override val isDemoMode: Boolean @@ -55,4 +65,38 @@ internal class ReferralRepositoryImpl @Inject constructor( ) } } + + override suspend fun getCryptoCurrency(userWalletId: UserWalletId, tokenData: TokenData): CryptoCurrency? { + val userWallet = userWalletsStore.getSyncOrNull(userWalletId) ?: error("Wallet $userWalletId not found") + val derivationStyleProvider = userWallet.scanResponse.derivationStyleProvider + + val blockchain = Blockchain.fromNetworkId(tokenData.networkId) + ?: error("Blockchain ${tokenData.networkId} not found") + + val cryptoCurrencyFactory = CryptoCurrencyFactory() + + val contractAddress = tokenData.contractAddress + val decimalCount = tokenData.decimalCount + return if (contractAddress != null && decimalCount != null) { + val sdkToken = Token( + name = tokenData.name, + symbol = tokenData.symbol, + contractAddress = contractAddress, + decimals = decimalCount, + id = tokenData.id, + ) + cryptoCurrencyFactory.createToken( + sdkToken = sdkToken, + blockchain = blockchain, + extraDerivationPath = null, + derivationStyleProvider = derivationStyleProvider, + ) + } else { + cryptoCurrencyFactory.createCoin( + blockchain = blockchain, + extraDerivationPath = null, + derivationStyleProvider = derivationStyleProvider, + ) + } + } } \ No newline at end of file diff --git a/features/referral/data/src/main/java/com/tangem/feature/referral/di/ReferralRepositoryModule.kt b/features/referral/data/src/main/java/com/tangem/feature/referral/di/ReferralRepositoryModule.kt index 4d1da6230a..2214c244dd 100644 --- a/features/referral/data/src/main/java/com/tangem/feature/referral/di/ReferralRepositoryModule.kt +++ b/features/referral/data/src/main/java/com/tangem/feature/referral/di/ReferralRepositoryModule.kt @@ -2,6 +2,7 @@ package com.tangem.feature.referral.di import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.demo.DemoModeDatasource +import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.feature.referral.converters.ReferralConverter import com.tangem.feature.referral.data.ReferralRepositoryImpl import com.tangem.feature.referral.domain.ReferralRepository @@ -25,6 +26,7 @@ class ReferralRepositoryModule { coroutineDispatcherProvider: CoroutineDispatcherProvider, demoModeDatasource: DemoModeDatasource, authProvider: AuthProvider, + userWalletsStore: UserWalletsStore, ): ReferralRepository { return ReferralRepositoryImpl( referralApi = tangemTechApi, @@ -32,6 +34,7 @@ class ReferralRepositoryModule { coroutineDispatcher = coroutineDispatcherProvider, demoModeDatasource = demoModeDatasource, authProvider = authProvider, + userWalletsStore = userWalletsStore, ) } } \ No newline at end of file diff --git a/features/referral/domain/build.gradle.kts b/features/referral/domain/build.gradle.kts index 036c5995f8..0ae67f2d5f 100644 --- a/features/referral/domain/build.gradle.kts +++ b/features/referral/domain/build.gradle.kts @@ -17,13 +17,23 @@ dependencies { /** Core modules */ implementation(projects.libs.crypto) + /** Domain modules */ + implementation(projects.domain.card) + implementation(projects.domain.tokens) + implementation(projects.domain.tokens.models) + implementation(projects.domain.wallets) + implementation(projects.domain.wallets.models) + /** Feature Apis */ + implementation(projects.features.tester.api) implementation(projects.features.wallet.api) /** Dependencies */ + implementation(deps.arrow.core) implementation(deps.jodatime) + implementation(deps.timber) /** DI */ - implementation(deps.hilt.core) + implementation(deps.hilt.android) kapt(deps.hilt.kapt) } \ No newline at end of file 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 ecdb5989e3..379d153a48 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 @@ -1,16 +1,27 @@ package com.tangem.feature.referral.domain +import arrow.core.getOrElse +import com.tangem.domain.card.DerivePublicKeysUseCase +import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase +import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase 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.tester.api.TesterFeatureToggles import com.tangem.lib.crypto.DerivationManager import com.tangem.lib.crypto.UserWalletManager +import timber.log.Timber +@Suppress("LongParameterList") internal class ReferralInteractorImpl( private val repository: ReferralRepository, private val derivationManager: DerivationManager, private val userWalletManager: UserWalletManager, private val tokensConverter: TokensConverter, + private val derivePublicKeysUseCase: DerivePublicKeysUseCase, + private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, + private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase, + private val testerFeatureToggles: TesterFeatureToggles, ) : ReferralInteractor { private val tokensForReferral = mutableListOf() @@ -27,21 +38,59 @@ internal class ReferralInteractorImpl( } override suspend fun startReferral(): ReferralData { - if (tokensForReferral.isNotEmpty()) { - val currency = tokensConverter.convert(tokensForReferral.first()) - val derivationPath = derivationManager.deriveAndAddTokens(currency) - val publicAddress = userWalletManager.getWalletAddress(currency.networkId, derivationPath) - return repository.startReferral( - walletId = userWalletManager.getWalletId(), - networkId = currency.networkId, - tokenId = currency.id, - address = publicAddress, - ) + return if (tokensForReferral.isNotEmpty()) { + if (testerFeatureToggles.isDerivePublicKeysRefactoringEnabled) { + startReferralNew(tokenData = tokensForReferral.first()) + } else { + // TODO: delete [REDACTED_JIRA] + startReferralLegacy(tokenData = tokensForReferral.first()) + } } else { error("Tokens for ref is empty") } } + private suspend fun startReferralNew(tokenData: TokenData): ReferralData { + val userWallet = getSelectedWalletSyncUseCase().getOrElse { + error("Failed to get selected wallet: $it") + } + + val cryptoCurrency = repository.getCryptoCurrency(userWalletId = userWallet.walletId, tokenData = tokenData) + derivePublicKeysUseCase(userWallet.walletId, listOfNotNull(cryptoCurrency)).getOrElse { + Timber.e("Failed to derive public keys: $it") + throw it + } + + addCryptoCurrenciesUseCase( + userWalletId = userWallet.walletId, + currencies = listOfNotNull(cryptoCurrency), + ) + + val publicAddress = userWalletManager.getWalletAddress( + networkId = tokenData.networkId, + derivationPath = cryptoCurrency?.network?.derivationPath?.value, + ) + + return repository.startReferral( + walletId = userWalletManager.getWalletId(), + networkId = tokenData.networkId, + tokenId = tokenData.id, + address = publicAddress, + ) + } + + private suspend fun startReferralLegacy(tokenData: TokenData): ReferralData { + val currency = tokensConverter.convert(tokenData) + val derivationPath = derivationManager.deriveAndAddTokens(currency) + val publicAddress = userWalletManager.getWalletAddress(currency.networkId, derivationPath) + return repository.startReferral( + walletId = userWalletManager.getWalletId(), + networkId = currency.networkId, + tokenId = currency.id, + address = publicAddress, + ) + } + private fun saveReferralTokens(tokens: List) { tokensForReferral.clear() tokensForReferral.addAll(tokens) diff --git a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt index c3b5eaa9ca..07897eb1be 100644 --- a/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt +++ b/features/referral/domain/src/main/java/com/tangem/feature/referral/domain/ReferralRepository.kt @@ -1,6 +1,9 @@ package com.tangem.feature.referral.domain +import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.referral.domain.models.ReferralData +import com.tangem.feature.referral.domain.models.TokenData interface ReferralRepository { @@ -11,4 +14,6 @@ interface ReferralRepository { /** Starts user referral program */ suspend fun startReferral(walletId: String, networkId: String, tokenId: String, address: String): ReferralData + + suspend fun getCryptoCurrency(userWalletId: UserWalletId, tokenData: TokenData): CryptoCurrency? } \ No newline at end of file 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..9b90eb5b0a 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 @@ -1,34 +1,46 @@ package com.tangem.feature.referral.domain.di +import com.tangem.domain.card.DerivePublicKeysUseCase +import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase +import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase 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.tester.api.TesterFeatureToggles import com.tangem.lib.crypto.DerivationManager import com.tangem.lib.crypto.UserWalletManager import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton +import dagger.hilt.android.components.ViewModelComponent +import dagger.hilt.android.scopes.ViewModelScoped @Module -@InstallIn(SingletonComponent::class) +@InstallIn(ViewModelComponent::class) class ReferralDomainModule { @Provides - @Singleton + @ViewModelScoped fun provideReferralInteractor( referralRepository: ReferralRepository, derivationManager: DerivationManager, userWalletManager: UserWalletManager, tokensConverter: TokensConverter, + derivePublicKeysUseCase: DerivePublicKeysUseCase, + getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, + addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase, + testerFeatureToggles: TesterFeatureToggles, ): ReferralInteractor { return ReferralInteractorImpl( repository = referralRepository, derivationManager = derivationManager, userWalletManager = userWalletManager, tokensConverter = tokensConverter, + derivePublicKeysUseCase = derivePublicKeysUseCase, + getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase, + addCryptoCurrenciesUseCase = addCryptoCurrenciesUseCase, + testerFeatureToggles = testerFeatureToggles, ) } } \ 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 b62cb56576..e3f12c83f6 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 @@ -2,29 +2,9 @@ package com.tangem.lib.crypto import com.tangem.lib.crypto.models.Currency -// FIXME: Migration [REDACTED_JIRA] @Deprecated(message = "Use DerivePublicKeysUseCase instead") interface DerivationManager { - /** - * Derives missing blockchain and returns flag true if did it successfully - * - * @param currency to derive (Native token or not) - */ - suspend fun deriveMissingBlockchains(currency: Currency): Boolean - - /** - * Returns derivationPath or null for blockchain with given networkId - * - * @param networkId - */ - fun getDerivationPathForBlockchain(networkId: String): String? - - /** - * 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 */