Skip to content

Commit

Permalink
Merge pull request #2 from malik672/write_zero
Browse files Browse the repository at this point in the history
add write_to_zero
  • Loading branch information
malik672 authored Nov 17, 2023
2 parents 05a52d2 + 00ae493 commit 0f5e44e
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 1,226 deletions.
1,345 changes: 233 additions & 1,112 deletions artifacts/contract.sol/TypeHashHelper.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions cache/solidity-files-cache.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
},
"files": {
"src/contract.sol": {
"lastModificationDate": 1699959572526,
"contentHash": "f3613cf746d20faaf0808270629634c2",
"lastModificationDate": 1700205730658,
"contentHash": "dfc9ae93f98c74ec23d8b6cb7d982df3",
"sourceName": "src/contract.sol",
"solcConfig": {
"settings": {
Expand Down
11 changes: 1 addition & 10 deletions report.json
Original file line number Diff line number Diff line change
@@ -1,10 +1 @@
{
"line_50": [
"Use Uint256 instead of bytes32 to store constant",
"variables that are constant should have a visibility of private"
],
"line_57": [
"Use Uint256 instead of bytes32 to store constant",
"variables that are constant should have a visibility of private"
]
}
{}
92 changes: 10 additions & 82 deletions src/contract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,86 +10,14 @@ pragma solidity 0.8.12;
* @notice Helper library containing functions to build EIP712 struct and type hashes
*/

library TypeHashHelper {
/**
* @notice Structural representation of transaction details
* @param operation type of operation
* @param to address to send tx to
* @param account address of safe
* @param executor address of executor if executed via executor plugin, address(0) if executed via execTransaction
* @param value txn value
* @param nonce txn nonce
* @param data txn callData
*/
struct Transaction {
uint8 operation;
address to;
address account;
address executor;
uint256 value;
uint256 nonce;
bytes data;
}

/**
* @notice Type of validation struct to hash
* @param expiryEpoch max time till validity of the signature
* @param transactionStructHash txn digest generated using TypeHashHelper._buildTransactionStructHash()
* @param policyHash policy commit hash of the safe account
*/
struct Validation {
uint32 expiryEpoch;
bytes32 transactionStructHash;
bytes32 policyHash;
}

/**
* @notice EIP712 typehash for transaction data
* @dev keccak256("ExecutionParams(address to,uint256 value,bytes data,uint8 operation,address account,address executor,uint256 nonce)");
*/
bytes32 public constant TRANSACTION_PARAMS_TYPEHASH =
0xfd4628b53a91b366f1977138e2eda53b93c8f5cc74bda8440f108d7da1e99290;

/**
* @notice EIP712 typehash for validation data
* @dev keccak256("ValidationParams(ExecutionParams executionParams,bytes32 policyHash,uint32 expiryEpoch)ExecutionParams(address to,uint256 value,bytes data,uint8 operation,address account,address executor,uint256 nonce)")
*/
bytes32 public constant VALIDATION_PARAMS_TYPEHASH =
0x0c7f653e0f641e41fbb4ed1440c7d0b08b8d2a19e1c35cfc98de2d47519e15b1;

/**
* @notice Builds EIP712 transaction struct hash
* @param txn transaction params struct
* @return transactionStructHash
*/
function _buildTransactionStructHash(Transaction memory txn) internal pure returns (bytes32) {
return keccak256(
abi.encode(
TRANSACTION_PARAMS_TYPEHASH,
txn.to,
txn.value,
keccak256(txn.data),
txn.operation,
txn.account,
txn.executor,
txn.nonce
)
);
}

/**
* @notice Builds EIP712 validation struct hash
* @param validation validation params struct
* @return validationStructHash
*/
function _buildValidationStructHash(Validation memory validation) internal pure returns (bytes32) {
return keccak256(
abi.encode(
VALIDATION_PARAMS_TYPEHASH,
validation.transactionStructHash,
validation.policyHash,
validation.expiryEpoch
)
);
}
contract TypeHashHelper {
uint public reds;
function red() public {
uint x = 3 +2;
reds = 0;
}

function destroy() public {
reds = 0;
}
}
4 changes: 4 additions & 0 deletions src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ pub async fn loader() {
let contract = read_sol_file("src/contract.sol").unwrap();
// }

//Generate the ast
optimizor::ast::ast();

optimizor::write_zero_to_storage::write_zero_to_storage();

//create new JSON Object to store gas inefficiencies
let mut gas_inefficiencies = Map::new();
Expand Down
17 changes: 1 addition & 16 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,10 @@
use std::fs;
use tokio;
mod config;
mod loader;
mod optimizor;
use ethers_solc::{Project};


#[tokio::main]
async fn main() {
// create a project from a configuration file
let project = Project::builder().build().unwrap();
let output = project
.compile_files(vec!["src/contract.sol"])
.unwrap();
let artifacts = output.output().sources.0;
let mut s_ast = artifacts.values();
let mut binding = s_ast.next();
let mut binding = binding.iter_mut().next();
let s_asts = binding.as_mut().unwrap();
let ast = s_asts.get(0).unwrap().source_file.ast.clone().unwrap();
let ast_json = serde_json::to_string(&ast).unwrap();
let write = fs::write("src/optimizor/ast.json", ast_json);
// println!("{:?}", ast);
loader::loader().await;
}
2 changes: 1 addition & 1 deletion src/optimizor/ast.json

Large diffs are not rendered by default.

18 changes: 16 additions & 2 deletions src/optimizor/ast.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
use std::fs;
use ethers_solc;
use ethers_solc::{Project};

fn ast() {

pub fn ast() {
// create a project from a configuration file
let project = Project::builder().build().unwrap();
let output = project
.compile_files(vec!["src/contract.sol"])
.unwrap();
let artifacts = output.output().sources.0;
let mut s_ast = artifacts.values();
let mut binding = s_ast.next();
let mut binding = binding.iter_mut().next();
let s_asts = binding.as_mut().unwrap();
let ast = s_asts.get(0).unwrap().source_file.ast.clone().unwrap();
let ast_json = serde_json::to_string(&ast).unwrap();
let write = fs::write("src/optimizor/ast.json", ast_json).expect("failed to write ast");
}
4 changes: 3 additions & 1 deletion src/optimizor/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pub mod gas_tricks;
pub mod ast;
pub mod gas_tricks;
pub mod write_zero_to_storage;
95 changes: 95 additions & 0 deletions src/optimizor/write_zero_to_storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use regex::Regex;
use serde_json::Value;
use std::fs;

pub fn write_zero_to_storage() {
let ast_json = fs::read_to_string("src/optimizor/ast.json").expect("Failed to read");
let ast: Value = serde_json::from_str(&ast_json).expect("Failed to deserialize");
let mut _name = "";
let mut _prev: usize = 0;
if let Some(nodes) = ast.get("nodes").and_then(Value::as_array) {
for node in nodes {
if let Some(node_type) = node.get("nodeType").and_then(Value::as_str) {
if node_type == "ContractDefinition" {
if let Some(contract_nodes) = node.get("nodes").and_then(Value::as_array) {
for contract_node in contract_nodes {
if let Some(func_node) = contract_node.as_object() {
if func_node.get("nodeType").and_then(Value::as_str)
== Some("FunctionDefinition")
{
if let Some(statements) = func_node
.get("body")
.and_then(|b| b.get("statements"))
.and_then(Value::as_array)
{
for statement in statements {
if let Some(expression) = statement.get("expression") {
if expression
.get("operator")
.and_then(Value::as_str)
== Some("=")
{
if let Some(left_hand_side) =
expression.get("leftHandSide")
{
_name = left_hand_side
.get("name")
.unwrap()
.as_str()
.unwrap_or("");
}
if let Some(right_hand_side) =
expression.get("rightHandSide")
{
if right_hand_side.get("value")
== Some(&Value::String("0".to_string()))
{
if !right_hand_side
.get("isConstant")
.unwrap_or(&Value::Bool(true))
.as_bool()
.unwrap_or(true)
{
println!(
"Avoid zero to one storage writes where possible. Line: {:?}",
get_line_number_zero(_name, _prev)
);
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}

fn get_line_number_zero(src: &str, mut _prev: usize) -> String {
// Read the source file as a string
let contract = fs::read_to_string("src/contract.sol").expect("Failed to read");

// Split the contract content into lines
let lines: Vec<&str> = contract.lines().collect();

// Format the string with " = 0" at the end
let strss = format!("{} = 0", src);

// Compile the regex pattern
let variable_declaration_regex = Regex::new(&strss).unwrap();

let mut _line_numbers = 0;
for (mut line_number, line) in lines.iter().enumerate() {
line_number = _prev;
_line_numbers = line_number + 1;
if let Some(_capture) = variable_declaration_regex.captures(line) {}
_prev = _line_numbers;
}
_prev.to_string()
}

0 comments on commit 0f5e44e

Please sign in to comment.