diff --git a/Cargo.lock b/Cargo.lock index eb1a8f7..f410000 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1320,6 +1320,7 @@ dependencies = [ "regex", "reqwest", "serde_json", + "snap", "tokio", ] @@ -2957,6 +2958,12 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +[[package]] +name = "snap" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" + [[package]] name = "socket2" version = "0.4.10" diff --git a/Cargo.toml b/Cargo.toml index 8b40b09..e2e5ee7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,4 +12,5 @@ ethers-solc = "2.0.10" regex = "1.10.2" reqwest = "0.11.22" serde_json = "1.0.107" +snap = "1.1.0" tokio = {version = "1", features = ["full"]} diff --git a/src/config.rs b/src/config.rs index 3fd0064..e69de29 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1 +0,0 @@ -pub fn cli() {} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 029dfa6..da28ddc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use reqwest::Error; use serde_json::{Map, Value}; use tokio; use std::fs; +mod config; fn read_sol_file(file_path: &str) -> Result { // Read the contents of the Solidity file into a string @@ -30,6 +31,7 @@ mod optimizor { #[tokio::main] async fn main() { let contract: &str = &read_sol_file("./src/contract.sol").unwrap(); + config::cli(); //create new JSON Object to store gas inefficiencies let mut gas_inefficiencies = Map::new(); @@ -44,6 +46,11 @@ async fn main() { optimizor::gas_tricks::uint_incur_overhead(contract, &mut gas_inefficiencies); optimizor::gas_tricks::mapping_instead_array(contract, &mut gas_inefficiencies); optimizor::gas_tricks::uint256_instead_bool(contract, &mut gas_inefficiencies); + optimizor::gas_tricks::require_double_logic(contract, &mut gas_inefficiencies); + optimizor::gas_tricks::revert_32(contract, &mut gas_inefficiencies); + optimizor::gas_tricks::do_while(contract, &mut gas_inefficiencies); + optimizor::gas_tricks::priv_constants_immut(contract, &mut gas_inefficiencies); + optimizor::gas_tricks::emit_loops(contract, &mut gas_inefficiencies); // Convert the gas inefficiencies to JSON let gas_inefficiencies_json = diff --git a/src/optimizor/gas_tricks.rs b/src/optimizor/gas_tricks.rs index bdafd26..8f9cdb6 100644 --- a/src/optimizor/gas_tricks.rs +++ b/src/optimizor/gas_tricks.rs @@ -189,3 +189,87 @@ pub fn use_named_retunrs(contract: &str, gas_inefficiencies: &mut Map, +) { + let regexe = Regex::new(r"require\(.*&&.*\);").unwrap(); + let lines: Vec<&str> = contract.lines().collect(); + for (line_number, line) in lines.iter().enumerate() { + if regexe.captures(line).is_some() { + let inefficiency_id = format!("line_{}", line_number + 1); + println!("split require statements "); + + gas_inefficiencies.insert( + inefficiency_id, + "split require statements that use && into two seperate parts to save gas ".into(), + ); + } + } +} + +pub fn revert_32(contract: &str, gas_inefficiencies: &mut Map) { + let regexe = Regex::new(r"revert\(.*\'.{33,}\'.*\);").unwrap(); + let lines: Vec<&str> = contract.lines().collect(); + for (line_number, line) in lines.iter().enumerate() { + if regexe.captures(line).is_some() { + let inefficiency_id = format!("line_{}", line_number + 1); + println!("string length more thaan 32 "); + + gas_inefficiencies.insert( + inefficiency_id, + "revert statement that has it's string longer than 32 length is always more expensive ".into(), + ); + } + } +} + +pub fn do_while(contract: &str, gas_inefficiencies: &mut Map) { + let regexe = Regex::new(r"\bfor\s*\(").unwrap(); + let lines: Vec<&str> = contract.lines().collect(); + for (line_number, line) in lines.iter().enumerate() { + if regexe.captures(line).is_some() { + let inefficiency_id = format!("line_{}", line_number + 1); + println!("use do while loops instead of for loops "); + + gas_inefficiencies.insert( + inefficiency_id, + "do while loops are cheaper than loops and consume less gas ".into(), + ); + } + } +} + +pub fn priv_constants_immut(contract: &str, gas_inefficiencies: &mut Map) { + let regexe = Regex::new(r"\bpublic\b.*(constant | immutable)").unwrap(); + let lines: Vec<&str> = contract.lines().collect(); + for (line_number, line) in lines.iter().enumerate() { + if regexe.captures(line).is_some() { + let inefficiency_id = format!("line_{}", line_number + 1); + println!("variables that are constant should have a visibility of private"); + + gas_inefficiencies.insert( + inefficiency_id, + "variables that are constant should have a visibility of private".into(), + ); + } + } +} + + +pub fn emit_loops(contract: &str, gas_inefficiencies: &mut Map) { + let regexe = Regex::new(r"\bfor\s*\(\s*.*emit").unwrap(); + let lines: Vec<&str> = contract.lines().collect(); + for (line_number, line) in lines.iter().enumerate() { + if regexe.captures(line).is_some() { + let inefficiency_id = format!("line_{}", line_number + 1); + println!("emiting events in loops cost more, and should be done using other means"); + + gas_inefficiencies.insert( + inefficiency_id, + "emiting events in loops cost more, and should be done using other means".into(), + ); + } + } +}