Skip to content

Commit a3f530f

Browse files
committed
Merge remote-tracking branch 'origin/master' into brock/scripting
2 parents 2762ce7 + 4b5aea9 commit a3f530f

16 files changed

+986
-331
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ similar = { version = "2.1.0", features = ["inline"] }
7272
strsim = "0.10.0"
7373
bytes = "1.1.0"
7474
strum = { version = "0.24", features = ["derive"] }
75-
reqwest = { version = "0.11.8", default-features = false, features = ["json"] }
7675

7776
[dev-dependencies]
7877
anvil = { path = "../anvil" }

cli/src/cast.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ use crate::{
4343
utils::{consume_config_rpc_url, read_secret},
4444
};
4545
use eyre::WrapErr;
46+
use foundry_utils::{
47+
format_tokens,
48+
selectors::{
49+
decode_calldata, decode_event_topic, decode_function_selector, import_selectors,
50+
parse_signatures, pretty_calldata, ParsedSignatures, SelectorImportData,
51+
},
52+
};
4653

4754
#[tokio::main]
4855
async fn main() -> eyre::Result<()> {
@@ -414,12 +421,12 @@ async fn main() -> eyre::Result<()> {
414421
}
415422
Subcommands::CalldataDecode { sig, calldata } => {
416423
let tokens = SimpleCast::abi_decode(&sig, &calldata, true)?;
417-
let tokens = foundry_utils::format_tokens(&tokens);
424+
let tokens = format_tokens(&tokens);
418425
tokens.for_each(|t| println!("{t}"));
419426
}
420427
Subcommands::AbiDecode { sig, calldata, input } => {
421428
let tokens = SimpleCast::abi_decode(&sig, &calldata, input)?;
422-
let tokens = foundry_utils::format_tokens(&tokens);
429+
let tokens = format_tokens(&tokens);
423430
tokens.for_each(|t| println!("{t}"));
424431
}
425432
Subcommands::AbiEncode { sig, args } => {
@@ -430,11 +437,11 @@ async fn main() -> eyre::Result<()> {
430437
println!("{encoded}");
431438
}
432439
Subcommands::FourByte { selector } => {
433-
let sigs = foundry_utils::decode_function_selector(&selector).await?;
440+
let sigs = decode_function_selector(&selector).await?;
434441
sigs.iter().for_each(|sig| println!("{}", sig));
435442
}
436443
Subcommands::FourByteDecode { calldata } => {
437-
let sigs = foundry_utils::decode_calldata(&calldata).await?;
444+
let sigs = decode_calldata(&calldata).await?;
438445
sigs.iter().enumerate().for_each(|(i, sig)| println!("{}) \"{}\"", i + 1, sig));
439446

440447
let sig = match sigs.len() {
@@ -451,21 +458,31 @@ async fn main() -> eyre::Result<()> {
451458
}?;
452459

453460
let tokens = SimpleCast::abi_decode(sig, &calldata, true)?;
454-
let tokens = foundry_utils::format_tokens(&tokens);
461+
let tokens = format_tokens(&tokens);
455462

456463
tokens.for_each(|t| println!("{t}"));
457464
}
458465
Subcommands::FourByteEvent { topic } => {
459-
let sigs = foundry_utils::decode_event_topic(&topic).await?;
466+
let sigs = decode_event_topic(&topic).await?;
460467
sigs.iter().for_each(|sig| println!("{}", sig));
461468
}
462469

470+
Subcommands::UploadSignature { signatures } => {
471+
let ParsedSignatures { signatures, abis } = parse_signatures(signatures);
472+
if !abis.is_empty() {
473+
import_selectors(SelectorImportData::Abi(abis)).await?.describe();
474+
}
475+
if !signatures.is_empty() {
476+
import_selectors(SelectorImportData::Raw(signatures)).await?.describe();
477+
}
478+
}
479+
463480
Subcommands::PrettyCalldata { calldata, offline } => {
464481
if !calldata.starts_with("0x") {
465482
eprintln!("Expected calldata hex string, received \"{calldata}\"");
466483
std::process::exit(0)
467484
}
468-
let pretty_data = foundry_utils::pretty_calldata(&calldata, offline).await?;
485+
let pretty_data = pretty_calldata(&calldata, offline).await?;
469486
println!("{pretty_data}");
470487
}
471488
Subcommands::Age { block, rpc_url } => {

cli/src/cmd/forge/fourbyte.rs

Lines changed: 7 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,8 @@ use crate::{
44
opts::forge::CompilerArgs,
55
};
66
use clap::Parser;
7-
use ethers::prelude::artifacts::{output_selection::ContractOutputSelection, LosslessAbi};
8-
use serde::{Deserialize, Serialize};
9-
use std::collections::HashMap;
10-
use tracing::trace;
11-
12-
static SELECTOR_DATABASE_URL: &str = "https://sig.eth.samczsun.com/api/v1/import";
7+
use ethers::prelude::artifacts::output_selection::ContractOutputSelection;
8+
use foundry_utils::selectors::{import_selectors, SelectorImportData};
139

1410
#[derive(Debug, Clone, Parser)]
1511
pub struct UploadSelectorsArgs {
@@ -34,79 +30,21 @@ impl UploadSelectorsArgs {
3430
..Default::default()
3531
};
3632

37-
trace!("Building project");
3833
let project = build_args.project()?;
3934
let outcome = compile::suppress_compile(&project)?;
4035
let found_artifact = outcome.find(&contract);
4136
let artifact = found_artifact.ok_or_else(|| {
4237
eyre::eyre!("Could not find artifact `{contract}` in the compiled artifacts")
4338
})?;
4439

45-
let body = ImportRequest {
46-
import_type: "abi".to_string(),
47-
data: vec![artifact.abi.clone().ok_or(eyre::eyre!("Unable to fetch abi"))?],
48-
};
40+
let import_data = SelectorImportData::Abi(vec![artifact
41+
.abi
42+
.clone()
43+
.ok_or(eyre::eyre!("Unable to fetch abi"))?]);
4944

5045
// upload abi to selector database
51-
trace!("Uploading selector args {:?}", body);
52-
let res: ImportResponse = reqwest::Client::new()
53-
.post(SELECTOR_DATABASE_URL)
54-
.json(&body)
55-
.send()
56-
.await?
57-
.json()
58-
.await?;
59-
trace!("Got response: {:?}", res);
60-
res.describe_upload();
46+
import_selectors(import_data).await?.describe();
6147

6248
Ok(())
6349
}
6450
}
65-
66-
#[derive(Serialize, Debug)]
67-
struct ImportRequest {
68-
#[serde(rename = "type")]
69-
import_type: String,
70-
data: Vec<LosslessAbi>,
71-
}
72-
73-
#[derive(Deserialize, Debug)]
74-
struct ImportTypeData {
75-
imported: HashMap<String, String>,
76-
duplicated: HashMap<String, String>,
77-
}
78-
79-
#[derive(Deserialize, Debug)]
80-
struct ImportData {
81-
function: ImportTypeData,
82-
event: ImportTypeData,
83-
}
84-
85-
#[derive(Deserialize, Debug)]
86-
struct ImportResponse {
87-
result: ImportData,
88-
}
89-
90-
impl ImportResponse {
91-
/// Print info about the functions which were uploaded or already known
92-
pub fn describe_upload(&self) {
93-
self.result
94-
.function
95-
.imported
96-
.iter()
97-
.for_each(|(k, v)| println!("Imported: Function {k}: {v}"));
98-
self.result.event.imported.iter().for_each(|(k, v)| println!("Imported: Event {k}: {v}"));
99-
self.result
100-
.function
101-
.duplicated
102-
.iter()
103-
.for_each(|(k, v)| println!("Duplicated: Function {k}: {v}"));
104-
self.result
105-
.event
106-
.duplicated
107-
.iter()
108-
.for_each(|(k, v)| println!("Duplicated: Event {k}: {v}"));
109-
110-
println!("Selectors successfully uploaded to https://sig.eth.samczsun.com");
111-
}
112-
}

cli/src/cmd/forge/install.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ fn install_as_submodule(
141141
target_dir: &str,
142142
no_commit: bool,
143143
) -> eyre::Result<()> {
144+
if !no_commit && !git_status_clean()? {
145+
eyre::bail!("There are changes in your working/staging area. Commit them first or add the `--no-commit` option.")
146+
}
147+
144148
// install the dep
145149
git_submodule(dep, libs, target_dir)?;
146150

@@ -168,6 +172,21 @@ fn install_as_submodule(
168172
Ok(())
169173
}
170174

175+
// check that there are no modification in git working/staging area
176+
fn git_status_clean() -> eyre::Result<bool> {
177+
let output = Command::new("git")
178+
.args(&["status", "--short"])
179+
.stdout(Stdio::piped())
180+
.stderr(Stdio::piped())
181+
.output()?;
182+
if !&output.status.success() {
183+
let stderr = String::from_utf8_lossy(&output.stderr);
184+
eyre::bail!("{}", stderr.trim())
185+
}
186+
let stdout = String::from_utf8_lossy(&output.stdout);
187+
Ok(stdout.trim().is_empty())
188+
}
189+
171190
fn git_clone(dep: &Dependency, libs: &Path, target_dir: &str) -> eyre::Result<()> {
172191
let url = dep.url.as_ref().unwrap();
173192

cli/src/opts/cast.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -424,37 +424,57 @@ Defaults to decoding output data. To decode input data pass --input or use cast
424424
},
425425
#[clap(name = "4byte")]
426426
#[clap(aliases = &["4", "4b"])]
427-
#[clap(about = "Get the function signatures for the given selector from 4byte.directory.")]
427+
#[clap(
428+
about = "Get the function signatures for the given selector from https://sig.eth.samczsun.com."
429+
)]
428430
FourByte {
429431
#[clap(help = "The function selector.")]
430432
selector: String,
431433
},
432434
#[clap(name = "4byte-decode")]
433435
#[clap(aliases = &["4d", "4bd"])]
434-
#[clap(about = "Decode ABI-encoded calldata using 4byte.directory.")]
436+
#[clap(about = "Decode ABI-encoded calldata using https://sig.eth.samczsun.com.")]
435437
FourByteDecode {
436438
#[clap(help = "The ABI-encoded calldata.")]
437439
calldata: String,
438440
},
439441
#[clap(name = "4byte-event")]
440442
#[clap(aliases = &["4e", "4be"])]
441-
#[clap(about = "Get the event signature for a given topic 0 from 4byte.directory.")]
443+
#[clap(
444+
about = "Get the event signature for a given topic 0 from https://sig.eth.samczsun.com."
445+
)]
442446
FourByteEvent {
443447
#[clap(help = "Topic 0", value_name = "TOPIC_0")]
444448
topic: String,
445449
},
450+
#[clap(name = "upload-signature")]
451+
#[clap(aliases = &["ups"])]
452+
#[clap(about = r#"Upload the given signatures to https://sig.eth.samczsun.com.
453+
454+
Examples:
455+
- cast upload-signature "transfer(address,uint256)"
456+
- cast upload-signature "function transfer(address,uint256)"
457+
- cast upload-signature "function transfer(address,uint256)" "event Transfer(address,address,uint256)"
458+
- cast upload-signature ./out/Contract.sol/Contract.json
459+
"#)]
460+
UploadSignature {
461+
#[clap(
462+
help = "The signatures to upload. Prefix with 'function', 'event', or 'error'. Defaults to function if no prefix given. Can also take paths to contract artifact JSON."
463+
)]
464+
signatures: Vec<String>,
465+
},
446466
#[clap(name = "pretty-calldata")]
447467
#[clap(alias = "pc")]
448468
#[clap(
449469
about = "Pretty print calldata.",
450470
long_about = r#"Pretty print calldata.
451471
452-
Tries to decode the calldata using 4byte.directory unless --offline is passed."#
472+
Tries to decode the calldata using https://sig.eth.samczsun.com unless --offline is passed."#
453473
)]
454474
PrettyCalldata {
455475
#[clap(help = "The calldata.")]
456476
calldata: String,
457-
#[clap(long, short, help = "Skip the 4byte directory lookup.")]
477+
#[clap(long, short, help = "Skip the https://sig.eth.samczsun.com lookup.")]
458478
offline: bool,
459479
},
460480
#[clap(name = "age")]

0 commit comments

Comments
 (0)