thalir-core 0.1.0

Core IR types and builders for ThalIR smart contract analysis
Documentation
use crate::block::BlockId;
use crate::values::Value;
use num_bigint::BigUint;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct SecurityMetadata {
    pub external_calls: Vec<ExternalCallSite>,
    pub state_mutations: Vec<StateMutation>,
    pub reentrancy_guards: Vec<ReentrancyGuard>,
    pub access_controls: Vec<AccessControl>,
    pub checked_operations: Vec<CheckedOp>,
    pub vulnerability_patterns: Vec<VulnerabilityPattern>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExternalCallSite {
    pub location: InstructionLocation,
    pub target: CallTarget,
    pub value_transfer: bool,
    pub state_changes_before: Vec<StateChange>,
    pub state_changes_after: Vec<StateChange>,
    pub can_reenter: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct InstructionLocation {
    pub block: BlockId,
    pub index: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CallTarget {
    Known(String),
    Unknown,
    UserControlled,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StateChange {
    pub storage_key: StorageKeyInfo,
    pub change_type: StateChangeType,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum StorageKeyInfo {
    Slot(BigUint),
    Mapping { base: BigUint, key: String },
    Dynamic(String),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum StateChangeType {
    Write,
    Delete,
    Increment,
    Decrement,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StateMutation {
    pub location: InstructionLocation,
    pub mutated_var: String,
    pub mutation_type: MutationType,
    pub depends_on_input: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MutationType {
    Assignment,
    Arithmetic,
    ArrayPush,
    ArrayPop,
    MappingUpdate,
    Deletion,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReentrancyGuard {
    pub guard_type: ReentrancyGuardType,
    pub protected_blocks: Vec<BlockId>,
    pub guard_variable: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ReentrancyGuardType {
    Mutex,
    CheckEffectsInteraction,
    NonReentrantModifier,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccessControl {
    pub control_type: AccessControlType,
    pub location: InstructionLocation,
    pub condition: AccessCondition,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AccessControlType {
    OwnerOnly,
    RoleBased(String),
    Whitelist,
    Pausable,
    Custom,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AccessCondition {
    RequireStatement,
    Modifier(String),
    IfStatement,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CheckedOp {
    pub location: InstructionLocation,
    pub operation: CheckedOperation,
    pub overflow_behavior: OverflowBehavior,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CheckedOperation {
    Addition,
    Subtraction,
    Multiplication,
    Division,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OverflowBehavior {
    Revert,
    Wrap,
    Saturate,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum VulnerabilityPattern {
    Reentrancy {
        call_site: InstructionLocation,
        state_changes: Vec<StateChange>,
    },
    IntegerOverflow {
        location: InstructionLocation,
        operation: String,
    },
    UnprotectedTransfer {
        location: InstructionLocation,
        recipient: String,
    },
    AccessControl {
        function: String,
        missing_check: String,
    },
    TimestampDependence {
        location: InstructionLocation,
        usage: String,
    },
    UncheckedReturn {
        call_location: InstructionLocation,
        ignored_value: String,
    },
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct OptimizationHints {
    pub pure_functions: HashSet<String>,
    pub view_functions: HashSet<String>,
    pub constant_expressions: Vec<ConstantExpression>,
    pub loop_bounds: HashMap<BlockId, LoopBound>,
    pub invariants: Vec<Invariant>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConstantExpression {
    pub location: InstructionLocation,
    pub value: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoopBound {
    pub min_iterations: Option<u64>,
    pub max_iterations: Option<u64>,
    pub bound_expression: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Invariant {
    pub condition: String,
    pub scope: InvariantScope,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum InvariantScope {
    Function(String),
    Loop(BlockId),
    Contract,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AnalysisMetadata {
    pub data_dependencies: DataDependencies,
    pub control_dependencies: ControlDependencies,
    pub taint_analysis: TaintAnalysis,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct DataDependencies {
    pub def_use_chains: HashMap<Value, HashSet<InstructionLocation>>,
    pub use_def_chains: HashMap<InstructionLocation, HashSet<Value>>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ControlDependencies {
    pub dominators: HashMap<BlockId, HashSet<BlockId>>,
    pub post_dominators: HashMap<BlockId, HashSet<BlockId>>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TaintAnalysis {
    pub tainted_values: HashSet<Value>,
    pub taint_sources: Vec<TaintSource>,
    pub taint_sinks: Vec<TaintSink>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaintSource {
    pub source_type: TaintSourceType,
    pub location: InstructionLocation,
    pub value: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TaintSourceType {
    UserInput,
    ExternalCall,
    Storage,
    Timestamp,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaintSink {
    pub sink_type: TaintSinkType,
    pub location: InstructionLocation,
    pub value: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TaintSinkType {
    StateChange,
    ExternalCall,
    Transfer,
    Selfdestruct,
}

impl SecurityMetadata {
    pub fn has_high_risk_patterns(&self) -> bool {
        for call in &self.external_calls {
            if call.value_transfer && !call.state_changes_after.is_empty() {
                return true;
            }
        }

        for mutation in &self.state_mutations {
            if mutation.depends_on_input && self.access_controls.is_empty() {
                return true;
            }
        }

        false
    }

    pub fn state_modifying_functions(&self) -> HashSet<String> {
        let functions = HashSet::new();

        for _mutation in &self.state_mutations {}

        functions
    }
}