Files
mev-beta/orig/internal/contracts/signature_validator.go
Administrator 803de231ba feat: create v2-prep branch with comprehensive planning
Restructured project for V2 refactor:

**Structure Changes:**
- Moved all V1 code to orig/ folder (preserved with git mv)
- Created docs/planning/ directory
- Added orig/README_V1.md explaining V1 preservation

**Planning Documents:**
- 00_V2_MASTER_PLAN.md: Complete architecture overview
  - Executive summary of critical V1 issues
  - High-level component architecture diagrams
  - 5-phase implementation roadmap
  - Success metrics and risk mitigation

- 07_TASK_BREAKDOWN.md: Atomic task breakdown
  - 99+ hours of detailed tasks
  - Every task < 2 hours (atomic)
  - Clear dependencies and success criteria
  - Organized by implementation phase

**V2 Key Improvements:**
- Per-exchange parsers (factory pattern)
- Multi-layer strict validation
- Multi-index pool cache
- Background validation pipeline
- Comprehensive observability

**Critical Issues Addressed:**
- Zero address tokens (strict validation + cache enrichment)
- Parsing accuracy (protocol-specific parsers)
- No audit trail (background validation channel)
- Inefficient lookups (multi-index cache)
- Stats disconnection (event-driven metrics)

Next Steps:
1. Review planning documents
2. Begin Phase 1: Foundation (P1-001 through P1-010)
3. Implement parsers in Phase 2
4. Build cache system in Phase 3
5. Add validation pipeline in Phase 4
6. Migrate and test in Phase 5

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 10:14:26 +01:00

240 lines
7.6 KiB
Go

