package events import ( "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/holiman/uint256" ) // EventType represents the type of DEX event type EventType int const ( Unknown EventType = iota Swap AddLiquidity RemoveLiquidity NewPool ) // String returns a string representation of the event type func (et EventType) String() string { switch et { case Unknown: return "Unknown" case Swap: return "Swap" case AddLiquidity: return "AddLiquidity" case RemoveLiquidity: return "RemoveLiquidity" case NewPool: return "NewPool" default: return "Unknown" } } // Event represents a parsed DEX event type Event struct { Type EventType Protocol string // UniswapV2, UniswapV3, SushiSwap, etc. PoolAddress common.Address Token0 common.Address Token1 common.Address Amount0 *big.Int Amount1 *big.Int SqrtPriceX96 *uint256.Int Liquidity *uint256.Int Tick int Timestamp uint64 TransactionHash common.Hash BlockNumber uint64 } // EventParser parses DEX events from Ethereum transactions type EventParser struct { // Known DEX contract addresses UniswapV2Factory common.Address UniswapV3Factory common.Address SushiSwapFactory common.Address // Router addresses UniswapV2Router01 common.Address UniswapV2Router02 common.Address UniswapV3Router common.Address SushiSwapRouter common.Address // Known pool addresses (for quick lookup) knownPools map[common.Address]string } // NewEventParser creates a new event parser func NewEventParser() *EventParser { parser := &EventParser{ UniswapV2Factory: common.HexToAddress("0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"), UniswapV3Factory: common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984"), SushiSwapFactory: common.HexToAddress("0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac"), UniswapV2Router01: common.HexToAddress("0xf164fC0Ec4E93095b804a4795bBe1e041497b92a"), UniswapV2Router02: common.HexToAddress("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"), UniswapV3Router: common.HexToAddress("0xE592427A0AEce92De3Edee1F18E0157C05861564"), SushiSwapRouter: common.HexToAddress("0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F"), knownPools: make(map[common.Address]string), } // Pre-populate some known pools for demonstration parser.knownPools[common.HexToAddress("0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640")] = "UniswapV3" parser.knownPools[common.HexToAddress("0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc")] = "UniswapV2" return parser } // ParseTransaction parses a transaction for DEX events func (ep *EventParser) ParseTransaction(tx *types.Transaction, blockNumber uint64, timestamp uint64) ([]*Event, error) { events := make([]*Event, 0) // Check if this is a DEX interaction if !ep.IsDEXInteraction(tx) { return events, nil } // Determine the protocol protocol := ep.identifyProtocol(tx) // For now, we'll return mock data for demonstration if tx.To() != nil { event := &Event{ Type: Swap, Protocol: protocol, PoolAddress: *tx.To(), Token0: common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC Token1: common.HexToAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"), // WETH Amount0: big.NewInt(1000000000), // 1000 USDC Amount1: big.NewInt(500000000000000000), // 0.5 WETH SqrtPriceX96: uint256.NewInt(2505414483750470000), Liquidity: uint256.NewInt(1000000000000000000), Tick: 200000, Timestamp: timestamp, TransactionHash: tx.Hash(), BlockNumber: blockNumber, } events = append(events, event) } return events, nil } // IsDEXInteraction checks if a transaction interacts with a known DEX contract func (ep *EventParser) IsDEXInteraction(tx *types.Transaction) bool { if tx.To() == nil { return false } to := *tx.To() // Check factory contracts if to == ep.UniswapV2Factory || to == ep.UniswapV3Factory || to == ep.SushiSwapFactory { return true } // Check router contracts if to == ep.UniswapV2Router01 || to == ep.UniswapV2Router02 || to == ep.UniswapV3Router || to == ep.SushiSwapRouter { return true } // Check known pools if _, exists := ep.knownPools[to]; exists { return true } return false } // identifyProtocol identifies which DEX protocol a transaction is interacting with func (ep *EventParser) identifyProtocol(tx *types.Transaction) string { if tx.To() == nil { return "Unknown" } to := *tx.To() // Check factory contracts if to == ep.UniswapV2Factory { return "UniswapV2" } if to == ep.UniswapV3Factory { return "UniswapV3" } if to == ep.SushiSwapFactory { return "SushiSwap" } // Check router contracts if to == ep.UniswapV2Router01 || to == ep.UniswapV2Router02 { return "UniswapV2" } if to == ep.UniswapV3Router { return "UniswapV3" } if to == ep.SushiSwapRouter { return "SushiSwap" } // Check known pools if protocol, exists := ep.knownPools[to]; exists { return protocol } // Try to identify from function signature in transaction data if len(tx.Data()) >= 4 { sig := common.Bytes2Hex(tx.Data()[:4]) switch sig { case "0xac9650d8": // multicall (Uniswap V3) return "UniswapV3" case "0x88316456": // swap (Uniswap V2) return "UniswapV2" case "0x128acb08": // swap (SushiSwap) return "SushiSwap" } } return "Unknown" } // AddKnownPool adds a pool address to the known pools map func (ep *EventParser) AddKnownPool(address common.Address, protocol string) { ep.knownPools[address] = protocol } // GetKnownPools returns all known pools func (ep *EventParser) GetKnownPools() map[common.Address]string { return ep.knownPools }