mod types;
mod util;
use similar::ChangeTag;
use console::Style;
use clap::Parser;
use web3::types::Address;
use types::*;
use util::*;
#[tokio::main]
async fn main() {
let cmd_args = CommandlineArgs::parse();
if !is_address_simplified(&cmd_args.address1) {
eprintln!("Error: 1st address is malformed. Make sure to prefix with '0x' and has 40 characters in length (exclude `0x`).");
std::process::exit(1);
}
if !is_address_simplified(&cmd_args.address2) {
eprintln!("Error: 2nd address is malformed. Make sure to prefix with '0x' and has 40 characters in length (exclude `0x`).");
std::process::exit(1);
}
let chain_value = cmd_args.chain.to_lowercase();
let mut chain: Option<ChainType> = None;
if chain_value == "bsc" {
chain = Some(ChainType::BSC);
}
else if chain_value == "ethereum" {
chain = Some(ChainType::Ethereum);
}
else if chain_value == "polygon" {
chain = Some(ChainType::Polygon);
}
if chain.is_none() {
eprintln!("Error unexpected thing happen affecting us not to determine which chain to operate on");
std::process::exit(1);
}
let web3 = create_web3(chain.unwrap());
let contract1_hexbytes_decoded = match hex::decode(&cmd_args.address1[2..]) {
Ok(res) => res,
Err(e) => {
eprintln!("Error: hex decoding of 1st address; err={}", e);
std::process::exit(1);
},
};
let contract1_code_fut = web3.eth().code(Address::from_slice(contract1_hexbytes_decoded.as_slice()), None);
let contract2_hexbytes_decoded = match hex::decode(&cmd_args.address2[2..]) {
Ok(res) => res,
Err(e) => {
eprintln!("Error: hex decoding of 2nd address; err={}", e);
std::process::exit(1);
},
};
let contract2_code_fut = web3.eth().code(Address::from_slice(contract2_hexbytes_decoded.as_slice()), None);
let (c1_code_res, c2_code_res) = futures::join!(contract1_code_fut, contract2_code_fut);
let c1_code_bytes = match c1_code_res {
Ok(res) => res,
Err(e) => {
eprintln!("Error: awaiting result for 1st address {}", e);
std::process::exit(1);
},
};
let c2_code_bytes = match c2_code_res {
Ok(res) => res,
Err(e) => {
eprintln!("Error: awaiting result for 2nd address {}", e);
std::process::exit(1);
},
};
let c1_code_hex_str = hex::encode(c1_code_bytes.0.as_slice());
let c2_code_hex_str = hex::encode(c2_code_bytes.0.as_slice());
if c1_code_hex_str.len() == 0 {
eprintln!("Error: 1st address is **not** a contract address.");
std::process::exit(1);
}
if c2_code_hex_str.len() == 0 {
eprintln!("Error: 2nd address is **not** a contract address.");
std::process::exit(1);
}
let diffs = similar::utils::diff_chars(similar::Algorithm::Myers, &c1_code_hex_str, &c2_code_hex_str);
for ch in diffs {
let (val, print_style) = match ch.0 {
ChangeTag::Equal => (ch.1, Style::new().dim()), ChangeTag::Delete => (ch.1, Style::new().red()),
ChangeTag::Insert => (ch.1, Style::new().green()),
};
print!("{}", print_style.apply_to(val));
}
println!("");
}