Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Support chained contract crunching with config file setup #26

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
/target
**/*.rs.bk
.DS_Store

# Output files
efficient_addresses.txt
efficient_addresses.*.txt
address_per_contracts.txt
106 changes: 93 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ rustc-hash = "1.1"
separator = "0.4.1"
terminal_size = "0.3.0"
tiny-keccak = "2.0"
serde = { version = "1.0", features = ["derive"] }
toml = "0.8.19"
regex = "1.11.0"

[profile.release]
opt-level = 3
Expand Down
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ Provide three arguments: a factory address (or contract that will call CREATE2),

Live `Create2Factory` contracts can be found [here](https://blockscan.com/address/0x0000000000ffe8b47b3e2130213b802212439497).

## Usage

## Cli

```sh
$ git clone https://github.com/0age/create2crunch
$ cd create2crunch
Expand All @@ -16,6 +20,24 @@ $ export INIT_CODE_HASH="<HASH_OF_YOUR_CONTRACT_INIT_CODE_GOES_HERE>"
$ cargo run --release $FACTORY $CALLER $INIT_CODE_HASH
```

## Config

1. Create a bin folder at the root of the project
2. Move each one of your smart contracts creation code to a file in the bin folder
3. If your contracts require constructor args, and it's one of the other contracts to be determined, you can put placeholder value in place, it will be automatically replaced by the actual value
4. Create your toml config based on the example `config.example.toml`
5. Run it
```sh
$ git clone https://github.com/0age/create2crunch
$ cd create2crunch
$ cargo run --release config.toml
```

You will have a multiple file outputs:
- `efficient_addresses.{contract_name}.txt` contains the addresses that are gas efficient for the given contract name
- `address_per_contracts.txt` contains the final output of all the addresses found for each contract


For each efficient address found, the salt, resultant addresses, and value *(i.e. approximate rarity)* will be written to `efficient_addresses.txt`. Verify that one of the salts actually results in the intended address before getting in too deep - ideally, the CREATE2 factory will have a view method for checking what address you'll get for submitting a particular salt. Be sure not to change the factory address or the init code without first removing any existing data to prevent the two salt types from becoming commingled. There's also a *very* simple monitoring tool available if you run `$python3 analysis.py` in another tab.

This tool was originally built for use with [`Pr000xy`](https://github.com/0age/Pr000xy), including with [`Create2Factory`](https://github.com/0age/Pr000xy/blob/master/contracts/Create2Factory.sol) directly.
Expand Down
26 changes: 26 additions & 0 deletions config.example.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Directory containing the creation code of the contracts
bin_folder = "./bin"

# Address of the factory contract
factory_address = "0x4e59b44847b379578588920cA78FbF26c0B4956C"

# Address of the wallet that will call the contracts
calling_address = "0xaE4e57b886541829BA70eFC84340653c41e2908C"

# GPU device to use (none or 255 for cpu usage)
gpu_device = 0

# First target
[[targets]]
# Name of the contract in the bin folder
name = "contract1.bin"
# Meaning that other bin with the placeholder `${ROOT_CONTRACT}` will be replaced with the computed address of this contract
placeholder_name = "ROOT_CONTRACT"
# Stop threshold for this contract, once an address match either of this target it will stop and move on to the next target
stop_thresholds = { leading_zeroes = 3, total_zeroes = 5 }

# Second target
[[targets]]
# Since `contract1` export the `ROOT_CONTRACT` placeholder, this target can contain a `${ROOT_CONTRACT}` arguments in it's bin
name = "contract2.bin"
stop_thresholds = { leading_zeroes = 3, total_zeroes = 5 }
114 changes: 114 additions & 0 deletions src/config_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use alloy_primitives::hex;

use crate::RunConfig;

/// Requires three hex-encoded arguments: the address of the contract that will
/// be calling CREATE2, the address of the caller of said contract *(assuming
/// the contract calling CREATE2 has frontrunning protection in place - if not
/// applicable to your use-case you can set it to the null address)*, and the
/// keccak-256 hash of the bytecode that is provided by the contract calling
/// CREATE2 that will be used to initialize the new contract. An additional set
/// of three optional values may be provided: a device to target for OpenCL GPU
/// search, a threshold for leading zeroes to search for, and a threshold for
/// total zeroes to search for.
pub struct CliArgsConfig {
pub factory_address: [u8; 20],
pub calling_address: [u8; 20],
pub init_code_hash: [u8; 32],
pub gpu_device: u8,
pub leading_zeroes_threshold: u8,
pub total_zeroes_threshold: u8,
}

/// Validate the provided arguments and construct the Config struct.
impl CliArgsConfig {
pub fn new(args: &[String]) -> Result<Self, &'static str> {
// get args, skipping first arg (program name)
let mut args_iter = args.iter();
args_iter.next();

let Some(factory_address_string) = args_iter.next() else {
return Err("didn't get a factory_address argument");
};
let Some(calling_address_string) = args_iter.next() else {
return Err("didn't get a calling_address argument");
};
let Some(init_code_hash_string) = args_iter.next() else {
return Err("didn't get an init_code_hash argument");
};

let gpu_device_string = match args_iter.next() {
Some(arg) => arg.clone(),
None => String::from("255"), // indicates that CPU will be used.
};
let leading_zeroes_threshold_string = match args_iter.next() {
Some(arg) => arg.clone(),
None => String::from("3"),
};
let total_zeroes_threshold_string = match args_iter.next() {
Some(arg) => arg.clone(),
None => String::from("5"),
};

// convert main arguments from hex string to vector of bytes
let Ok(factory_address_vec) = hex::decode(factory_address_string) else {
return Err("could not decode factory address argument");
};
let Ok(calling_address_vec) = hex::decode(calling_address_string) else {
return Err("could not decode calling address argument");
};
let Ok(init_code_hash_vec) = hex::decode(init_code_hash_string) else {
return Err("could not decode initialization code hash argument");
};

// convert from vector to fixed array
let Ok(factory_address) = factory_address_vec.try_into() else {
return Err("invalid length for factory address argument");
};
let Ok(calling_address) = calling_address_vec.try_into() else {
return Err("invalid length for calling address argument");
};
let Ok(init_code_hash) = init_code_hash_vec.try_into() else {
return Err("invalid length for initialization code hash argument");
};

// convert gpu arguments to u8 values
let Ok(gpu_device) = gpu_device_string.parse::<u8>() else {
return Err("invalid gpu device value");
};
let Ok(leading_zeroes_threshold) = leading_zeroes_threshold_string.parse::<u8>() else {
return Err("invalid leading zeroes threshold value supplied");
};
let Ok(total_zeroes_threshold) = total_zeroes_threshold_string.parse::<u8>() else {
return Err("invalid total zeroes threshold value supplied");
};

if leading_zeroes_threshold > 20 {
return Err("invalid value for leading zeroes threshold argument. (valid: 0..=20)");
}
if total_zeroes_threshold > 20 && total_zeroes_threshold != 255 {
return Err("invalid value for total zeroes threshold argument. (valid: 0..=20 | 255)");
}

Ok(Self {
factory_address,
calling_address,
init_code_hash,
gpu_device,
leading_zeroes_threshold,
total_zeroes_threshold,
})
}

// Map a cli args to a run config
pub fn to_run_config(&self) -> RunConfig {
RunConfig {
factory_address: self.factory_address,
calling_address: self.calling_address,
init_code_hash: self.init_code_hash,
leading_zeroes_threshold: self.leading_zeroes_threshold,
total_zeroes_threshold: self.total_zeroes_threshold,
early_stop: false,
}
}
}
Loading