Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-12 12:00:52 +04:00
parent 1472431435
commit fdc22278e6
9 changed files with 60 additions and 8 deletions

View file

@ -5,6 +5,7 @@ import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
import com.tangem.domain.networks.single.SingleNetworkStatusSupplier
import com.tangem.domain.notifications.repository.PushNotificationsRepository
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
import com.tangem.domain.tokens.GetViewedTokenReceiveWarningUseCase
@ -56,6 +57,7 @@ internal object TransactionDomainModule {
singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
tangemHotWalletSignerFactory: TangemHotWalletSigner.Factory,
dispatchers: CoroutineDispatcherProvider,
pushNotificationsRepository: PushNotificationsRepository,
): SendTransactionUseCase {
return SendTransactionUseCase(
demoConfig = DemoConfig,
@ -65,6 +67,7 @@ internal object TransactionDomainModule {
singleNetworkStatusFetcher = singleNetworkStatusFetcher,
parallelUpdatingScope = CoroutineScope(SupervisorJob() + dispatchers.io),
getHotWalletSigner = tangemHotWalletSignerFactory::create,
pushNotificationsRepository = pushNotificationsRepository,
)
}

View file

@ -203,7 +203,7 @@ interface TangemTechApi {
* Used when yield operations generate intermediate transactions
* that should not trigger notifications.
*/
@POST("v1/transaction-events")
@POST("v2/transaction-events")
suspend fun transactionEvents(@Body name: TransactionEventBody): ApiResponse<Unit>
// region Earn

View file

@ -7,6 +7,7 @@ import com.squareup.moshi.JsonClass
data class TransactionEventBody(
@Json(name = "transactionId") val transactionId: String,
@Json(name = "operationType") val operationType: OperationType,
@Json(name = "userAddress") val userAddress: String? = null,
)
@JsonClass(generateAdapter = false)

View file

@ -15,10 +15,14 @@ import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getSyncOrNull
import com.tangem.datasource.local.preferences.utils.store
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.notifications.models.ApplicationId
import com.tangem.domain.notifications.models.NotificationsError
import com.tangem.domain.notifications.repository.PushNotificationsRepository
import com.tangem.domain.notifications.models.NotificationsEligibleNetwork
import com.tangem.datasource.local.preferences.utils.getObjectMap
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.info.AppInfoProvider
import kotlinx.coroutines.withContext
@ -96,4 +100,9 @@ internal class DefaultPushNotificationsRepository @Inject constructor(
NotificationsEligibleNetworkConverter.convert(it)
}
}
override suspend fun isNotificationsEnabled(userWalletId: UserWalletId): Boolean =
appPreferencesStore.getObjectMap<Boolean>(PreferencesKeys.NOTIFICATIONS_ENABLED_STATES_KEY)
.map { it[userWalletId.stringValue] == true }
.firstOrNull() == true
}

View file

@ -422,7 +422,11 @@ internal class DefaultTransactionRepository(
preparer.prepareAndSignMultiple(transactionData, signer)
}
override suspend fun sendTransactionHash(hash: String, transactionType: EventTransactionTypeDto) {
override suspend fun sendTransactionHash(
hash: String,
transactionType: EventTransactionTypeDto,
userAddress: String?,
) {
runCatching(dispatchers.io) {
val operationType = when (transactionType) {
EventTransactionTypeDto.DEPOSIT -> OperationType.YIELD_DEPOSIT
@ -432,6 +436,7 @@ internal class DefaultTransactionRepository(
val body = TransactionEventBody(
operationType = operationType,
transactionId = hash,
userAddress = userAddress,
)
val response = tangemTechApi.transactionEvents(body)
response.fold(

View file

@ -1,6 +1,7 @@
package com.tangem.domain.notifications.repository
import arrow.core.Either
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.notifications.models.ApplicationId
import com.tangem.domain.notifications.models.NotificationsEligibleNetwork
import com.tangem.domain.notifications.models.NotificationsError
@ -20,4 +21,6 @@ interface PushNotificationsRepository {
@Throws
suspend fun getEligibleNetworks(): List<NotificationsEligibleNetwork>
suspend fun isNotificationsEnabled(userWalletId: UserWalletId): Boolean
}

View file

@ -35,6 +35,7 @@ dependencies {
implementation(projects.domain.transaction.models)
implementation(projects.domain.demo)
implementation(projects.domain.card)
implementation(projects.domain.notifications)
api(projects.domain.networks)
testRuntimeOnly(deps.test.junit5.engine)

View file

@ -125,5 +125,5 @@ interface TransactionRepository {
network: Network,
): com.tangem.blockchain.extensions.Result<List<ByteArray>>
suspend fun sendTransactionHash(hash: String, transactionType: EventTransactionTypeDto)
suspend fun sendTransactionHash(hash: String, transactionType: EventTransactionTypeDto, userAddress: String?)
}

View file

@ -25,6 +25,7 @@ import com.tangem.domain.demo.models.DemoConfig
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
import com.tangem.domain.notifications.repository.PushNotificationsRepository
import com.tangem.domain.transaction.TransactionRepository
import com.tangem.domain.transaction.error.SendTransactionError
import com.tangem.domain.transaction.error.parseWrappedError
@ -44,6 +45,7 @@ class SendTransactionUseCase(
private val singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
private val parallelUpdatingScope: CoroutineScope,
private val getHotWalletSigner: (UserWallet.Hot) -> TransactionSigner,
private val pushNotificationsRepository: PushNotificationsRepository,
) {
suspend operator fun invoke(
txsData: List<TransactionData>,
@ -112,7 +114,11 @@ class SendTransactionUseCase(
}
.fold(
ifRight = { result ->
processSentTransactionsHashes(txsData, result.hashes)
processSentTransactionsHashes(
userWallet = userWallet,
transactions = txsData,
hashes = result.hashes,
)
result.hashes.right()
},
ifLeft = { it.left() },
@ -128,11 +134,19 @@ class SendTransactionUseCase(
.map { it.first() }
}
private fun processSentTransactionsHashes(transactions: List<TransactionData>, hashes: List<String>) {
private fun processSentTransactionsHashes(
userWallet: UserWallet,
transactions: List<TransactionData>,
hashes: List<String>,
) {
parallelUpdatingScope.launch {
withContext(NonCancellable) {
transactions.forEachIndexed { ind, tx ->
sendHashToBackendIfNeeded(tx, hashes[ind])
sendHashToBackendIfNeeded(
userWallet = userWallet,
transaction = tx,
txHash = hashes[ind],
)
}
}
}
@ -141,7 +155,11 @@ class SendTransactionUseCase(
/**
* Sends tx hash to backend for specific transaction types
*/
private suspend fun sendHashToBackendIfNeeded(transaction: TransactionData, txHash: String) {
private suspend fun sendHashToBackendIfNeeded(
userWallet: UserWallet,
transaction: TransactionData,
txHash: String,
) {
(transaction as? TransactionData.Uncompiled)?.let { tx ->
val extras = tx.extras
when (extras) {
@ -152,7 +170,19 @@ class SendTransactionUseCase(
is EthereumYieldSupplyExitCallData -> EventTransactionTypeDto.WITHDRAW
else -> return
}
transactionRepository.sendTransactionHash(txHash, txType)
val isPushNotificationEnabled = pushNotificationsRepository.isNotificationsEnabled(
userWallet.walletId,
)
val userAddress = if (isPushNotificationEnabled) {
transaction.sourceAddress
} else {
null
}
transactionRepository.sendTransactionHash(
hash = txHash,
transactionType = txType,
userAddress = userAddress,
)
}
}
}