Skip to content

Commit

Permalink
feat: add upload selectors command to forge
Browse files Browse the repository at this point in the history
This commit adds a new command to forge to upload a contract's abi to
sig.eth.samczsun.com selector database
  • Loading branch information
marktoda committed May 20, 2022
1 parent 1f5e4b6 commit a375ef8
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ similar = { version = "2.1.0", features = ["inline"] }
strsim = "0.10.0"
bytes = "1.1.0"
strum = { version = "0.24", features = ["derive"] }
reqwest = { version = "0.11.8", default-features = false, features = ["json"] }

[dev-dependencies]
foundry-utils = { path = "./../utils", features = ["test"] }
Expand Down
113 changes: 113 additions & 0 deletions cli/src/cmd/forge/fourbyte.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use crate::{
cmd::forge::build::{CoreBuildArgs, ProjectPathsArgs},
compile,
opts::forge::CompilerArgs,
};
use clap::Parser;
use ethers::prelude::artifacts::{output_selection::ContractOutputSelection, LosslessAbi};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use tracing::trace;

#[derive(Serialize, Debug)]
struct ImportRequest {
#[serde(rename = "type")]
import_type: String,
data: Vec<LosslessAbi>,
}

#[derive(Deserialize, Debug)]
struct ImportTypeData {
imported: HashMap<String, String>,
duplicated: HashMap<String, String>,
}

#[derive(Deserialize, Debug)]
struct ImportData {
function: ImportTypeData,
event: ImportTypeData,
}

#[derive(Deserialize, Debug)]
struct ImportResponse {
result: ImportData,
}

#[derive(Debug, Clone, Parser)]
pub struct UploadSelectorsArgs {
#[clap(help = "The name of the contract to upload selectors for.")]
pub contract: String,

#[clap(flatten, next_help_heading = "PROJECT OPTIONS")]
pub project_paths: ProjectPathsArgs,
}

impl UploadSelectorsArgs {
/// Builds a contract and uploads the ABI to selector database
pub async fn run(self) -> eyre::Result<()> {
let UploadSelectorsArgs { contract, project_paths } = self;

let build_args = CoreBuildArgs {
project_paths: project_paths.clone(),
out_path: Default::default(),
ignored_error_codes: vec![],
no_auto_detect: false,
use_solc: None,
offline: false,
force: false,
libraries: vec![],
via_ir: false,
revert_strings: None,
compiler: CompilerArgs {
extra_output: vec![ContractOutputSelection::Abi],
..Default::default()
},
};

trace!("Building project");
let project = build_args.project()?;
let outcome = compile::suppress_compile(&project)?;
let found_artifact = outcome.find(&contract);
let artifact = found_artifact.ok_or_else(|| {
eyre::eyre!("Could not find artifact `{contract}` in the compiled artifacts")
})?;

let body = ImportRequest {
import_type: "abi".to_string(),
data: vec![artifact.abi.clone().ok_or(eyre::eyre!("Unable to fetch abi"))?],
};

// upload abi to selector database
trace!("Uploading selector args {:?}", body);
let res: ImportResponse = reqwest::Client::new()
.post("https://sig.eth.samczsun.com/api/v1/import")
.json(&body)
.send()
.await?
.json()
.await?;
trace!("Got response: {:?}", res);
describe_upload(res);

Ok(())
}
}

/// Print info about the functions which were uploaded or already known
fn describe_upload(response: ImportResponse) {
response.result.function.imported.iter().for_each(|(k, v)| {
println!("Imported: Function {k}: {v}")
});
response.result.event.imported.iter().for_each(|(k, v)| {
println!("Imported: Event {k}: {v}")
});
response.result.function.duplicated.iter().for_each(|(k, v)| {
println!(
"Duplicated: Function {k}: {v}")
});
response.result.event.duplicated.iter().for_each(|(k, v)| {
println!("Duplicated: Event {k}: {v}")
});

println!("Selectors successfully uploaded to https://sig.eth.samczsun.com");
}
1 change: 1 addition & 0 deletions cli/src/cmd/forge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub mod config;
pub mod create;
pub mod flatten;
// pub mod fmt;
pub mod fourbyte;
pub mod init;
pub mod inspect;
pub mod install;
Expand Down
3 changes: 3 additions & 0 deletions cli/src/forge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ fn main() -> eyre::Result<()> {
Subcommands::Inspect(cmd) => {
cmd.run()?;
}
Subcommands::UploadSelectors(args) => {
utils::block_on(args.run())?;
}
Subcommands::Tree(cmd) => {
cmd.run()?;
}
Expand Down
4 changes: 4 additions & 0 deletions cli/src/opts/forge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::cmd::forge::{
config,
create::CreateArgs,
flatten,
fourbyte::UploadSelectorsArgs,
init::InitArgs,
inspect,
install::InstallArgs,
Expand Down Expand Up @@ -143,6 +144,9 @@ pub enum Subcommands {
#[clap(alias = "in", about = "Get specialized information about a smart contract")]
Inspect(inspect::InspectArgs),

#[clap(alias = "up", about = "Uploads abi to sig.eth.samczsun.com function selector database")]
UploadSelectors(UploadSelectorsArgs),

#[clap(
alias = "tr",
about = "Display a tree visualization of the project's dependency graph."
Expand Down

0 comments on commit a375ef8

Please sign in to comment.