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>
This commit is contained in:
564
orig/pkg/security/contract_validator.go
Normal file
564
orig/pkg/security/contract_validator.go
Normal file
@@ -0,0 +1,564 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
|
||||
"github.com/fraktal/mev-beta/internal/logger"
|
||||
)
|
||||
|
||||
// ContractInfo represents information about a verified contract
|
||||
type ContractInfo struct {
|
||||
Address common.Address `json:"address"`
|
||||
BytecodeHash string `json:"bytecode_hash"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
DeployedAt *big.Int `json:"deployed_at"`
|
||||
Deployer common.Address `json:"deployer"`
|
||||
VerifiedAt time.Time `json:"verified_at"`
|
||||
IsWhitelisted bool `json:"is_whitelisted"`
|
||||
RiskLevel RiskLevel `json:"risk_level"`
|
||||
Permissions ContractPermissions `json:"permissions"`
|
||||
ABIHash string `json:"abi_hash,omitempty"`
|
||||
SourceCodeHash string `json:"source_code_hash,omitempty"`
|
||||
}
|
||||
|
||||
// ContractPermissions defines what operations are allowed with a contract
|
||||
type ContractPermissions struct {
|
||||
CanInteract bool `json:"can_interact"`
|
||||
CanSendValue bool `json:"can_send_value"`
|
||||
MaxValueWei *big.Int `json:"max_value_wei,omitempty"`
|
||||
AllowedMethods []string `json:"allowed_methods,omitempty"`
|
||||
RequireConfirm bool `json:"require_confirmation"`
|
||||
DailyLimit *big.Int `json:"daily_limit,omitempty"`
|
||||
}
|
||||
|
||||
// RiskLevel represents the risk assessment of a contract
|
||||
type RiskLevel int
|
||||
|
||||
const (
|
||||
RiskLevelLow RiskLevel = iota
|
||||
RiskLevelMedium
|
||||
RiskLevelHigh
|
||||
RiskLevelCritical
|
||||
RiskLevelBlocked
|
||||
)
|
||||
|
||||
func (r RiskLevel) String() string {
|
||||
switch r {
|
||||
case RiskLevelLow:
|
||||
return "Low"
|
||||
case RiskLevelMedium:
|
||||
return "Medium"
|
||||
case RiskLevelHigh:
|
||||
return "High"
|
||||
case RiskLevelCritical:
|
||||
return "Critical"
|
||||
case RiskLevelBlocked:
|
||||
return "Blocked"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// ContractValidationResult contains the result of contract validation
|
||||
type ContractValidationResult struct {
|
||||
IsValid bool `json:"is_valid"`
|
||||
ContractInfo *ContractInfo `json:"contract_info"`
|
||||
ValidationError string `json:"validation_error,omitempty"`
|
||||
Warnings []string `json:"warnings"`
|
||||
ChecksPerformed []ValidationCheck `json:"checks_performed"`
|
||||
RiskScore int `json:"risk_score"` // 1-10
|
||||
}
|
||||
|
||||
// ValidationCheck represents a single validation check
|
||||
type ValidationCheck struct {
|
||||
Name string `json:"name"`
|
||||
Passed bool `json:"passed"`
|
||||
Description string `json:"description"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// ContractValidator provides secure contract validation and verification
|
||||
type ContractValidator struct {
|
||||
client *ethclient.Client
|
||||
logger *logger.Logger
|
||||
trustedContracts map[common.Address]*ContractInfo
|
||||
contractCache map[common.Address]*ContractInfo
|
||||
cacheMutex sync.RWMutex
|
||||
config *ContractValidatorConfig
|
||||
|
||||
// Security tracking
|
||||
interactionCounts map[common.Address]int64
|
||||
dailyLimits map[common.Address]*big.Int
|
||||
lastResetTime time.Time
|
||||
limitsMutex sync.RWMutex
|
||||
}
|
||||
|
||||
// ContractValidatorConfig provides configuration for the contract validator
|
||||
type ContractValidatorConfig struct {
|
||||
EnableBytecodeVerification bool `json:"enable_bytecode_verification"`
|
||||
EnableABIValidation bool `json:"enable_abi_validation"`
|
||||
RequireWhitelist bool `json:"require_whitelist"`
|
||||
MaxBytecodeSize int `json:"max_bytecode_size"`
|
||||
CacheTimeout time.Duration `json:"cache_timeout"`
|
||||
MaxRiskScore int `json:"max_risk_score"`
|
||||
BlockUnverifiedContracts bool `json:"block_unverified_contracts"`
|
||||
RequireSourceCode bool `json:"require_source_code"`
|
||||
EnableRealTimeValidation bool `json:"enable_realtime_validation"`
|
||||
}
|
||||
|
||||
// NewContractValidator creates a new contract validator
|
||||
func NewContractValidator(client *ethclient.Client, logger *logger.Logger, config *ContractValidatorConfig) *ContractValidator {
|
||||
if config == nil {
|
||||
config = getDefaultValidatorConfig()
|
||||
}
|
||||
|
||||
return &ContractValidator{
|
||||
client: client,
|
||||
logger: logger,
|
||||
config: config,
|
||||
trustedContracts: make(map[common.Address]*ContractInfo),
|
||||
contractCache: make(map[common.Address]*ContractInfo),
|
||||
interactionCounts: make(map[common.Address]int64),
|
||||
dailyLimits: make(map[common.Address]*big.Int),
|
||||
lastResetTime: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// AddTrustedContract adds a contract to the trusted list
|
||||
func (cv *ContractValidator) AddTrustedContract(info *ContractInfo) error {
|
||||
cv.cacheMutex.Lock()
|
||||
defer cv.cacheMutex.Unlock()
|
||||
|
||||
// Validate the contract info
|
||||
if info.Address == (common.Address{}) {
|
||||
return fmt.Errorf("invalid contract address")
|
||||
}
|
||||
|
||||
if info.BytecodeHash == "" {
|
||||
return fmt.Errorf("bytecode hash is required")
|
||||
}
|
||||
|
||||
// Mark as whitelisted and set low risk
|
||||
info.IsWhitelisted = true
|
||||
if info.RiskLevel == 0 {
|
||||
info.RiskLevel = RiskLevelLow
|
||||
}
|
||||
info.VerifiedAt = time.Now()
|
||||
|
||||
cv.trustedContracts[info.Address] = info
|
||||
cv.contractCache[info.Address] = info
|
||||
|
||||
cv.logger.Info(fmt.Sprintf("Added trusted contract: %s (%s)", info.Address.Hex(), info.Name))
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateContract performs comprehensive contract validation
|
||||
func (cv *ContractValidator) ValidateContract(ctx context.Context, address common.Address) (*ContractValidationResult, error) {
|
||||
result := &ContractValidationResult{
|
||||
IsValid: false,
|
||||
Warnings: make([]string, 0),
|
||||
ChecksPerformed: make([]ValidationCheck, 0),
|
||||
}
|
||||
|
||||
// Check if contract is in trusted list first
|
||||
cv.cacheMutex.RLock()
|
||||
if trusted, exists := cv.trustedContracts[address]; exists {
|
||||
cv.cacheMutex.RUnlock()
|
||||
result.IsValid = true
|
||||
result.ContractInfo = trusted
|
||||
result.ChecksPerformed = append(result.ChecksPerformed, ValidationCheck{
|
||||
Name: "Trusted Contract Check",
|
||||
Passed: true,
|
||||
Description: "Contract found in trusted whitelist",
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Check cache
|
||||
if cached, exists := cv.contractCache[address]; exists {
|
||||
if time.Since(cached.VerifiedAt) < cv.config.CacheTimeout {
|
||||
cv.cacheMutex.RUnlock()
|
||||
result.IsValid = true
|
||||
result.ContractInfo = cached
|
||||
result.ChecksPerformed = append(result.ChecksPerformed, ValidationCheck{
|
||||
Name: "Cache Check",
|
||||
Passed: true,
|
||||
Description: "Contract found in validation cache",
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
cv.cacheMutex.RUnlock()
|
||||
|
||||
// Perform real-time validation
|
||||
contractInfo, err := cv.validateContractOnChain(ctx, address, result)
|
||||
if err != nil {
|
||||
result.ValidationError = err.Error()
|
||||
return result, err
|
||||
}
|
||||
|
||||
result.ContractInfo = contractInfo
|
||||
result.RiskScore = cv.calculateRiskScore(contractInfo, result)
|
||||
|
||||
// Check if contract meets security requirements
|
||||
if cv.config.RequireWhitelist && !contractInfo.IsWhitelisted {
|
||||
result.ValidationError = "Contract not whitelisted"
|
||||
result.ChecksPerformed = append(result.ChecksPerformed, ValidationCheck{
|
||||
Name: "Whitelist Check",
|
||||
Passed: false,
|
||||
Description: "Contract not found in whitelist",
|
||||
Error: "Contract not whitelisted",
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
return result, fmt.Errorf("contract not whitelisted: %s", address.Hex())
|
||||
}
|
||||
|
||||
if result.RiskScore > cv.config.MaxRiskScore {
|
||||
result.ValidationError = fmt.Sprintf("Risk score too high: %d > %d", result.RiskScore, cv.config.MaxRiskScore)
|
||||
return result, fmt.Errorf("contract risk score too high: %d", result.RiskScore)
|
||||
}
|
||||
|
||||
// Cache the validation result
|
||||
cv.cacheMutex.Lock()
|
||||
cv.contractCache[address] = contractInfo
|
||||
cv.cacheMutex.Unlock()
|
||||
|
||||
result.IsValid = true
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// validateContractOnChain performs on-chain validation of a contract
|
||||
func (cv *ContractValidator) validateContractOnChain(ctx context.Context, address common.Address, result *ContractValidationResult) (*ContractInfo, error) {
|
||||
// Check if address is a contract
|
||||
bytecode, err := cv.client.CodeAt(ctx, address, nil)
|
||||
if err != nil {
|
||||
result.ChecksPerformed = append(result.ChecksPerformed, ValidationCheck{
|
||||
Name: "Bytecode Retrieval",
|
||||
Passed: false,
|
||||
Description: "Failed to retrieve contract bytecode",
|
||||
Error: err.Error(),
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
return nil, fmt.Errorf("failed to get contract bytecode: %w", err)
|
||||
}
|
||||
|
||||
if len(bytecode) == 0 {
|
||||
result.ChecksPerformed = append(result.ChecksPerformed, ValidationCheck{
|
||||
Name: "Contract Existence",
|
||||
Passed: false,
|
||||
Description: "Address is not a contract (no bytecode)",
|
||||
Error: "No bytecode found",
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
return nil, fmt.Errorf("address is not a contract: %s", address.Hex())
|
||||
}
|
||||
|
||||
result.ChecksPerformed = append(result.ChecksPerformed, ValidationCheck{
|
||||
Name: "Contract Existence",
|
||||
Passed: true,
|
||||
Description: fmt.Sprintf("Contract bytecode found (%d bytes)", len(bytecode)),
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
|
||||
// Validate bytecode size
|
||||
if cv.config.MaxBytecodeSize > 0 && len(bytecode) > cv.config.MaxBytecodeSize {
|
||||
result.Warnings = append(result.Warnings, fmt.Sprintf("Large bytecode size: %d bytes", len(bytecode)))
|
||||
}
|
||||
|
||||
// Create bytecode hash
|
||||
bytecodeHash := crypto.Keccak256Hash(bytecode).Hex()
|
||||
|
||||
// Get deployment transaction info
|
||||
deployedAt, deployer, err := cv.getDeploymentInfo(ctx, address)
|
||||
if err != nil {
|
||||
cv.logger.Warn(fmt.Sprintf("Could not retrieve deployment info for %s: %v", address.Hex(), err))
|
||||
deployedAt = big.NewInt(0)
|
||||
deployer = common.Address{}
|
||||
}
|
||||
|
||||
// Create contract info
|
||||
contractInfo := &ContractInfo{
|
||||
Address: address,
|
||||
BytecodeHash: bytecodeHash,
|
||||
Name: "Unknown Contract",
|
||||
Version: "unknown",
|
||||
DeployedAt: deployedAt,
|
||||
Deployer: deployer,
|
||||
VerifiedAt: time.Now(),
|
||||
IsWhitelisted: false,
|
||||
RiskLevel: cv.assessRiskLevel(bytecode, result),
|
||||
Permissions: cv.getDefaultPermissions(),
|
||||
}
|
||||
|
||||
// Verify bytecode against known contracts if enabled
|
||||
if cv.config.EnableBytecodeVerification {
|
||||
cv.verifyBytecodeSignature(bytecode, contractInfo, result)
|
||||
}
|
||||
|
||||
result.ChecksPerformed = append(result.ChecksPerformed, ValidationCheck{
|
||||
Name: "Bytecode Validation",
|
||||
Passed: true,
|
||||
Description: "Bytecode hash calculated and verified",
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
|
||||
return contractInfo, nil
|
||||
}
|
||||
|
||||
// getDeploymentInfo retrieves deployment information for a contract
|
||||
func (cv *ContractValidator) getDeploymentInfo(ctx context.Context, address common.Address) (*big.Int, common.Address, error) {
|
||||
// This is a simplified implementation
|
||||
// In production, you would need to scan blocks or use an indexer
|
||||
return big.NewInt(0), common.Address{}, fmt.Errorf("deployment info not available")
|
||||
}
|
||||
|
||||
// assessRiskLevel assesses the risk level of a contract based on its bytecode
|
||||
func (cv *ContractValidator) assessRiskLevel(bytecode []byte, result *ContractValidationResult) RiskLevel {
|
||||
riskFactors := 0
|
||||
|
||||
// Check for suspicious patterns in bytecode
|
||||
bytecodeStr := hex.EncodeToString(bytecode)
|
||||
|
||||
// Look for dangerous opcodes
|
||||
dangerousOpcodes := []string{
|
||||
"ff", // SELFDESTRUCT
|
||||
"f4", // DELEGATECALL
|
||||
"3d", // RETURNDATASIZE (often used in proxy patterns)
|
||||
}
|
||||
|
||||
for _, opcode := range dangerousOpcodes {
|
||||
if contains := func(haystack, needle string) bool {
|
||||
return len(haystack) >= len(needle) && haystack[:len(needle)] == needle ||
|
||||
len(haystack) > len(needle) && haystack[len(haystack)-len(needle):] == needle
|
||||
}; contains(bytecodeStr, opcode) {
|
||||
riskFactors++
|
||||
}
|
||||
}
|
||||
|
||||
// Check bytecode size (larger contracts may be more complex/risky)
|
||||
if len(bytecode) > 20000 { // 20KB
|
||||
riskFactors++
|
||||
result.Warnings = append(result.Warnings, "Large contract size detected")
|
||||
}
|
||||
|
||||
// Assess risk level based on factors
|
||||
switch {
|
||||
case riskFactors == 0:
|
||||
return RiskLevelLow
|
||||
case riskFactors <= 2:
|
||||
return RiskLevelMedium
|
||||
case riskFactors <= 4:
|
||||
return RiskLevelHigh
|
||||
default:
|
||||
return RiskLevelCritical
|
||||
}
|
||||
}
|
||||
|
||||
// verifyBytecodeSignature verifies bytecode against known contract signatures
|
||||
func (cv *ContractValidator) verifyBytecodeSignature(bytecode []byte, info *ContractInfo, result *ContractValidationResult) {
|
||||
// Known contract bytecode hashes for common contracts
|
||||
knownContracts := map[string]string{
|
||||
// Uniswap V3 Factory
|
||||
"0x1f98431c8ad98523631ae4a59f267346ea31f984": "uniswap_v3_factory",
|
||||
// Uniswap V3 Router
|
||||
"0xe592427a0aece92de3edee1f18e0157c05861564": "uniswap_v3_router",
|
||||
// Add more known contracts...
|
||||
}
|
||||
|
||||
addressStr := info.Address.Hex()
|
||||
if name, exists := knownContracts[addressStr]; exists {
|
||||
info.Name = name
|
||||
info.IsWhitelisted = true
|
||||
info.RiskLevel = RiskLevelLow
|
||||
result.ChecksPerformed = append(result.ChecksPerformed, ValidationCheck{
|
||||
Name: "Known Contract Verification",
|
||||
Passed: true,
|
||||
Description: fmt.Sprintf("Verified as known contract: %s", name),
|
||||
Timestamp: time.Now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// calculateRiskScore calculates a numerical risk score (1-10)
|
||||
func (cv *ContractValidator) calculateRiskScore(info *ContractInfo, result *ContractValidationResult) int {
|
||||
score := 1 // Base score
|
||||
|
||||
// Adjust based on risk level
|
||||
switch info.RiskLevel {
|
||||
case RiskLevelLow:
|
||||
score += 0
|
||||
case RiskLevelMedium:
|
||||
score += 2
|
||||
case RiskLevelHigh:
|
||||
score += 5
|
||||
case RiskLevelCritical:
|
||||
score += 8
|
||||
case RiskLevelBlocked:
|
||||
score = 10
|
||||
}
|
||||
|
||||
// Adjust based on whitelist status
|
||||
if !info.IsWhitelisted {
|
||||
score += 2
|
||||
}
|
||||
|
||||
// Adjust based on warnings
|
||||
score += len(result.Warnings)
|
||||
|
||||
// Cap at 10
|
||||
if score > 10 {
|
||||
score = 10
|
||||
}
|
||||
|
||||
return score
|
||||
}
|
||||
|
||||
// getDefaultPermissions returns default permissions for unverified contracts
|
||||
func (cv *ContractValidator) getDefaultPermissions() ContractPermissions {
|
||||
return ContractPermissions{
|
||||
CanInteract: true,
|
||||
CanSendValue: false,
|
||||
MaxValueWei: big.NewInt(0),
|
||||
AllowedMethods: []string{}, // Empty means all methods allowed
|
||||
RequireConfirm: true,
|
||||
DailyLimit: big.NewInt(1000000000000000000), // 1 ETH
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateTransaction validates a transaction against contract permissions
|
||||
func (cv *ContractValidator) ValidateTransaction(ctx context.Context, tx *types.Transaction) error {
|
||||
if tx.To() == nil {
|
||||
return nil // Contract creation, allow
|
||||
}
|
||||
|
||||
// Validate the contract
|
||||
result, err := cv.ValidateContract(ctx, *tx.To())
|
||||
if err != nil {
|
||||
return fmt.Errorf("contract validation failed: %w", err)
|
||||
}
|
||||
|
||||
if !result.IsValid {
|
||||
return fmt.Errorf("transaction to invalid contract: %s", tx.To().Hex())
|
||||
}
|
||||
|
||||
// Check permissions
|
||||
permissions := result.ContractInfo.Permissions
|
||||
|
||||
// Check value transfer permission
|
||||
if tx.Value().Sign() > 0 && !permissions.CanSendValue {
|
||||
return fmt.Errorf("contract does not allow value transfers: %s", tx.To().Hex())
|
||||
}
|
||||
|
||||
// Check value limits
|
||||
if permissions.MaxValueWei != nil && tx.Value().Cmp(permissions.MaxValueWei) > 0 {
|
||||
return fmt.Errorf("transaction value exceeds limit: %s > %s",
|
||||
tx.Value().String(), permissions.MaxValueWei.String())
|
||||
}
|
||||
|
||||
// Check daily limits
|
||||
if err := cv.checkDailyLimit(*tx.To(), tx.Value()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cv.logger.Debug(fmt.Sprintf("Transaction validated for contract %s", tx.To().Hex()))
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkDailyLimit checks if transaction exceeds daily interaction limit
|
||||
func (cv *ContractValidator) checkDailyLimit(contractAddr common.Address, value *big.Int) error {
|
||||
cv.limitsMutex.Lock()
|
||||
defer cv.limitsMutex.Unlock()
|
||||
|
||||
// Reset daily counters if needed
|
||||
if time.Since(cv.lastResetTime) > 24*time.Hour {
|
||||
cv.dailyLimits = make(map[common.Address]*big.Int)
|
||||
cv.lastResetTime = time.Now()
|
||||
}
|
||||
|
||||
// Get current daily usage
|
||||
currentUsage, exists := cv.dailyLimits[contractAddr]
|
||||
if !exists {
|
||||
currentUsage = big.NewInt(0)
|
||||
cv.dailyLimits[contractAddr] = currentUsage
|
||||
}
|
||||
|
||||
// Get contract info for daily limit
|
||||
cv.cacheMutex.RLock()
|
||||
contractInfo, exists := cv.contractCache[contractAddr]
|
||||
cv.cacheMutex.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return nil // No limit if contract not cached
|
||||
}
|
||||
|
||||
if contractInfo.Permissions.DailyLimit == nil {
|
||||
return nil // No daily limit set
|
||||
}
|
||||
|
||||
// Check if adding this transaction would exceed limit
|
||||
newUsage := new(big.Int).Add(currentUsage, value)
|
||||
if newUsage.Cmp(contractInfo.Permissions.DailyLimit) > 0 {
|
||||
return fmt.Errorf("daily limit exceeded for contract %s: %s + %s > %s",
|
||||
contractAddr.Hex(),
|
||||
currentUsage.String(),
|
||||
value.String(),
|
||||
contractInfo.Permissions.DailyLimit.String())
|
||||
}
|
||||
|
||||
// Update usage
|
||||
cv.dailyLimits[contractAddr] = newUsage
|
||||
return nil
|
||||
}
|
||||
|
||||
// getDefaultValidatorConfig returns default configuration
|
||||
func getDefaultValidatorConfig() *ContractValidatorConfig {
|
||||
return &ContractValidatorConfig{
|
||||
EnableBytecodeVerification: true,
|
||||
EnableABIValidation: false, // Requires additional infrastructure
|
||||
RequireWhitelist: false, // Start permissive, can be tightened
|
||||
MaxBytecodeSize: 50000, // 50KB
|
||||
CacheTimeout: 1 * time.Hour,
|
||||
MaxRiskScore: 7, // Allow medium-high risk
|
||||
BlockUnverifiedContracts: false,
|
||||
RequireSourceCode: false,
|
||||
EnableRealTimeValidation: true,
|
||||
}
|
||||
}
|
||||
|
||||
// GetContractInfo returns information about a validated contract
|
||||
func (cv *ContractValidator) GetContractInfo(address common.Address) (*ContractInfo, bool) {
|
||||
cv.cacheMutex.RLock()
|
||||
defer cv.cacheMutex.RUnlock()
|
||||
|
||||
if info, exists := cv.contractCache[address]; exists {
|
||||
return info, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// ListTrustedContracts returns all trusted contracts
|
||||
func (cv *ContractValidator) ListTrustedContracts() map[common.Address]*ContractInfo {
|
||||
cv.cacheMutex.RLock()
|
||||
defer cv.cacheMutex.RUnlock()
|
||||
|
||||
// Create a copy to avoid race conditions
|
||||
trusted := make(map[common.Address]*ContractInfo)
|
||||
for addr, info := range cv.trustedContracts {
|
||||
trusted[addr] = info
|
||||
}
|
||||
return trusted
|
||||
}
|
||||
Reference in New Issue
Block a user