Files
mev-beta/internal/registry/contract_registry.go
Krypto Kajun 850223a953 fix(multicall): resolve critical multicall parsing corruption issues
- Added comprehensive bounds checking to prevent buffer overruns in multicall parsing
- Implemented graduated validation system (Strict/Moderate/Permissive) to reduce false positives
- Added LRU caching system for address validation with 10-minute TTL
- Enhanced ABI decoder with missing Universal Router and Arbitrum-specific DEX signatures
- Fixed duplicate function declarations and import conflicts across multiple files
- Added error recovery mechanisms with multiple fallback strategies
- Updated tests to handle new validation behavior for suspicious addresses
- Fixed parser test expectations for improved validation system
- Applied gofmt formatting fixes to ensure code style compliance
- Fixed mutex copying issues in monitoring package by introducing MetricsSnapshot
- Resolved critical security vulnerabilities in heuristic address extraction
- Progress: Updated TODO audit from 10% to 35% complete

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-17 00:12:55 -05:00

494 lines
16 KiB
Go

package registry
import (
"context"
"fmt"
"sync"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/fraktal/mev-beta/internal/contracts"
"github.com/fraktal/mev-beta/internal/logger"
)
// ContractInfo contains comprehensive information about a contract
type ContractInfo struct {
Address common.Address
Type contracts.ContractType
Name string
Symbol string
Decimals uint8
Token0 common.Address // For pools
Token1 common.Address // For pools
Fee uint32 // For V3 pools (in basis points)
Factory common.Address
Protocol string
IsVerified bool
LastUpdated time.Time
Confidence float64
}
// ContractRegistry provides authoritative mapping of contract addresses to their types and metadata
type ContractRegistry struct {
mu sync.RWMutex
contracts map[common.Address]*ContractInfo
tokensBySymbol map[string]common.Address
poolsByTokenPair map[string][]common.Address // "token0:token1" -> pool addresses
detector *contracts.ContractDetector
logger *logger.Logger
updateInterval time.Duration
lastFullUpdate time.Time
}
// NewContractRegistry creates a new contract registry
func NewContractRegistry(detector *contracts.ContractDetector, logger *logger.Logger) *ContractRegistry {
registry := &ContractRegistry{
contracts: make(map[common.Address]*ContractInfo),
tokensBySymbol: make(map[string]common.Address),
poolsByTokenPair: make(map[string][]common.Address),
detector: detector,
logger: logger,
updateInterval: 24 * time.Hour, // Update every 24 hours
lastFullUpdate: time.Time{},
}
// Initialize with known Arbitrum contracts
registry.initializeKnownContracts()
return registry
}
// initializeKnownContracts populates the registry with well-known Arbitrum contracts
func (cr *ContractRegistry) initializeKnownContracts() {
cr.mu.Lock()
defer cr.mu.Unlock()
now := time.Now()
// Major ERC-20 tokens on Arbitrum
knownTokens := map[common.Address]*ContractInfo{
common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"): {
Address: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"),
Type: contracts.ContractTypeERC20Token,
Name: "Wrapped Ether",
Symbol: "WETH",
Decimals: 18,
Protocol: "Arbitrum",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
common.HexToAddress("0xA0b86a33E6D8E4BBa6Fd6bD5BA0e2FF8A1e8B8D4"): {
Address: common.HexToAddress("0xA0b86a33E6D8E4BBa6Fd6bD5BA0e2FF8A1e8B8D4"),
Type: contracts.ContractTypeERC20Token,
Name: "USD Coin",
Symbol: "USDC",
Decimals: 6,
Protocol: "Arbitrum",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
common.HexToAddress("0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"): {
Address: common.HexToAddress("0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"),
Type: contracts.ContractTypeERC20Token,
Name: "Tether USD",
Symbol: "USDT",
Decimals: 6,
Protocol: "Arbitrum",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
common.HexToAddress("0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f"): {
Address: common.HexToAddress("0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f"),
Type: contracts.ContractTypeERC20Token,
Name: "Wrapped BTC",
Symbol: "WBTC",
Decimals: 8,
Protocol: "Arbitrum",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
common.HexToAddress("0x912CE59144191C1204E64559FE8253a0e49E6548"): {
Address: common.HexToAddress("0x912CE59144191C1204E64559FE8253a0e49E6548"),
Type: contracts.ContractTypeERC20Token,
Name: "Arbitrum",
Symbol: "ARB",
Decimals: 18,
Protocol: "Arbitrum",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
}
// Major Uniswap V3 pools on Arbitrum
knownPools := map[common.Address]*ContractInfo{
common.HexToAddress("0xC6962004f452bE9203591991D15f6b388e09E8D0"): {
Address: common.HexToAddress("0xC6962004f452bE9203591991D15f6b388e09E8D0"),
Type: contracts.ContractTypeUniswapV3Pool,
Name: "USDC/WETH 0.05%",
Token0: common.HexToAddress("0xA0b86a33E6D8E4BBa6Fd6bD5BA0e2FF8A1e8B8D4"), // USDC
Token1: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), // WETH
Fee: 500, // 0.05%
Factory: common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984"),
Protocol: "UniswapV3",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
common.HexToAddress("0x17c14D2c404D167802b16C450d3c99F88F2c4F4d"): {
Address: common.HexToAddress("0x17c14D2c404D167802b16C450d3c99F88F2c4F4d"),
Type: contracts.ContractTypeUniswapV3Pool,
Name: "USDC/WETH 0.3%",
Token0: common.HexToAddress("0xA0b86a33E6D8E4BBa6Fd6bD5BA0e2FF8A1e8B8D4"), // USDC
Token1: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), // WETH
Fee: 3000, // 0.3%
Factory: common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984"),
Protocol: "UniswapV3",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
common.HexToAddress("0x2f5e87C9312fa29aed5c179E456625D79015299c"): {
Address: common.HexToAddress("0x2f5e87C9312fa29aed5c179E456625D79015299c"),
Type: contracts.ContractTypeUniswapV3Pool,
Name: "WBTC/WETH 0.05%",
Token0: common.HexToAddress("0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f"), // WBTC
Token1: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), // WETH
Fee: 500, // 0.05%
Factory: common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984"),
Protocol: "UniswapV3",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
common.HexToAddress("0x641C00A822e8b671738d32a431a4Fb6074E5c79d"): {
Address: common.HexToAddress("0x641C00A822e8b671738d32a431a4Fb6074E5c79d"),
Type: contracts.ContractTypeUniswapV3Pool,
Name: "USDT/WETH 0.05%",
Token0: common.HexToAddress("0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9"), // USDT
Token1: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), // WETH
Fee: 500, // 0.05%
Factory: common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984"),
Protocol: "UniswapV3",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
common.HexToAddress("0xFe7D6a84287235C7b4b57C4fEb9a44d4C6Ed3BB8"): {
Address: common.HexToAddress("0xFe7D6a84287235C7b4b57C4fEb9a44d4C6Ed3BB8"),
Type: contracts.ContractTypeUniswapV3Pool,
Name: "ARB/WETH 0.05%",
Token0: common.HexToAddress("0x912CE59144191C1204E64559FE8253a0e49E6548"), // ARB
Token1: common.HexToAddress("0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"), // WETH
Fee: 500, // 0.05%
Factory: common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984"),
Protocol: "UniswapV3",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
}
// Major routers on Arbitrum
knownRouters := map[common.Address]*ContractInfo{
common.HexToAddress("0xE592427A0AEce92De3Edee1F18E0157C05861564"): {
Address: common.HexToAddress("0xE592427A0AEce92De3Edee1F18E0157C05861564"),
Type: contracts.ContractTypeUniswapV3Router,
Name: "Uniswap V3 Router",
Protocol: "UniswapV3",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
common.HexToAddress("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"): {
Address: common.HexToAddress("0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"),
Type: contracts.ContractTypeUniswapV3Router,
Name: "Uniswap V3 Router 2",
Protocol: "UniswapV3",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
common.HexToAddress("0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"): {
Address: common.HexToAddress("0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"),
Type: contracts.ContractTypeUniswapV2Router,
Name: "SushiSwap Router",
Protocol: "SushiSwap",
IsVerified: true,
LastUpdated: now,
Confidence: 1.0,
},
}
// Add all known contracts
for addr, info := range knownTokens {
cr.contracts[addr] = info
cr.tokensBySymbol[info.Symbol] = addr
}
for addr, info := range knownPools {
cr.contracts[addr] = info
// Index pools by token pair
if info.Token0 != (common.Address{}) && info.Token1 != (common.Address{}) {
pairKey := cr.makeTokenPairKey(info.Token0, info.Token1)
cr.poolsByTokenPair[pairKey] = append(cr.poolsByTokenPair[pairKey], addr)
}
}
for addr, info := range knownRouters {
cr.contracts[addr] = info
}
cr.logger.Info("Contract registry initialized",
"tokens", len(knownTokens),
"pools", len(knownPools),
"routers", len(knownRouters))
}
// GetContractInfo retrieves contract information, using cache first then detection
func (cr *ContractRegistry) GetContractInfo(ctx context.Context, address common.Address) (*ContractInfo, error) {
// Try cache first
if info := cr.getCachedInfo(address); info != nil {
return info, nil
}
// Not in cache, use detector
detection := cr.detector.DetectContractType(ctx, address)
if detection.Error != nil {
return nil, fmt.Errorf("contract detection failed: %w", detection.Error)
}
// Create contract info from detection
info := &ContractInfo{
Address: address,
Type: detection.ContractType,
Name: fmt.Sprintf("Unknown %s", detection.ContractType.String()),
Protocol: "Unknown",
IsVerified: false,
LastUpdated: time.Now(),
Confidence: detection.Confidence,
}
// Cache the result
cr.cacheContractInfo(info)
return info, nil
}
// getCachedInfo safely retrieves cached contract info
func (cr *ContractRegistry) getCachedInfo(address common.Address) *ContractInfo {
cr.mu.RLock()
defer cr.mu.RUnlock()
return cr.contracts[address]
}
// cacheContractInfo safely caches contract info
func (cr *ContractRegistry) cacheContractInfo(info *ContractInfo) {
cr.mu.Lock()
defer cr.mu.Unlock()
cr.contracts[info.Address] = info
}
// IsKnownToken checks if an address is a known ERC-20 token
func (cr *ContractRegistry) IsKnownToken(address common.Address) bool {
cr.mu.RLock()
defer cr.mu.RUnlock()
if info, exists := cr.contracts[address]; exists {
return info.Type == contracts.ContractTypeERC20Token
}
return false
}
// IsKnownPool checks if an address is a known pool
func (cr *ContractRegistry) IsKnownPool(address common.Address) bool {
cr.mu.RLock()
defer cr.mu.RUnlock()
if info, exists := cr.contracts[address]; exists {
return info.Type == contracts.ContractTypeUniswapV2Pool ||
info.Type == contracts.ContractTypeUniswapV3Pool
}
return false
}
// IsKnownRouter checks if an address is a known router
func (cr *ContractRegistry) IsKnownRouter(address common.Address) bool {
cr.mu.RLock()
defer cr.mu.RUnlock()
if info, exists := cr.contracts[address]; exists {
return info.Type == contracts.ContractTypeUniswapV2Router ||
info.Type == contracts.ContractTypeUniswapV3Router ||
info.Type == contracts.ContractTypeUniversalRouter
}
return false
}
// GetTokenBySymbol retrieves a token address by symbol
func (cr *ContractRegistry) GetTokenBySymbol(symbol string) (common.Address, bool) {
cr.mu.RLock()
defer cr.mu.RUnlock()
addr, exists := cr.tokensBySymbol[symbol]
return addr, exists
}
// GetPoolsForTokenPair retrieves pools for a given token pair
func (cr *ContractRegistry) GetPoolsForTokenPair(token0, token1 common.Address) []common.Address {
cr.mu.RLock()
defer cr.mu.RUnlock()
pairKey := cr.makeTokenPairKey(token0, token1)
return cr.poolsByTokenPair[pairKey]
}
// makeTokenPairKey creates a consistent key for token pairs
func (cr *ContractRegistry) makeTokenPairKey(token0, token1 common.Address) string {
// Ensure consistent ordering
if token0.Big().Cmp(token1.Big()) > 0 {
token0, token1 = token1, token0
}
return fmt.Sprintf("%s:%s", token0.Hex(), token1.Hex())
}
// GetKnownContracts returns all cached contracts
func (cr *ContractRegistry) GetKnownContracts() map[common.Address]*ContractInfo {
cr.mu.RLock()
defer cr.mu.RUnlock()
// Return a copy to prevent external modification
result := make(map[common.Address]*ContractInfo)
for addr, info := range cr.contracts {
result[addr] = info
}
return result
}
// UpdateContractInfo updates contract information (for dynamic discovery)
func (cr *ContractRegistry) UpdateContractInfo(info *ContractInfo) {
cr.mu.Lock()
defer cr.mu.Unlock()
info.LastUpdated = time.Now()
cr.contracts[info.Address] = info
// Update indexes
if info.Type == contracts.ContractTypeERC20Token && info.Symbol != "" {
cr.tokensBySymbol[info.Symbol] = info.Address
}
if (info.Type == contracts.ContractTypeUniswapV2Pool || info.Type == contracts.ContractTypeUniswapV3Pool) &&
info.Token0 != (common.Address{}) && info.Token1 != (common.Address{}) {
pairKey := cr.makeTokenPairKey(info.Token0, info.Token1)
// Check if already exists in slice
pools := cr.poolsByTokenPair[pairKey]
exists := false
for _, pool := range pools {
if pool == info.Address {
exists = true
break
}
}
if !exists {
cr.poolsByTokenPair[pairKey] = append(pools, info.Address)
}
}
}
// GetCacheStats returns statistics about the cached contracts
func (cr *ContractRegistry) GetCacheStats() map[string]int {
cr.mu.RLock()
defer cr.mu.RUnlock()
stats := map[string]int{
"total": len(cr.contracts),
"tokens": 0,
"v2_pools": 0,
"v3_pools": 0,
"routers": 0,
"verified": 0,
}
for _, info := range cr.contracts {
switch info.Type {
case contracts.ContractTypeERC20Token:
stats["tokens"]++
case contracts.ContractTypeUniswapV2Pool:
stats["v2_pools"]++
case contracts.ContractTypeUniswapV3Pool:
stats["v3_pools"]++
case contracts.ContractTypeUniswapV2Router, contracts.ContractTypeUniswapV3Router:
stats["routers"]++
}
if info.IsVerified {
stats["verified"]++
}
}
return stats
}
// GetPoolInfo returns pool information for a given address
func (cr *ContractRegistry) GetPoolInfo(address common.Address) *ContractInfo {
cr.mu.RLock()
defer cr.mu.RUnlock()
if info, exists := cr.contracts[address]; exists {
if info.Type == contracts.ContractTypeUniswapV2Pool || info.Type == contracts.ContractTypeUniswapV3Pool {
return info
}
}
return nil
}
// AddPool adds a pool to the registry
func (cr *ContractRegistry) AddPool(poolAddress, token0, token1 common.Address, protocol string) {
cr.mu.Lock()
defer cr.mu.Unlock()
// Determine pool type based on protocol
var poolType contracts.ContractType
switch protocol {
case "UniswapV2":
poolType = contracts.ContractTypeUniswapV2Pool
case "UniswapV3":
poolType = contracts.ContractTypeUniswapV3Pool
default:
poolType = contracts.ContractTypeUniswapV2Pool // Default to V2
}
// Add or update pool info
info := &ContractInfo{
Address: poolAddress,
Type: poolType,
Token0: token0,
Token1: token1,
Protocol: protocol,
IsVerified: false, // Runtime discovered pools are not pre-verified
LastUpdated: time.Now(),
Confidence: 0.8, // High confidence for runtime discovered pools
}
cr.contracts[poolAddress] = info
// Update token pair mapping
pairKey := cr.makeTokenPairKey(token0, token1)
if pools, exists := cr.poolsByTokenPair[pairKey]; exists {
// Check if pool already exists in the list
for _, existingPool := range pools {
if existingPool == poolAddress {
return // Already exists
}
}
cr.poolsByTokenPair[pairKey] = append(pools, poolAddress)
} else {
cr.poolsByTokenPair[pairKey] = []common.Address{poolAddress}
}
}