feat: add pool cache adapter and strict event validation

- Created PoolCacheAdapter to wrap PoolDiscovery for EventParser
- Updated ArbitrumMonitor to pass pool cache to parser via NewEventParserFull
- Added strict validation to reject events with zero addresses
- Added strict validation to reject events with zero amounts
- Parser now uses discovered pools from cache for token enrichment

This ensures zero addresses and zero amounts NEVER reach the scanner.
Events with invalid data are logged and rejected at the monitor level.

Changes:
- pkg/pools/pool_cache_adapter.go: New adapter implementing PoolCache interface
- pkg/monitor/concurrent.go: Pool cache integration and validation logic

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Administrator
2025-11-10 10:03:28 +01:00
parent e02ded0a6a
commit e79e0d960d
2 changed files with 158 additions and 18 deletions

View File

@@ -0,0 +1,92 @@
package pools
import (
"github.com/ethereum/go-ethereum/common"
arbcommon "github.com/fraktal/mev-beta/pkg/arbitrum/common"
)
// PoolCacheAdapter adapts PoolDiscovery to implement interfaces.PoolCache
// This allows the EventParser to use PoolDiscovery as its pool cache
type PoolCacheAdapter struct {
discovery *PoolDiscovery
}
// NewPoolCacheAdapter creates a new adapter wrapping a PoolDiscovery
func NewPoolCacheAdapter(discovery *PoolDiscovery) *PoolCacheAdapter {
return &PoolCacheAdapter{
discovery: discovery,
}
}
// GetPool retrieves pool information from cache
func (a *PoolCacheAdapter) GetPool(address common.Address) *arbcommon.PoolInfo {
if a.discovery == nil {
return nil
}
// Get pool from discovery
pool, exists := a.discovery.GetPool(address.Hex())
if !exists || pool == nil {
return nil
}
// Convert Pool to PoolInfo
return &arbcommon.PoolInfo{
Address: common.HexToAddress(pool.Address),
Protocol: parseProtocol(pool.Protocol),
PoolType: parsePoolType(pool.Protocol),
FactoryAddress: common.HexToAddress(pool.Factory),
Token0: common.HexToAddress(pool.Token0),
Token1: common.HexToAddress(pool.Token1),
Fee: pool.Fee,
TotalLiquidity: pool.Liquidity,
}
}
// GetPoolsByTokenPair retrieves pools for a specific token pair
func (a *PoolCacheAdapter) GetPoolsByTokenPair(token0, token1 common.Address) []*arbcommon.PoolInfo {
if a.discovery == nil {
return nil
}
// PoolDiscovery doesn't have a direct method for this yet
// We'll return nil for now and implement this later if needed
// This is acceptable as the parser only uses GetPool currently
return nil
}
// parseProtocol converts protocol string to Protocol enum
func parseProtocol(protocol string) arbcommon.Protocol {
switch protocol {
case "uniswap-v2":
return arbcommon.ProtocolUniswapV2
case "uniswap-v3":
return arbcommon.ProtocolUniswapV3
case "sushiswap":
return arbcommon.ProtocolSushiSwap
case "camelot":
return arbcommon.ProtocolCamelot
case "curve":
return arbcommon.ProtocolCurve
case "balancer":
return arbcommon.ProtocolBalancer
default:
return arbcommon.ProtocolUnknown
}
}
// parsePoolType converts protocol string to PoolType enum
func parsePoolType(protocol string) arbcommon.PoolType {
switch protocol {
case "uniswap-v2", "sushiswap", "camelot":
return arbcommon.PoolTypeV2
case "uniswap-v3":
return arbcommon.PoolTypeV3
case "curve":
return arbcommon.PoolTypeStableSwap
case "balancer":
return arbcommon.PoolTypeWeighted
default:
return arbcommon.PoolTypeUnknown
}
}