package contracts
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/fraktal/mev-beta/internal/logger"
)
// FunctionSignature represents a known function signature
type FunctionSignature struct {
Name string
Selector []byte
AllowedTypes []ContractType
}
// SignatureValidator validates function calls against contract types
type SignatureValidator struct {
detector *ContractDetector
logger *logger.Logger
signatures map[string]*FunctionSignature
}
// NewSignatureValidator creates a new function signature validator
func NewSignatureValidator(detector *ContractDetector, logger *logger.Logger) *SignatureValidator {
sv := &SignatureValidator{
detector: detector,
logger: logger,
signatures: make(map[string]*FunctionSignature),
}
// Initialize known function signatures
sv.initializeSignatures()
return sv
}
// initializeSignatures initializes the known function signatures and their allowed contract types
func (sv *SignatureValidator) initializeSignatures() {
// ERC-20 token functions
sv.signatures["name()"] = &FunctionSignature{
Name: "name()",
Selector: []byte{0x06, 0xfd, 0xde, 0x03},
AllowedTypes: []ContractType{ContractTypeERC20Token},
}
sv.signatures["symbol()"] = &FunctionSignature{
Name: "symbol()",
Selector: []byte{0x95, 0xd8, 0x9b, 0x41},
AllowedTypes: []ContractType{ContractTypeERC20Token},
}
sv.signatures["decimals()"] = &FunctionSignature{
Name: "decimals()",
Selector: []byte{0x31, 0x3c, 0xe5, 0x67},
AllowedTypes: []ContractType{ContractTypeERC20Token},
}
sv.signatures["totalSupply()"] = &FunctionSignature{
Name: "totalSupply()",
Selector: []byte{0x18, 0x16, 0x0d, 0xdd},
AllowedTypes: []ContractType{ContractTypeERC20Token},
}
sv.signatures["balanceOf()"] = &FunctionSignature{
Name: "balanceOf()",
Selector: []byte{0x70, 0xa0, 0x82, 0x31},
AllowedTypes: []ContractType{ContractTypeERC20Token},
}
// Uniswap V2 Pool functions
sv.signatures["token0()"] = &FunctionSignature{
Name: "token0()",
Selector: []byte{0x0d, 0xfe, 0x16, 0x81},
AllowedTypes: []ContractType{
ContractTypeUniswapV2Pool,
ContractTypeUniswapV3Pool,
},
}
sv.signatures["token1()"] = &FunctionSignature{
Name: "token1()",
Selector: []byte{0xd2, 0x12, 0x20, 0xa7},
AllowedTypes: []ContractType{
ContractTypeUniswapV2Pool,
ContractTypeUniswapV3Pool,
},
}
sv.signatures["getReserves()"] = &FunctionSignature{
Name: "getReserves()",
Selector: []byte{0x09, 0x02, 0xf1, 0xac},
AllowedTypes: []ContractType{ContractTypeUniswapV2Pool},
}
// Uniswap V3 Pool specific functions
sv.signatures["slot0()"] = &FunctionSignature{
Name: "slot0()",
Selector: []byte{0x38, 0x50, 0xc7, 0xbd},
AllowedTypes: []ContractType{ContractTypeUniswapV3Pool},
}
sv.signatures["fee()"] = &FunctionSignature{
Name: "fee()",
Selector: []byte{0xdd, 0xca, 0x3f, 0x43},
AllowedTypes: []ContractType{ContractTypeUniswapV3Pool},
}
sv.signatures["liquidity()"] = &FunctionSignature{
Name: "liquidity()",
Selector: []byte{0x1a, 0x68, 0x65, 0x0f},
AllowedTypes: []ContractType{ContractTypeUniswapV3Pool},
}
sv.signatures["tickSpacing()"] = &FunctionSignature{
Name: "tickSpacing()",
Selector: []byte{0xd0, 0xc9, 0x32, 0x07},
AllowedTypes: []ContractType{ContractTypeUniswapV3Pool},
}
// Router functions
sv.signatures["WETH()"] = &FunctionSignature{
Name: "WETH()",
Selector: []byte{0xad, 0x5c, 0x46, 0x48},
AllowedTypes: []ContractType{
ContractTypeUniswapV2Router,
ContractTypeUniswapV3Router,
},
}
sv.signatures["factory()"] = &FunctionSignature{
Name: "factory()",
Selector: []byte{0xc4, 0x5a, 0x01, 0x55},
AllowedTypes: []ContractType{
ContractTypeUniswapV2Router,
ContractTypeUniswapV3Router,
},
}
}
// ValidationResult contains the result of function signature validation
type ValidationResult struct {
IsValid bool
FunctionName string
ContractType ContractType
Error error
Warnings []string
}
// ValidateFunctionCall validates if a function can be called on a contract
func (sv *SignatureValidator) ValidateFunctionCall(ctx context.Context, contractAddress common.Address, functionSelector []byte) *ValidationResult {
result := &ValidationResult{
IsValid: false,
Warnings: []string{},
}
// Detect contract type
detection := sv.detector.DetectContractType(ctx, contractAddress)
result.ContractType = detection.ContractType
if detection.Error != nil {
result.Error = fmt.Errorf("contract type detection failed: %w", detection.Error)
return result
}
// Find matching function signature
var matchedSignature *FunctionSignature
for _, sig := range sv.signatures {
if len(sig.Selector) >= 4 && len(functionSelector) >= 4 {
if sig.Selector[0] == functionSelector[0] &&
sig.Selector[1] == functionSelector[1] &&
sig.Selector[2] == functionSelector[2] &&
sig.Selector[3] == functionSelector[3] {
matchedSignature = sig
result.FunctionName = sig.Name
break
}
}
}
// If no signature match found, warn but allow (could be unknown function)
if matchedSignature == nil {
result.IsValid = true
result.Warnings = append(result.Warnings, fmt.Sprintf("unknown function selector: %x", functionSelector))
return result
}
// Check if the detected contract type is allowed for this function
allowed := false
for _, allowedType := range matchedSignature.AllowedTypes {
if detection.ContractType == allowedType {
allowed = true
break
}
}
if !allowed {
result.Error = fmt.Errorf("function %s cannot be called on contract type %s (allowed types: %v)",
matchedSignature.Name, detection.ContractType.String(), matchedSignature.AllowedTypes)
return result
}
// Check confidence level
if detection.Confidence < 0.7 {
result.Warnings = append(result.Warnings, fmt.Sprintf("low confidence in contract type detection: %.2f", detection.Confidence))
}
result.IsValid = true
return result
}
// ValidateToken0Call specifically validates token0() function calls
func (sv *SignatureValidator) ValidateToken0Call(ctx context.Context, contractAddress common.Address) *ValidationResult {
token0Selector := []byte{0x0d, 0xfe, 0x16, 0x81}
return sv.ValidateFunctionCall(ctx, contractAddress, token0Selector)
}
// ValidateToken1Call specifically validates token1() function calls
func (sv *SignatureValidator) ValidateToken1Call(ctx context.Context, contractAddress common.Address) *ValidationResult {
token1Selector := []byte{0xd2, 0x12, 0x20, 0xa7}
return sv.ValidateFunctionCall(ctx, contractAddress, token1Selector)
}
// ValidateGetReservesCall specifically validates getReserves() function calls
func (sv *SignatureValidator) ValidateGetReservesCall(ctx context.Context, contractAddress common.Address) *ValidationResult {
getReservesSelector := []byte{0x09, 0x02, 0xf1, 0xac}
return sv.ValidateFunctionCall(ctx, contractAddress, getReservesSelector)
}
// ValidateSlot0Call specifically validates slot0() function calls for Uniswap V3
func (sv *SignatureValidator) ValidateSlot0Call(ctx context.Context, contractAddress common.Address) *ValidationResult {
slot0Selector := []byte{0x38, 0x50, 0xc7, 0xbd}
return sv.ValidateFunctionCall(ctx, contractAddress, slot0Selector)
}
// GetSupportedFunctions returns the functions supported by a contract type
func (sv *SignatureValidator) GetSupportedFunctions(contractType ContractType) []string {
var functions []string
for _, sig := range sv.signatures {
for _, allowedType := range sig.AllowedTypes {
if allowedType == contractType {
functions = append(functions, sig.Name)
break
}
}
}
return functions
}