Updated on 2026-08-14
This commit is contained in:
parent
c68cf7165b
commit
39a190f056
22 changed files with 378 additions and 2 deletions
|
|
@ -238,6 +238,8 @@ dependencies {
|
|||
implementation(projects.features.home.impl)
|
||||
implementation(projects.features.account.api)
|
||||
implementation(projects.features.account.impl)
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
implementation(projects.features.tokenRecieve.impl)
|
||||
|
||||
/** AndroidX libraries */
|
||||
implementation(deps.androidx.core.ktx)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import com.tangem.domain.tokens.operations.CachedCurrenciesStatusesOperations
|
|||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
||||
import com.tangem.domain.tokens.repository.TokenReceiveWarningsViewedRepository
|
||||
import com.tangem.domain.tokens.wallet.WalletBalanceFetcher
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.tap.domain.tokens.DefaultTokensFeatureToggles
|
||||
|
|
@ -506,4 +507,20 @@ internal object TokensDomainModule {
|
|||
fun provideGetAssetRequirementsUseCase(walletManagersFacade: WalletManagersFacade): GetAssetRequirementsUseCase {
|
||||
return GetAssetRequirementsUseCase(walletManagersFacade)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetViewedTokenReceiveWarningUseCase(
|
||||
tokenReceiveWarningsViewedRepository: TokenReceiveWarningsViewedRepository,
|
||||
): GetViewedTokenReceiveWarningUseCase {
|
||||
return GetViewedTokenReceiveWarningUseCase(tokenReceiveWarningsViewedRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSaveViewedTokenReceiveWarningUseCase(
|
||||
tokenReceiveWarningsViewedRepository: TokenReceiveWarningsViewedRepository,
|
||||
): SaveViewedTokenReceiveWarningUseCase {
|
||||
return SaveViewedTokenReceiveWarningUseCase(tokenReceiveWarningsViewedRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import com.tangem.domain.tokens.TokensFeatureToggles
|
|||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.transaction.FeeRepository
|
||||
import com.tangem.domain.transaction.TransactionRepository
|
||||
import com.tangem.domain.transaction.WalletAddressServiceRepository
|
||||
import com.tangem.domain.transaction.usecase.*
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import dagger.Module
|
||||
|
|
@ -18,6 +19,7 @@ import dagger.hilt.InstallIn
|
|||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object TransactionDomainModule {
|
||||
|
|
@ -210,4 +212,24 @@ internal object TransactionDomainModule {
|
|||
): CreateNFTTransferTransactionUseCase {
|
||||
return CreateNFTTransferTransactionUseCase(transactionRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetEnsNameUseCase(
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
walletAddressServiceRepository: WalletAddressServiceRepository,
|
||||
): GetEnsNameUseCase {
|
||||
return GetEnsNameUseCase(
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
walletAddressServiceRepository = walletAddressServiceRepository,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetReverseResolvedEnsAddressUseCase(
|
||||
walletAddressServiceRepository: WalletAddressServiceRepository,
|
||||
): GetReverseResolvedEnsAddressUseCase {
|
||||
return GetReverseResolvedEnsAddressUseCase(walletAddressServiceRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.tangem.datasource.di
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStoreFactory
|
||||
import androidx.datastore.dataStoreFile
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.datasource.local.token.DefaultTokenReceiveWarningActionStore
|
||||
import com.tangem.datasource.local.token.TokenReceiveWarningActionStore
|
||||
import com.tangem.datasource.utils.MoshiDataStoreSerializer
|
||||
import com.tangem.datasource.utils.setTypes
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object TokenReceiveWarningModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideTokenReceiveWarningStore(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
@ApplicationContext context: Context,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): TokenReceiveWarningActionStore {
|
||||
return DefaultTokenReceiveWarningActionStore(
|
||||
persistenceStore = DataStoreFactory.create(
|
||||
serializer = MoshiDataStoreSerializer(
|
||||
moshi = moshi,
|
||||
types = setTypes<String>(),
|
||||
defaultValue = emptySet(),
|
||||
),
|
||||
produceFile = { context.dataStoreFile(fileName = "token_receive_warnings_viewed") },
|
||||
scope = CoroutineScope(context = dispatchers.io + SupervisorJob()),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.datasource.local.token
|
||||
|
||||
import androidx.datastore.core.DataStore
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
|
||||
internal class DefaultTokenReceiveWarningActionStore(
|
||||
private val persistenceStore: DataStore<Set<String>>,
|
||||
) : TokenReceiveWarningActionStore {
|
||||
|
||||
override suspend fun getSync(): Set<String> {
|
||||
return persistenceStore.data.firstOrNull() ?: emptySet()
|
||||
}
|
||||
|
||||
override suspend fun store(symbol: String) {
|
||||
persistenceStore.updateData { data -> data.plus(symbol) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.datasource.local.token
|
||||
|
||||
interface TokenReceiveWarningActionStore {
|
||||
|
||||
suspend fun getSync(): Set<String>
|
||||
|
||||
suspend fun store(symbol: String)
|
||||
}
|
||||
|
|
@ -8,14 +8,17 @@ import com.tangem.data.common.currency.UserTokensSaver
|
|||
import com.tangem.data.tokens.repository.DefaultCurrenciesRepository
|
||||
import com.tangem.data.tokens.repository.DefaultCurrencyChecksRepository
|
||||
import com.tangem.data.tokens.repository.DefaultPolkadotAccountHealthCheckRepository
|
||||
import com.tangem.data.tokens.repository.DefaultTokenReceiveWarningsViewedRepository
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.exchangeservice.swap.ExpressServiceLoader
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.token.TokenReceiveWarningActionStore
|
||||
import com.tangem.datasource.local.token.UserTokensResponseStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
||||
import com.tangem.domain.tokens.repository.TokenReceiveWarningsViewedRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
|
|
@ -83,4 +86,14 @@ internal object TokensDataModule {
|
|||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideTokenReceiveWarningsViewedRepository(
|
||||
tokenReceiveWarningActionStore: TokenReceiveWarningActionStore,
|
||||
): TokenReceiveWarningsViewedRepository {
|
||||
return DefaultTokenReceiveWarningsViewedRepository(
|
||||
tokenReceiveWarningActionStore = tokenReceiveWarningActionStore,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.data.tokens.repository
|
||||
|
||||
import com.tangem.datasource.local.token.TokenReceiveWarningActionStore
|
||||
import com.tangem.domain.tokens.repository.TokenReceiveWarningsViewedRepository
|
||||
|
||||
internal class DefaultTokenReceiveWarningsViewedRepository(
|
||||
private val tokenReceiveWarningActionStore: TokenReceiveWarningActionStore,
|
||||
) : TokenReceiveWarningsViewedRepository {
|
||||
|
||||
override suspend fun getViewedWarnings(): Set<String> {
|
||||
return tokenReceiveWarningActionStore.getSync()
|
||||
}
|
||||
|
||||
override suspend fun view(symbol: String) {
|
||||
tokenReceiveWarningActionStore.store(symbol)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import com.tangem.blockchain.blockchains.near.NearWalletManager
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.NameResolver
|
||||
import com.tangem.blockchain.common.ResolveAddressResult
|
||||
import com.tangem.blockchain.common.ReverseResolveAddressResult
|
||||
import com.tangem.blockchainsdk.utils.toBlockchain
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
|
@ -22,6 +23,40 @@ class DefaultWalletAddressServiceRepository(
|
|||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : WalletAddressServiceRepository {
|
||||
|
||||
override suspend fun getEns(userWalletId: UserWalletId, network: Network, address: String): String? {
|
||||
return withContext(dispatchers.io) {
|
||||
val blockchain = network.toBlockchain()
|
||||
val walletManager = walletManagersFacade.getOrCreateWalletManager(
|
||||
userWalletId = userWalletId,
|
||||
blockchain = blockchain,
|
||||
derivationPath = network.derivationPath.value,
|
||||
)
|
||||
walletManager?.wallet?.ens
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun reverseResolveAddress(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
address: String,
|
||||
): ReverseResolveAddressResult {
|
||||
return withContext(dispatchers.io) {
|
||||
val blockchain = network.toBlockchain()
|
||||
|
||||
val walletManager = walletManagersFacade.getOrCreateWalletManager(
|
||||
userWalletId = userWalletId,
|
||||
blockchain = blockchain,
|
||||
derivationPath = network.derivationPath.value,
|
||||
)
|
||||
|
||||
if (walletManager is NameResolver) {
|
||||
walletManager.reverseResolve(address.toByteArray())
|
||||
} else {
|
||||
ReverseResolveAddressResult.NotSupported
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun resolveAddress(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.domain.models.ens
|
||||
|
||||
sealed interface EnsAddress {
|
||||
data class Address(val name: String) : EnsAddress
|
||||
data class Error(val error: Exception) : EnsAddress
|
||||
data object NotSupported : EnsAddress
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import com.tangem.domain.tokens.repository.TokenReceiveWarningsViewedRepository
|
||||
|
||||
class GetViewedTokenReceiveWarningUseCase(
|
||||
private val tokenReceiveWarningsViewedRepository: TokenReceiveWarningsViewedRepository,
|
||||
) {
|
||||
suspend operator fun invoke(): Set<String> {
|
||||
return tokenReceiveWarningsViewedRepository.getViewedWarnings()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import com.tangem.domain.tokens.repository.TokenReceiveWarningsViewedRepository
|
||||
|
||||
class SaveViewedTokenReceiveWarningUseCase(
|
||||
private val tokenReceiveWarningsViewedRepository: TokenReceiveWarningsViewedRepository,
|
||||
) {
|
||||
suspend operator fun invoke(symbol: String) {
|
||||
tokenReceiveWarningsViewedRepository.view(symbol)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.tangem.domain.tokens.repository
|
||||
|
||||
interface TokenReceiveWarningsViewedRepository {
|
||||
|
||||
suspend fun getViewedWarnings(): Set<String>
|
||||
|
||||
suspend fun view(symbol: String)
|
||||
}
|
||||
|
|
@ -1,15 +1,24 @@
|
|||
package com.tangem.domain.transaction
|
||||
|
||||
import com.tangem.blockchain.common.ResolveAddressResult
|
||||
import com.tangem.blockchain.common.ReverseResolveAddressResult
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.wallets.models.ParsedQrCode
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.wallets.models.ParsedQrCode
|
||||
|
||||
/**
|
||||
* Wallet address service repository.
|
||||
*/
|
||||
interface WalletAddressServiceRepository {
|
||||
|
||||
suspend fun getEns(userWalletId: UserWalletId, network: Network, address: String): String?
|
||||
|
||||
suspend fun reverseResolveAddress(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
address: String,
|
||||
): ReverseResolveAddressResult
|
||||
|
||||
suspend fun resolveAddress(userWalletId: UserWalletId, network: Network, address: String): ResolveAddressResult
|
||||
|
||||
suspend fun validateAddress(userWalletId: UserWalletId, network: Network, address: String): Boolean
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
package com.tangem.domain.transaction.usecase
|
||||
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.transaction.WalletAddressServiceRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
|
||||
class GetEnsNameUseCase(
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val walletAddressServiceRepository: WalletAddressServiceRepository,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(userWalletId: UserWalletId, network: Network, address: String): String? {
|
||||
if (network.nameResolvingType != Network.NameResolvingType.ENS) {
|
||||
return null
|
||||
}
|
||||
|
||||
val addresses = walletManagersFacade.getAddresses(userWalletId, network)
|
||||
|
||||
val isOwnAddress = addresses.any { it.value == address }
|
||||
if (!isOwnAddress) {
|
||||
return null
|
||||
}
|
||||
|
||||
return walletAddressServiceRepository.getEns(
|
||||
userWalletId = userWalletId,
|
||||
network = network,
|
||||
address = address,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.tangem.domain.transaction.usecase
|
||||
|
||||
import com.tangem.blockchain.common.ReverseResolveAddressResult
|
||||
import com.tangem.domain.models.ens.EnsAddress
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.transaction.WalletAddressServiceRepository
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
|
||||
class GetReverseResolvedEnsAddressUseCase(private val walletAddressServiceRepository: WalletAddressServiceRepository) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
addresses: List<String>,
|
||||
): List<EnsAddress> {
|
||||
return supervisorScope {
|
||||
val addressesDeferred = addresses.map { address ->
|
||||
async {
|
||||
val result = walletAddressServiceRepository.reverseResolveAddress(
|
||||
userWalletId = userWalletId,
|
||||
network = network,
|
||||
address = address,
|
||||
)
|
||||
mapReverseResolveResult(result)
|
||||
}
|
||||
}
|
||||
addressesDeferred.awaitAll()
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapReverseResolveResult(reverseResolveAddressResult: ReverseResolveAddressResult): EnsAddress {
|
||||
return when (reverseResolveAddressResult) {
|
||||
is ReverseResolveAddressResult.Error -> EnsAddress.Error(reverseResolveAddressResult.error)
|
||||
ReverseResolveAddressResult.NotSupported -> EnsAddress.NotSupported
|
||||
is ReverseResolveAddressResult.Resolved -> EnsAddress.Address(reverseResolveAddressResult.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
1
features/token-recieve/api/.gitignore
vendored
Normal file
1
features/token-recieve/api/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
23
features/token-recieve/api/build.gradle.kts
Normal file
23
features/token-recieve/api/build.gradle.kts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
id("kotlin-parcelize")
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.features.tokenrecieve.api"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
/** Core */
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.ui)
|
||||
|
||||
/** Common */
|
||||
implementation(projects.common.ui)
|
||||
|
||||
/** Domain */
|
||||
implementation(projects.domain.models)
|
||||
|
||||
}
|
||||
1
features/token-recieve/impl/.gitignore
vendored
Normal file
1
features/token-recieve/impl/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
55
features/token-recieve/impl/build.gradle.kts
Normal file
55
features/token-recieve/impl/build.gradle.kts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
alias(deps.plugins.kotlin.kapt)
|
||||
alias(deps.plugins.kotlin.serialization)
|
||||
alias(deps.plugins.hilt.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.features.tokenreceive.impl"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
/** Compose */
|
||||
implementation(deps.compose.foundation)
|
||||
implementation(deps.compose.material3)
|
||||
implementation(deps.compose.navigation)
|
||||
implementation(deps.compose.navigation.hilt)
|
||||
implementation(deps.compose.ui)
|
||||
implementation(deps.compose.ui.tooling)
|
||||
implementation(deps.compose.ui.utils)
|
||||
|
||||
implementation(deps.kotlin.immutable.collections)
|
||||
implementation(deps.timber)
|
||||
implementation(deps.lifecycle.compose)
|
||||
implementation(deps.kotlin.serialization)
|
||||
implementation(deps.decompose.ext.compose)
|
||||
|
||||
/** DI */
|
||||
implementation(deps.hilt.android)
|
||||
kapt(deps.hilt.kapt)
|
||||
|
||||
/** Common */
|
||||
implementation(projects.common.ui)
|
||||
|
||||
/** Core modules */
|
||||
implementation(projects.common.routing)
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.core.analytics)
|
||||
implementation(projects.core.analytics.models)
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.res)
|
||||
|
||||
/** Domain modules */
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.transaction)
|
||||
implementation(projects.domain.transaction.models)
|
||||
|
||||
/** Feature Apis */
|
||||
implementation(projects.features.tokenRecieve.api)
|
||||
}
|
||||
|
|
@ -272,6 +272,9 @@ include(":features:welcome:impl")
|
|||
|
||||
include(":features:account:api")
|
||||
include(":features:account:impl")
|
||||
|
||||
include(":features:token-recieve:api")
|
||||
include(":features:token-recieve:impl")
|
||||
// endregion Feature modules
|
||||
|
||||
// region Domain modules
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 794a8187e6d248ca3c21661df199a34ffeb0037a
|
||||
Subproject commit 428b83bb378b615209e23afa05c88c454d06a9f1
|
||||
Loading…
Add table
Add a link
Reference in a new issue