diff --git a/data/blockaid/src/main/kotlin/com/tangem/data/blockaid/BlockAidMapper.kt b/data/blockaid/src/main/kotlin/com/tangem/data/blockaid/BlockAidMapper.kt index a36dea8518..3b31a9b9a7 100644 --- a/data/blockaid/src/main/kotlin/com/tangem/data/blockaid/BlockAidMapper.kt +++ b/data/blockaid/src/main/kotlin/com/tangem/data/blockaid/BlockAidMapper.kt @@ -15,7 +15,7 @@ private const val SUCCESS_STATUS = "Success" private const val DOMAIN_CHECKED_STATUS = "hit" private const val VALIDATION_SAFE_STATUS = "Benign" -internal class BlockAidMapper { +internal object BlockAidMapper { fun mapToDomain(from: DomainScanResponse): CheckDAppResult { return when { diff --git a/data/blockaid/src/main/kotlin/com/tangem/data/blockaid/DefaultBlockAidRepository.kt b/data/blockaid/src/main/kotlin/com/tangem/data/blockaid/DefaultBlockAidRepository.kt index 8659672ffe..66483ed2df 100644 --- a/data/blockaid/src/main/kotlin/com/tangem/data/blockaid/DefaultBlockAidRepository.kt +++ b/data/blockaid/src/main/kotlin/com/tangem/data/blockaid/DefaultBlockAidRepository.kt @@ -12,19 +12,19 @@ import kotlinx.coroutines.withContext internal class DefaultBlockAidRepository( private val api: BlockAidApi, - private val dispatcherProvider: CoroutineDispatcherProvider, + private val dispatchers: CoroutineDispatcherProvider, private val mapper: BlockAidMapper, ) : BlockAidRepository { override suspend fun verifyDAppDomain(data: DAppData): CheckDAppResult { - val response = withContext(dispatcherProvider.io) { + val response = withContext(dispatchers.io) { api.scanDomain(DomainScanRequest(data.url)) } return mapper.mapToDomain(response) } override suspend fun verifyTransaction(data: TransactionData): CheckTransactionResult { - val response = withContext(dispatcherProvider.io) { + val response = withContext(dispatchers.io) { when (data.params) { is TransactionParams.Evm -> { api.scanJsonRpc(mapper.mapToEvmRequest(data)) diff --git a/data/blockaid/src/main/kotlin/com/tangem/data/blockaid/di/BlockAidDataInternalModule.kt b/data/blockaid/src/main/kotlin/com/tangem/data/blockaid/di/BlockAidDataInternalModule.kt index 4f4ff71605..1ca90326c6 100644 --- a/data/blockaid/src/main/kotlin/com/tangem/data/blockaid/di/BlockAidDataInternalModule.kt +++ b/data/blockaid/src/main/kotlin/com/tangem/data/blockaid/di/BlockAidDataInternalModule.kt @@ -17,11 +17,11 @@ internal object BlockAidDataInternalModule { @Provides @Singleton - fun provideRepository(api: BlockAidApi, dispatcherProvider: CoroutineDispatcherProvider): BlockAidRepository { + fun provideRepository(api: BlockAidApi, dispatchers: CoroutineDispatcherProvider): BlockAidRepository { return DefaultBlockAidRepository( api = api, - dispatcherProvider = dispatcherProvider, - mapper = BlockAidMapper(), + dispatchers = dispatchers, + mapper = BlockAidMapper, ) } } \ No newline at end of file diff --git a/data/blockaid/src/test/kotlin/com/tangem/data/blockaid/BlockAidMapperTest.kt b/data/blockaid/src/test/kotlin/com/tangem/data/blockaid/BlockAidMapperTest.kt index faaba4926c..175cc033b9 100644 --- a/data/blockaid/src/test/kotlin/com/tangem/data/blockaid/BlockAidMapperTest.kt +++ b/data/blockaid/src/test/kotlin/com/tangem/data/blockaid/BlockAidMapperTest.kt @@ -11,7 +11,7 @@ import java.math.BigDecimal class BlockAidMapperTest { - private val mapper = BlockAidMapper() + private val mapper = BlockAidMapper @Test fun `when status hit and is malicious false then map to domain returns safe`() { diff --git a/data/blockaid/src/test/kotlin/com/tangem/data/blockaid/DefaultBlockAidRepositoryTest.kt b/data/blockaid/src/test/kotlin/com/tangem/data/blockaid/DefaultBlockAidRepositoryTest.kt index 036ed43815..d125246bce 100644 --- a/data/blockaid/src/test/kotlin/com/tangem/data/blockaid/DefaultBlockAidRepositoryTest.kt +++ b/data/blockaid/src/test/kotlin/com/tangem/data/blockaid/DefaultBlockAidRepositoryTest.kt @@ -29,12 +29,12 @@ class DefaultBlockAidRepositoryTest { private lateinit var repository: DefaultBlockAidRepository - private val testDispatcherProvider = TestingCoroutineDispatcherProvider() + private val dispatchers = TestingCoroutineDispatcherProvider() @Before fun setup() { MockKAnnotations.init(this) - repository = DefaultBlockAidRepository(api, testDispatcherProvider, mapper) + repository = DefaultBlockAidRepository(api, dispatchers, mapper) } @Test diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/BlockAidEthereumVerificationDelegate.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/BlockAidEthereumVerificationDelegate.kt new file mode 100644 index 0000000000..ba45ffbdcd --- /dev/null +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/BlockAidEthereumVerificationDelegate.kt @@ -0,0 +1,50 @@ +package com.tangem.data.walletconnect.network.ethereum + +import com.domain.blockaid.models.transaction.CheckTransactionResult +import com.domain.blockaid.models.transaction.TransactionData +import com.domain.blockaid.models.transaction.TransactionParams +import com.tangem.domain.blockaid.BlockAidVerifier +import com.tangem.domain.core.lce.Lce +import com.tangem.domain.tokens.model.Network +import com.tangem.domain.walletconnect.model.WcEthMethod +import com.tangem.domain.walletconnect.model.WcSession +import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import timber.log.Timber +import javax.inject.Inject + +internal class BlockAidEthereumVerificationDelegate @Inject constructor( + private val blockAidVerifier: BlockAidVerifier, +) { + + fun getSecurityStatus( + network: Network, + method: WcEthMethod, + rawSdkRequest: WcSdkSessionRequest, + session: WcSession, + ): Flow> = flow { + emit(Lce.Loading(partialContent = null)) + blockAidVerifier.verifyTransaction( + TransactionData( + chain = network.name, + accountAddress = when (method) { + is WcEthMethod.MessageSign -> method.account + is WcEthMethod.SendTransaction -> method.transaction.from + is WcEthMethod.SignTransaction -> method.transaction.from + }, + method = rawSdkRequest.request.method, + domainUrl = session.sdkModel.appMetaData.url, + params = TransactionParams.Evm(rawSdkRequest.request.params), + ), + ).fold( + ifLeft = { + Timber.e("Failed to verify transaction: ${it.localizedMessage}") + emit(Lce.Error(it)) + }, + ifRight = { + emit(Lce.Content(it)) + }, + ) + } +} \ No newline at end of file diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthMessageSignUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthMessageSignUseCase.kt index bbbd62d234..ed0c48b91b 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthMessageSignUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthMessageSignUseCase.kt @@ -30,9 +30,12 @@ internal class DefaultWcEthMessageSignUseCase @AssistedInject constructor( @Assisted private val method: WcEthMethod.MessageSign, private val walletManagersFacade: WalletManagersFacade, private val signUseCase: SignUseCase, + blockAidDelegate: BlockAidEthereumVerificationDelegate, ) : BaseWcSignUseCase(), WcEthMessageSignUseCase { + override val securityStatus = blockAidDelegate.getSecurityStatus(network, method, rawSdkRequest, session) + override suspend fun SignCollector.onSign( state: WcSignState, ) { diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSendTransactionUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSendTransactionUseCase.kt index c923e955fd..00f485605d 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSendTransactionUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSendTransactionUseCase.kt @@ -25,9 +25,12 @@ internal class DefaultWcEthSendTransactionUseCase @AssistedInject constructor( @Assisted private val method: WcEthMethod.SendTransaction, override val respondService: WcRespondService, private val sendTransaction: SendTransactionUseCase, + blockAidDelegate: BlockAidEthereumVerificationDelegate, ) : BaseWcSignUseCase(), WcEthSendTransactionUseCase { + override val securityStatus = blockAidDelegate.getSecurityStatus(network, method, rawSdkRequest, session) + private val converter = EthTransactionParamsConverter(context) override suspend fun SignCollector.onSign(state: WcSignState) { diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSignTransactionUseCase.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSignTransactionUseCase.kt index 70b1c7b3a3..a4ad2df2a1 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSignTransactionUseCase.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/DefaultWcEthSignTransactionUseCase.kt @@ -27,9 +27,12 @@ internal class DefaultWcEthSignTransactionUseCase @AssistedInject constructor( private val prepareForSend: PrepareForSendUseCase, @Assisted override val context: WcMethodUseCaseContext, @Assisted private val method: WcEthMethod.SignTransaction, + blockAidDelegate: BlockAidEthereumVerificationDelegate, ) : BaseWcSignUseCase(), WcEthSignTransactionUseCase { + override val securityStatus = blockAidDelegate.getSecurityStatus(network, method, rawSdkRequest, session) + private val converter = EthTransactionParamsConverter(context) override suspend fun SignCollector.onSign(state: WcSignState) { diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthNetwork.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthNetwork.kt index 171bb54185..4f05896657 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthNetwork.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/network/ethereum/WcEthNetwork.kt @@ -18,7 +18,7 @@ import com.tangem.domain.walletconnect.usecase.WcMethodUseCase import com.tangem.domain.wallets.models.UserWallet import jakarta.inject.Inject -internal class WcEthNetwork constructor( +internal class WcEthNetwork( private val moshi: Moshi, private val excludedBlockchains: ExcludedBlockchains, private val sessionsManager: WcSessionsManager, @@ -34,7 +34,6 @@ internal class WcEthNetwork constructor( val session = sessionsManager.findSessionByTopic(request.topic) ?: return null val network = toNetwork(request.chainId.orEmpty(), session.wallet) ?: return null val context = WcMethodUseCaseContext(session = session, rawSdkRequest = request, network = network) - return when (method) { is WcEthMethod.MessageSign -> factories.messageSign.create(context, method) is WcEthMethod.SendTransaction -> factories.sendTransaction.create(context, method) diff --git a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/blockaid/WcBlockAidEligibleTransactionUseCase.kt b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/blockaid/WcBlockAidEligibleTransactionUseCase.kt new file mode 100644 index 0000000000..8cf1497baf --- /dev/null +++ b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/blockaid/WcBlockAidEligibleTransactionUseCase.kt @@ -0,0 +1,10 @@ +package com.tangem.domain.walletconnect.usecase.blockaid + +import com.domain.blockaid.models.transaction.CheckTransactionResult +import com.tangem.domain.core.lce.Lce +import kotlinx.coroutines.flow.Flow + +interface WcBlockAidEligibleTransactionUseCase { + + val securityStatus: Flow> +} \ No newline at end of file diff --git a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/ethereum/WcEthMessageSignUseCase.kt b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/ethereum/WcEthMessageSignUseCase.kt index 0895241c36..c2ab17f065 100644 --- a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/ethereum/WcEthMessageSignUseCase.kt +++ b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/ethereum/WcEthMessageSignUseCase.kt @@ -1,10 +1,12 @@ package com.tangem.domain.walletconnect.usecase.ethereum +import com.tangem.domain.walletconnect.usecase.blockaid.WcBlockAidEligibleTransactionUseCase import com.tangem.domain.walletconnect.usecase.sign.WcSignUseCase interface WcEthMessageSignUseCase : WcSignUseCase, - WcSignUseCase.SimpleRun { + WcSignUseCase.SimpleRun, + WcBlockAidEligibleTransactionUseCase { data class SignModel( val humanMsg: String, diff --git a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/ethereum/WcEthTransactionUseCase.kt b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/ethereum/WcEthTransactionUseCase.kt index 48f74153de..406abcdaba 100644 --- a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/ethereum/WcEthTransactionUseCase.kt +++ b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/usecase/ethereum/WcEthTransactionUseCase.kt @@ -6,11 +6,13 @@ import com.tangem.domain.tokens.model.Network import com.tangem.domain.walletconnect.model.WcSession import com.tangem.domain.walletconnect.model.sdkcopy.WcSdkSessionRequest import com.tangem.domain.walletconnect.usecase.WcMutableFee +import com.tangem.domain.walletconnect.usecase.blockaid.WcBlockAidEligibleTransactionUseCase import com.tangem.domain.walletconnect.usecase.sign.WcSignUseCase interface WcEthSendTransactionUseCase : WcSignUseCase, WcSignUseCase.SimpleRun, + WcBlockAidEligibleTransactionUseCase, WcMutableFee { override val session: WcSession @@ -25,6 +27,7 @@ interface WcEthSendTransactionUseCase : interface WcEthSignTransactionUseCase : WcSignUseCase, WcSignUseCase.SimpleRun, + WcBlockAidEligibleTransactionUseCase, WcMutableFee { override val session: WcSession