Skip to content

Commit

Permalink
Improve transaction spam filter
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelekol committed Oct 18, 2023
1 parent 3efdba5 commit 5f04591
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 26 deletions.
4 changes: 4 additions & 0 deletions app/src/main/java/io/horizontalsystems/bankwallet/core/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import io.horizontalsystems.bankwallet.core.managers.RestoreSettingsManager
import io.horizontalsystems.bankwallet.core.managers.SolanaKitManager
import io.horizontalsystems.bankwallet.core.managers.SolanaRpcSourceManager
import io.horizontalsystems.bankwallet.core.managers.SolanaWalletManager
import io.horizontalsystems.bankwallet.core.managers.SpamManager
import io.horizontalsystems.bankwallet.core.managers.SubscriptionManager
import io.horizontalsystems.bankwallet.core.managers.SystemInfoManager
import io.horizontalsystems.bankwallet.core.managers.TermsManager
Expand Down Expand Up @@ -191,6 +192,7 @@ class App : CoreApp(), WorkConfiguration.Provider, ImageLoaderFactory {
lateinit var cexAssetManager: CexAssetManager
lateinit var chartIndicatorManager: ChartIndicatorManager
lateinit var backupProvider: BackupProvider
lateinit var spamManager: SpamManager
}

override fun onCreate() {
Expand Down Expand Up @@ -438,6 +440,8 @@ class App : CoreApp(), WorkConfiguration.Provider, ImageLoaderFactory {
contactsRepository = contactsRepository
)

spamManager = SpamManager(marketKit)

startTasks()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class Eip20Adapter(
evmLabelManager: EvmLabelManager
) : BaseEvmAdapter(evmKitWrapper, wallet.decimal, coinManager) {

private val transactionConverter = EvmTransactionConverter(coinManager, evmKitWrapper, wallet.transactionSource, baseToken, evmLabelManager)
private val transactionConverter = EvmTransactionConverter(coinManager, evmKitWrapper, wallet.transactionSource, App.spamManager, baseToken, evmLabelManager)

private val contractAddress: Address = Address(contractAddress)
val eip20Kit: Erc20Kit = Erc20Kit.getInstance(context, this.evmKit, this.contractAddress)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.horizontalsystems.bankwallet.core.adapters
import io.horizontalsystems.bankwallet.core.ICoinManager
import io.horizontalsystems.bankwallet.core.managers.EvmKitWrapper
import io.horizontalsystems.bankwallet.core.managers.EvmLabelManager
import io.horizontalsystems.bankwallet.core.managers.SpamManager
import io.horizontalsystems.bankwallet.core.tokenIconPlaceholder
import io.horizontalsystems.bankwallet.entities.TransactionValue
import io.horizontalsystems.bankwallet.entities.nft.NftUid
Expand Down Expand Up @@ -49,6 +50,7 @@ class EvmTransactionConverter(
private val coinManager: ICoinManager,
private val evmKitWrapper: EvmKitWrapper,
private val source: TransactionSource,
private val spamManager: SpamManager,
private val baseToken: Token,
private val evmLabelManager: EvmLabelManager
) {
Expand Down Expand Up @@ -184,7 +186,7 @@ class EvmTransactionConverter(
}
transaction.from != address && transaction.to != address -> {
ExternalContractCallTransactionRecord(
transaction, baseToken, source,
transaction, baseToken, source, spamManager,
getInternalEvents(internalTransactions) +
getIncomingEip20Events(incomingEip20Transfers) +
getIncomingEip721Events(incomingEip721Transfers) +
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.horizontalsystems.bankwallet.core.adapters

import io.horizontalsystems.bankwallet.core.AdapterState
import io.horizontalsystems.bankwallet.core.App
import io.horizontalsystems.bankwallet.core.ICoinManager
import io.horizontalsystems.bankwallet.core.ITransactionsAdapter
import io.horizontalsystems.bankwallet.core.managers.EvmKitWrapper
Expand All @@ -27,7 +28,7 @@ class EvmTransactionsAdapter(
) : ITransactionsAdapter {

private val evmKit = evmKitWrapper.evmKit
private val transactionConverter = EvmTransactionConverter(coinManager, evmKitWrapper, source, baseToken, evmLabelManager)
private val transactionConverter = EvmTransactionConverter(coinManager, evmKitWrapper, source, App.spamManager, baseToken, evmLabelManager)

override val explorerTitle: String
get() = evmTransactionSource.name
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.horizontalsystems.bankwallet.core.adapters

import io.horizontalsystems.bankwallet.core.App
import io.horizontalsystems.bankwallet.core.ICoinManager
import io.horizontalsystems.bankwallet.core.managers.EvmLabelManager
import io.horizontalsystems.bankwallet.core.managers.TronKitWrapper
Expand Down Expand Up @@ -121,7 +122,7 @@ class TronTransactionConverter(

decoration.fromAddress != address && decoration.toAddress != address -> {
TronExternalContractCallTransactionRecord(
transaction, baseToken, source,
transaction, baseToken, source, App.spamManager,
getInternalEvents(internalTransactions) +
getIncomingEip20Events(incomingEip20Transfers),
getOutgoingEip20Events(outgoingEip20Transfers)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package io.horizontalsystems.bankwallet.core.managers

import io.horizontalsystems.bankwallet.entities.TransactionValue
import io.horizontalsystems.bankwallet.entities.transactionrecords.evm.TransferEvent
import java.math.BigDecimal

class SpamManager(
private val marketKitWrapper: MarketKitWrapper
) {
private val negligibleValue = BigDecimal("0.01")
private var cachedUsdPrices = mutableMapOf<String, BigDecimal?>()

fun isSpam(
incomingEvents: List<TransferEvent>,
outgoingEvents: List<TransferEvent>
): Boolean {
val allEvents = incomingEvents + outgoingEvents
return allEvents.all { spamEvent(it) }
}

private fun spamEvent(event: TransferEvent): Boolean {
return when (val eventValue = event.value) {
is TransactionValue.CoinValue -> {
spamValue(eventValue.coinUid, eventValue.value)
}

is TransactionValue.NftValue -> {
spamValue(eventValue.coinUid, eventValue.value)
}

else -> true
}
}

private fun spamValue(coinUid: String, value: BigDecimal): Boolean {
return cachedUsdPrice(coinUid)?.let { usdPrice ->
usdPrice * value < negligibleValue
} ?: run {
value <= BigDecimal.ZERO
}
}

private fun cachedUsdPrice(coinUid: String): BigDecimal? {
return cachedUsdPrices.getOrPut(coinUid) {
marketKitWrapper.coinPrice(coinUid, "USD")?.value
}
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
package io.horizontalsystems.bankwallet.entities.transactionrecords.evm

import io.horizontalsystems.bankwallet.core.managers.SpamManager
import io.horizontalsystems.bankwallet.entities.TransactionValue
import io.horizontalsystems.bankwallet.modules.transactions.TransactionSource
import io.horizontalsystems.ethereumkit.models.Transaction
import io.horizontalsystems.marketkit.models.Token
import java.math.BigDecimal

class ExternalContractCallTransactionRecord(
transaction: Transaction,
baseToken: Token,
source: TransactionSource,
spamManager: SpamManager,
val incomingEvents: List<TransferEvent>,
val outgoingEvents: List<TransferEvent>
) : EvmTransactionRecord(
transaction = transaction,
baseToken = baseToken,
source = source,
foreignTransaction = true,
spam = isSpam(incomingEvents, outgoingEvents)
spam = spamManager.isSpam(incomingEvents, outgoingEvents)
) {

override val mainValue: TransactionValue?
Expand All @@ -30,22 +31,4 @@ class ExternalContractCallTransactionRecord(
else -> null
}
}

companion object {
fun isSpam(
incomingEvents: List<TransferEvent>,
outgoingEvents: List<TransferEvent>
): Boolean {
for (event in (incomingEvents + outgoingEvents)) {
val value = event.value
if (
value is TransactionValue.CoinValue && value.value > BigDecimal.ZERO ||
value is TransactionValue.NftValue && value.value > BigDecimal.ZERO
) {
return false
}
}
return true
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package io.horizontalsystems.bankwallet.entities.transactionrecords.tron

import io.horizontalsystems.bankwallet.core.managers.SpamManager
import io.horizontalsystems.bankwallet.entities.TransactionValue
import io.horizontalsystems.bankwallet.entities.transactionrecords.evm.EvmTransactionRecord
import io.horizontalsystems.bankwallet.entities.transactionrecords.evm.ExternalContractCallTransactionRecord
import io.horizontalsystems.bankwallet.entities.transactionrecords.evm.TransferEvent
import io.horizontalsystems.bankwallet.modules.transactions.TransactionSource
import io.horizontalsystems.marketkit.models.Token
Expand All @@ -12,14 +12,15 @@ class TronExternalContractCallTransactionRecord(
transaction: Transaction,
baseToken: Token,
source: TransactionSource,
spamManager: SpamManager,
val incomingEvents: List<TransferEvent>,
val outgoingEvents: List<TransferEvent>
) : TronTransactionRecord(
transaction = transaction,
baseToken = baseToken,
source = source,
foreignTransaction = true,
spam = ExternalContractCallTransactionRecord.isSpam(incomingEvents, outgoingEvents)
spam = spamManager.isSpam(incomingEvents, outgoingEvents)
) {

override val mainValue: TransactionValue?
Expand Down

0 comments on commit 5f04591

Please sign in to comment.