// Package types defines core data types for MEV Bot V2 package types import ( "math/big" "time" "github.com/ethereum/go-ethereum/common" ) // ProtocolType identifies the DEX protocol type ProtocolType string const ( ProtocolUniswapV2 ProtocolType = "uniswap-v2" ProtocolUniswapV3 ProtocolType = "uniswap-v3" ProtocolUniswapV4 ProtocolType = "uniswap-v4" ProtocolCurve ProtocolType = "curve" ProtocolBalancerV2 ProtocolType = "balancer-v2" ProtocolBalancerV3 ProtocolType = "balancer-v3" ProtocolKyberClassic ProtocolType = "kyber-classic" ProtocolKyberElastic ProtocolType = "kyber-elastic" ProtocolCamelotV2 ProtocolType = "camelot-v2" ProtocolCamelotV3AlgebraV1 ProtocolType = "camelot-v3-algebra-v1" ProtocolCamelotV3AlgebraV19 ProtocolType = "camelot-v3-algebra-v1.9" ProtocolCamelotV3AlgebraIntegral ProtocolType = "camelot-v3-algebra-integral" ProtocolCamelotV3AlgebraDirectional ProtocolType = "camelot-v3-algebra-directional" ProtocolUnknown ProtocolType = "unknown" ) // SwapEvent represents a parsed swap event from any protocol type SwapEvent struct { // Event metadata TxHash common.Hash BlockNumber uint64 LogIndex uint Timestamp time.Time // Pool information PoolAddress common.Address Protocol ProtocolType // Token information Token0 common.Address Token1 common.Address Token0Decimals uint8 Token1Decimals uint8 // Swap amounts (scaled to 18 decimals internally) Amount0In *big.Int Amount1In *big.Int Amount0Out *big.Int Amount1Out *big.Int // Additional protocol-specific data Fee *big.Int // Fee amount (if applicable) SqrtPriceX96 *big.Int // UniswapV3/Camelot V3 price Liquidity *big.Int // Current liquidity Tick *int32 // UniswapV3/Camelot V3 tick // Sender and recipient Sender common.Address Recipient common.Address } // Validate checks if the swap event is valid func (s *SwapEvent) Validate() error { if s.TxHash == (common.Hash{}) { return ErrInvalidTxHash } if s.PoolAddress == (common.Address{}) { return ErrInvalidPoolAddress } if s.Token0 == (common.Address{}) { return ErrInvalidToken0Address } if s.Token1 == (common.Address{}) { return ErrInvalidToken1Address } if s.Protocol == ProtocolUnknown { return ErrUnknownProtocol } // At least one amount should be non-zero if isZero(s.Amount0In) && isZero(s.Amount1In) && isZero(s.Amount0Out) && isZero(s.Amount1Out) { return ErrZeroAmounts } return nil } // GetInputToken returns the token being swapped in func (s *SwapEvent) GetInputToken() (common.Address, *big.Int) { if !isZero(s.Amount0In) { return s.Token0, s.Amount0In } return s.Token1, s.Amount1In } // GetOutputToken returns the token being swapped out func (s *SwapEvent) GetOutputToken() (common.Address, *big.Int) { if !isZero(s.Amount0Out) { return s.Token0, s.Amount0Out } return s.Token1, s.Amount1Out } // isZero checks if a big.Int is nil or zero func isZero(n *big.Int) bool { return n == nil || n.Sign() == 0 }