1use crate::block::BlockId;
2use crate::values::Value;
3use num_bigint::BigUint;
4use serde::{Deserialize, Serialize};
5use std::collections::{HashMap, HashSet};
6
7#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8pub struct SecurityMetadata {
9 pub external_calls: Vec<ExternalCallSite>,
10 pub state_mutations: Vec<StateMutation>,
11 pub reentrancy_guards: Vec<ReentrancyGuard>,
12 pub access_controls: Vec<AccessControl>,
13 pub checked_operations: Vec<CheckedOp>,
14 pub vulnerability_patterns: Vec<VulnerabilityPattern>,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct ExternalCallSite {
19 pub location: InstructionLocation,
20 pub target: CallTarget,
21 pub value_transfer: bool,
22 pub state_changes_before: Vec<StateChange>,
23 pub state_changes_after: Vec<StateChange>,
24 pub can_reenter: bool,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
28pub struct InstructionLocation {
29 pub block: BlockId,
30 pub index: usize,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub enum CallTarget {
35 Known(String),
36 Unknown,
37 UserControlled,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct StateChange {
42 pub storage_key: StorageKeyInfo,
43 pub change_type: StateChangeType,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub enum StorageKeyInfo {
48 Slot(BigUint),
49 Mapping { base: BigUint, key: String },
50 Dynamic(String),
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub enum StateChangeType {
55 Write,
56 Delete,
57 Increment,
58 Decrement,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct StateMutation {
63 pub location: InstructionLocation,
64 pub mutated_var: String,
65 pub mutation_type: MutationType,
66 pub depends_on_input: bool,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub enum MutationType {
71 Assignment,
72 Arithmetic,
73 ArrayPush,
74 ArrayPop,
75 MappingUpdate,
76 Deletion,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct ReentrancyGuard {
81 pub guard_type: ReentrancyGuardType,
82 pub protected_blocks: Vec<BlockId>,
83 pub guard_variable: Option<String>,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub enum ReentrancyGuardType {
88 Mutex,
89 CheckEffectsInteraction,
90 NonReentrantModifier,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct AccessControl {
95 pub control_type: AccessControlType,
96 pub location: InstructionLocation,
97 pub condition: AccessCondition,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub enum AccessControlType {
102 OwnerOnly,
103 RoleBased(String),
104 Whitelist,
105 Pausable,
106 Custom,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub enum AccessCondition {
111 RequireStatement,
112 Modifier(String),
113 IfStatement,
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct CheckedOp {
118 pub location: InstructionLocation,
119 pub operation: CheckedOperation,
120 pub overflow_behavior: OverflowBehavior,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub enum CheckedOperation {
125 Addition,
126 Subtraction,
127 Multiplication,
128 Division,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
132pub enum OverflowBehavior {
133 Revert,
134 Wrap,
135 Saturate,
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
139pub enum VulnerabilityPattern {
140 Reentrancy {
141 call_site: InstructionLocation,
142 state_changes: Vec<StateChange>,
143 },
144 IntegerOverflow {
145 location: InstructionLocation,
146 operation: String,
147 },
148 UnprotectedTransfer {
149 location: InstructionLocation,
150 recipient: String,
151 },
152 AccessControl {
153 function: String,
154 missing_check: String,
155 },
156 TimestampDependence {
157 location: InstructionLocation,
158 usage: String,
159 },
160 UncheckedReturn {
161 call_location: InstructionLocation,
162 ignored_value: String,
163 },
164}
165
166#[derive(Debug, Clone, Default, Serialize, Deserialize)]
167pub struct OptimizationHints {
168 pub pure_functions: HashSet<String>,
169 pub view_functions: HashSet<String>,
170 pub constant_expressions: Vec<ConstantExpression>,
171 pub loop_bounds: HashMap<BlockId, LoopBound>,
172 pub invariants: Vec<Invariant>,
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct ConstantExpression {
177 pub location: InstructionLocation,
178 pub value: Value,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct LoopBound {
183 pub min_iterations: Option<u64>,
184 pub max_iterations: Option<u64>,
185 pub bound_expression: Option<String>,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct Invariant {
190 pub condition: String,
191 pub scope: InvariantScope,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub enum InvariantScope {
196 Function(String),
197 Loop(BlockId),
198 Contract,
199}
200
201#[derive(Debug, Clone, Default, Serialize, Deserialize)]
202pub struct AnalysisMetadata {
203 pub data_dependencies: DataDependencies,
204 pub control_dependencies: ControlDependencies,
205 pub taint_analysis: TaintAnalysis,
206}
207
208#[derive(Debug, Clone, Default, Serialize, Deserialize)]
209pub struct DataDependencies {
210 pub def_use_chains: HashMap<Value, HashSet<InstructionLocation>>,
211 pub use_def_chains: HashMap<InstructionLocation, HashSet<Value>>,
212}
213
214#[derive(Debug, Clone, Default, Serialize, Deserialize)]
215pub struct ControlDependencies {
216 pub dominators: HashMap<BlockId, HashSet<BlockId>>,
217 pub post_dominators: HashMap<BlockId, HashSet<BlockId>>,
218}
219
220#[derive(Debug, Clone, Default, Serialize, Deserialize)]
221pub struct TaintAnalysis {
222 pub tainted_values: HashSet<Value>,
223 pub taint_sources: Vec<TaintSource>,
224 pub taint_sinks: Vec<TaintSink>,
225}
226
227#[derive(Debug, Clone, Serialize, Deserialize)]
228pub struct TaintSource {
229 pub source_type: TaintSourceType,
230 pub location: InstructionLocation,
231 pub value: Value,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
235pub enum TaintSourceType {
236 UserInput,
237 ExternalCall,
238 Storage,
239 Timestamp,
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize)]
243pub struct TaintSink {
244 pub sink_type: TaintSinkType,
245 pub location: InstructionLocation,
246 pub value: Value,
247}
248
249#[derive(Debug, Clone, Serialize, Deserialize)]
250pub enum TaintSinkType {
251 StateChange,
252 ExternalCall,
253 Transfer,
254 Selfdestruct,
255}
256
257impl SecurityMetadata {
258 pub fn has_high_risk_patterns(&self) -> bool {
259 for call in &self.external_calls {
260 if call.value_transfer && !call.state_changes_after.is_empty() {
261 return true;
262 }
263 }
264
265 for mutation in &self.state_mutations {
266 if mutation.depends_on_input && self.access_controls.is_empty() {
267 return true;
268 }
269 }
270
271 false
272 }
273
274 pub fn state_modifying_functions(&self) -> HashSet<String> {
275 let functions = HashSet::new();
276
277 for _mutation in &self.state_mutations {}
278
279 functions
280 }
281}