Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
89422d5
Simple REVM test runner (#788)
onbjerg Feb 22, 2022
c1046ae
REVM fuzzer (#789)
onbjerg Feb 23, 2022
9d82a78
REVM cheatcodes (#841)
onbjerg Mar 8, 2022
8933219
feat(revm): add forking mode (#835)
gakonst Mar 8, 2022
04892dd
chore: fmt
onbjerg Mar 12, 2022
1e88070
REVM tracing and gas reports (#867)
onbjerg Mar 13, 2022
90a6aaf
REVM debugger (#920)
onbjerg Mar 15, 2022
da67116
feat: support hardhat artifacts in `vm.getCode` (#956)
onbjerg Mar 17, 2022
a6a56d2
REVM: FFI cheatcode updates (#955)
onbjerg Mar 17, 2022
39d5a34
REVM gas fixes (#950)
onbjerg Mar 17, 2022
bd04c19
REVM: Pull EVM executor into own crate (#961)
onbjerg Mar 17, 2022
1e635fd
feat: better ux for expect revert without reason (#962)
onbjerg Mar 17, 2022
043e895
Cross-crate testdata (#965)
onbjerg Mar 17, 2022
2dafb3e
fix: fix prank cheatcode (#973)
onbjerg Mar 17, 2022
1d1afc5
fix: prank depth math
onbjerg Mar 17, 2022
76585d3
test: fix lib linking test
onbjerg Mar 17, 2022
016df8d
refactor: use revm `log` hook (#984)
onbjerg Mar 20, 2022
ad082a8
test: add lil-web3 to integration tests
gakonst Mar 20, 2022
b672c91
test: add maple labs loans to integration tests
onbjerg Mar 21, 2022
2837663
REVM fuzz dictionary (#985)
onbjerg Mar 21, 2022
88abbe9
feat(cli): Refactor cli/cmd over forge and cast (#1009)
refcell Mar 22, 2022
899f856
REVM: Support cheatcodes in `setUp` (#997)
onbjerg Mar 22, 2022
dc32546
test: explain why git clone failed
onbjerg Mar 22, 2022
fa37be2
test: disable maple-labs/loan
onbjerg Mar 22, 2022
ff83f81
refactor: make addresses statics instead of lazies
onbjerg Mar 22, 2022
ac66716
docs: fix console address comment
onbjerg Mar 22, 2022
7263f10
refactor: make `DUMMY_CREATE_ADDRESS` a static
onbjerg Mar 22, 2022
47e2695
chore: minor nits
onbjerg Mar 22, 2022
c2f15ae
refactor: move inspector state collection
onbjerg Mar 22, 2022
f3f43ad
fix: report correct fuzz failure case (#1017)
onbjerg Mar 22, 2022
89459a6
feat: add support for storage caching (#1006)
mattsse Mar 22, 2022
71cd0e9
fix: default to 80m gas
onbjerg Mar 22, 2022
bd7fc8d
fix(evm): gracefully shutdown backendhandler (#1021)
mattsse Mar 22, 2022
b6240b2
feat(evm/cache): improve json file caching (#1025)
mattsse Mar 23, 2022
91879d3
release: 0.2.0
gakonst Mar 23, 2022
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
419 changes: 128 additions & 291 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 2 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
[workspace]
members = [
"evm-adapters",
"utils",
"cast",
"forge",
"cli",
"cli/test-utils",
"config",
"fmt",
"ui",
"evm"
]

# Binary size optimizations
Expand All @@ -18,11 +19,6 @@ codegen-units = 1
panic = "abort"
debug = true

## Patch sputnik with more recent primitive types
# https://github.com/rust-blockchain/evm/pulls
[patch."https://github.com/rust-blockchain/evm"]
evm = { git = "https://github.com/gakonst/evm", branch = "bump-primitive-types" }

## Patch ethers-rs with a local checkout then run `cargo update -p ethers`
#[patch."https://github.com/gakonst/ethers-rs"]
#ethers = { path = "../ethers-rs" }
Expand Down
2 changes: 1 addition & 1 deletion cast/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cast"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
license = "MIT OR Apache-2.0"

Expand Down
17 changes: 4 additions & 13 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "foundry-cli"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
license = "MIT OR Apache-2.0"

Expand All @@ -26,7 +26,6 @@ foundry-utils = { path = "../utils" }
forge = { path = "../forge" }
foundry-config = { path = "../config" }
cast = { path = "../cast" }
evm-adapters = { path = "../evm-adapters" }
ui = { path = "../ui" }
dunce = "1.0.2"
# ethers = "0.5"
Expand All @@ -39,16 +38,14 @@ tokio = { version = "1.11.0", features = ["macros"] }
regex = { version = "1.5.4", default-features = false }
ansi_term = "0.12.1"
rpassword = "5.0.1"
tracing-subscriber = "0.2.20"
tracing-error = "0.2.0"
tracing-subscriber = { version = "0.3", features = ["registry", "env-filter", "fmt"] }
tracing = "0.1.26"
hex = "0.4.3"
rayon = "1.5.1"
serde = "1.0.133"
futures = "0.3.17"

## EVM Implementations
# evm = { version = "0.30.1" }
sputnik = { package = "evm", git = "https://github.com/rust-blockchain/evm", default-features = false, features = ["std"], optional = true }
proptest = "1.0.0"
glob = "0.3.0"
semver = "1.0.5"
Expand All @@ -68,17 +65,11 @@ pretty_assertions = "1.0.0"
toml = "0.5"

[features]
default = ["sputnik-evm", "rustls"]
default = ["rustls"]
solc-asm = ["ethers/solc-sha2-asm"]
rustls = ["ethers/rustls"]
openssl = ["ethers/openssl"]

sputnik-evm = [
"sputnik",
"evm-adapters/sputnik",
"evm-adapters/sputnik-helpers",
]

integration-tests = []

[[bin]]
Expand Down
64 changes: 3 additions & 61 deletions cli/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use ethers::{
},
providers::{Middleware, Provider},
signers::{LocalWallet, Signer},
types::{Address, Chain, NameOrAddress, Signature, U256, U64},
types::{Address, Chain, NameOrAddress, Signature, U256},
utils::get_contract_address,
};
use opts::{
Expand All @@ -36,9 +36,8 @@ use std::{
use clap::{IntoApp, Parser};
use clap_complete::generate;

use crate::utils::read_secret;
use crate::{cmd::Cmd, utils::read_secret};
use eyre::WrapErr;
use futures::join;

#[tokio::main]
async fn main() -> eyre::Result<()> {
Expand Down Expand Up @@ -542,64 +541,7 @@ async fn main() -> eyre::Result<()> {
let selector = contract.abi().functions().last().unwrap().short_signature();
println!("0x{}", hex::encode(selector));
}
Subcommands::FindBlock { timestamp, rpc_url } => {
let ts_target = U256::from(timestamp);
let provider = Provider::try_from(rpc_url)?;
let last_block_num = provider.get_block_number().await?;
let cast_provider = Cast::new(provider);

let res = join!(cast_provider.timestamp(last_block_num), cast_provider.timestamp(1));
let ts_block_latest = res.0.unwrap();
let ts_block_1 = res.1.unwrap();

let block_num = if ts_block_latest.lt(&ts_target) {
// If the most recent block's timestamp is below the target, return it
last_block_num
} else if ts_block_1.gt(&ts_target) {
// If the target timestamp is below block 1's timestamp, return that
U64::from(1)
} else {
// Otherwise, find the block that is closest to the timestamp
let mut low_block = U64::from(1); // block 0 has a timestamp of 0: https://github.com/ethereum/go-ethereum/issues/17042#issuecomment-559414137
let mut high_block = last_block_num;
let mut matching_block: Option<U64> = None;
while high_block.gt(&low_block) && matching_block.is_none() {
// Get timestamp of middle block (this approach approach to avoids overflow)
let high_minus_low_over_2 = high_block
.checked_sub(low_block)
.ok_or_else(|| eyre::eyre!("unexpected underflow"))
.unwrap()
.checked_div(U64::from(2))
.unwrap();
let mid_block = high_block.checked_sub(high_minus_low_over_2).unwrap();
let ts_mid_block = cast_provider.timestamp(mid_block).await?;

// Check if we've found a match or should keep searching
if ts_mid_block.eq(&ts_target) {
matching_block = Some(mid_block)
} else if high_block.checked_sub(low_block).unwrap().eq(&U64::from(1)) {
// The target timestamp is in between these blocks. This rounds to the
// highest block if timestamp is equidistant between blocks
let res = join!(
cast_provider.timestamp(high_block),
cast_provider.timestamp(low_block)
);
let ts_high = res.0.unwrap();
let ts_low = res.1.unwrap();
let high_diff = ts_high.checked_sub(ts_target).unwrap();
let low_diff = ts_target.checked_sub(ts_low).unwrap();
let is_low = low_diff.lt(&high_diff);
matching_block = if is_low { Some(low_block) } else { Some(high_block) }
} else if ts_mid_block.lt(&ts_target) {
low_block = mid_block;
} else {
high_block = mid_block;
}
}
matching_block.unwrap_or(low_block)
};
println!("{}", block_num);
}
Subcommands::FindBlock(cmd) => cmd.run()?,
Subcommands::Wallet { command } => match command {
WalletSubcommands::New { path, password, unsafe_password } => {
let mut rng = thread_rng();
Expand Down
90 changes: 90 additions & 0 deletions cli/src/cmd/cast/find_block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//! cast find-block subcommand

use crate::cmd::Cmd;
use cast::Cast;
use clap::Parser;
use ethers::prelude::*;
use eyre::Result;
use futures::join;

#[derive(Debug, Clone, Parser)]
pub struct FindBlockArgs {
#[clap(help = "The UNIX timestamp to search for (in seconds)")]
timestamp: u64,
#[clap(long, env = "ETH_RPC_URL")]
rpc_url: String,
}

impl Cmd for FindBlockArgs {
type Output = ();

fn run(self) -> Result<Self::Output> {
let FindBlockArgs { timestamp, rpc_url } = self;
let rt = tokio::runtime::Runtime::new().expect("could not start tokio rt");
rt.block_on(Self::query_block(timestamp, rpc_url))?;
Ok(())
}
}

impl FindBlockArgs {
async fn query_block(timestamp: u64, rpc_url: String) -> Result<()> {
let ts_target = U256::from(timestamp);
let provider = Provider::try_from(rpc_url)?;
let last_block_num = provider.get_block_number().await?;
let cast_provider = Cast::new(provider);

let res = join!(cast_provider.timestamp(last_block_num), cast_provider.timestamp(1));
let ts_block_latest = res.0.unwrap();
let ts_block_1 = res.1.unwrap();

let block_num = if ts_block_latest.lt(&ts_target) {
// If the most recent block's timestamp is below the target, return it
last_block_num
} else if ts_block_1.gt(&ts_target) {
// If the target timestamp is below block 1's timestamp, return that
U64::from(1_u64)
} else {
// Otherwise, find the block that is closest to the timestamp
let mut low_block = U64::from(1_u64); // block 0 has a timestamp of 0: https://github.com/ethereum/go-ethereum/issues/17042#issuecomment-559414137
let mut high_block = last_block_num;
let mut matching_block: Option<U64> = None;
while high_block.gt(&low_block) && matching_block.is_none() {
// Get timestamp of middle block (this approach approach to avoids overflow)
let high_minus_low_over_2 = high_block
.checked_sub(low_block)
.ok_or_else(|| eyre::eyre!("unexpected underflow"))
.unwrap()
.checked_div(U64::from(2_u64))
.unwrap();
let mid_block = high_block.checked_sub(high_minus_low_over_2).unwrap();
let ts_mid_block = cast_provider.timestamp(mid_block).await?;

// Check if we've found a match or should keep searching
if ts_mid_block.eq(&ts_target) {
matching_block = Some(mid_block)
} else if high_block.checked_sub(low_block).unwrap().eq(&U64::from(1_u64)) {
// The target timestamp is in between these blocks. This rounds to the
// highest block if timestamp is equidistant between blocks
let res = join!(
cast_provider.timestamp(high_block),
cast_provider.timestamp(low_block)
);
let ts_high = res.0.unwrap();
let ts_low = res.1.unwrap();
let high_diff = ts_high.checked_sub(ts_target).unwrap();
let low_diff = ts_target.checked_sub(ts_low).unwrap();
let is_low = low_diff.lt(&high_diff);
matching_block = if is_low { Some(low_block) } else { Some(high_block) }
} else if ts_mid_block.lt(&ts_target) {
low_block = mid_block;
} else {
high_block = mid_block;
}
}
matching_block.unwrap_or(low_block)
};
println!("{}", block_num);

Ok(())
}
}
8 changes: 8 additions & 0 deletions cli/src/cmd/cast/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//! Subcommands for cast
//!
//! All subcommands should respect the `foundry_config::Config`.
//! If a subcommand accepts values that are supported by the `Config`, then the subcommand should
//! implement `figment::Provider` which allows the subcommand to override the config's defaults, see
//! [`foundry_config::Config`].

pub mod find_block;
2 changes: 1 addition & 1 deletion cli/src/cmd/bind.rs → cli/src/cmd/forge/bind.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::cmd::Cmd;
use crate::cmd::utils::Cmd;

use clap::{Parser, ValueHint};
use ethers::contract::MultiAbigen;
Expand Down
6 changes: 3 additions & 3 deletions cli/src/cmd/build.rs → cli/src/cmd/forge/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::path::PathBuf;

use crate::{cmd::Cmd, opts::forge::CompilerArgs};

use crate::cmd::watch::WatchArgs;
use crate::cmd::forge::watch::WatchArgs;
use clap::{Parser, ValueHint};
use ethers::solc::remappings::Remapping;
use foundry_config::{
Expand Down Expand Up @@ -191,7 +191,7 @@ impl Cmd for BuildArgs {
type Output = ProjectCompileOutput;
fn run(self) -> eyre::Result<Self::Output> {
let project = self.project()?;
super::compile(&project, self.names, self.sizes)
crate::cmd::utils::compile(&project, self.names, self.sizes)
}
}

Expand All @@ -214,7 +214,7 @@ impl BuildArgs {
/// Returns the [`watchexec::InitConfig`] and [`watchexec::RuntimeConfig`] necessary to
/// bootstrap a new [`watchexe::Watchexec`] loop.
pub(crate) fn watchexec_config(&self) -> eyre::Result<(InitConfig, RuntimeConfig)> {
use crate::cmd::watch;
use crate::cmd::forge::watch;
let init = watch::init()?;
let mut runtime = watch::runtime(&self.watch)?;

Expand Down
2 changes: 1 addition & 1 deletion cli/src/cmd/config.rs → cli/src/cmd/forge/config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! config command

use crate::{
cmd::{build::BuildArgs, Cmd},
cmd::{forge::build::BuildArgs, utils::Cmd},
opts::evm::EvmArgs,
};
use clap::Parser;
Expand Down
7 changes: 4 additions & 3 deletions cli/src/cmd/create.rs → cli/src/cmd/forge/create.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Create command

use crate::{
cmd::{build::BuildArgs, Cmd},
cmd::{forge::build::BuildArgs, Cmd},
opts::{EthereumOpts, WalletType},
utils::parse_u256,
};
Expand Down Expand Up @@ -70,10 +70,11 @@ impl Cmd for CreateArgs {
fn run(self) -> Result<Self::Output> {
// Find Project & Compile
let project = self.opts.project()?;
let compiled = super::compile(&project, self.opts.names, self.opts.sizes)?;
let compiled = crate::cmd::utils::compile(&project, self.opts.names, self.opts.sizes)?;

// Get ABI and BIN
let (abi, bin, _) = super::read_artifact(&project, compiled, self.contract.clone())?;
let (abi, bin, _) =
crate::cmd::utils::read_artifact(&project, compiled, self.contract.clone())?;

let bin = match bin.object {
BytecodeObject::Bytecode(_) => bin.object,
Expand Down
2 changes: 1 addition & 1 deletion cli/src/cmd/flatten.rs → cli/src/cmd/forge/flatten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::path::PathBuf;

use ethers::solc::remappings::Remapping;

use crate::cmd::{build::BuildArgs, Cmd};
use crate::cmd::{forge::build::BuildArgs, Cmd};
use clap::{Parser, ValueHint};
use foundry_config::Config;

Expand Down
File renamed without changes.
13 changes: 8 additions & 5 deletions cli/src/cmd/init.rs → cli/src/cmd/forge/init.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//! init command

use crate::{
cmd::{install::install, Cmd},
cmd::{forge::install::install, Cmd},
opts::forge::Dependency,
utils::p_println,
};
use clap::{Parser, ValueHint};
use foundry_config::Config;

use crate::cmd::{install::DependencyInstallOpts, remappings};
use crate::cmd::forge::{install::DependencyInstallOpts, remappings};
use ansi_term::Colour;
use ethers::solc::remappings::Remapping;
use std::{
Expand Down Expand Up @@ -102,10 +102,13 @@ impl Cmd for InitArgs {

// write the contract file
let contract_path = src.join("Contract.sol");
std::fs::write(contract_path, include_str!("../../../assets/ContractTemplate.sol"))?;
std::fs::write(contract_path, include_str!("../../../../assets/ContractTemplate.sol"))?;
// write the tests
let contract_path = test.join("Contract.t.sol");
std::fs::write(contract_path, include_str!("../../../assets/ContractTemplate.t.sol"))?;
std::fs::write(
contract_path,
include_str!("../../../../assets/ContractTemplate.t.sol"),
)?;

let dest = root.join(Config::FILE_NAME);
if !dest.exists() {
Expand Down Expand Up @@ -159,7 +162,7 @@ fn init_git_repo(root: &Path, no_commit: bool) -> eyre::Result<()> {

if !is_git.success() {
let gitignore_path = root.join(".gitignore");
std::fs::write(gitignore_path, include_str!("../../../assets/.gitignoreTemplate"))?;
std::fs::write(gitignore_path, include_str!("../../../../assets/.gitignoreTemplate"))?;

Command::new("git")
.arg("init")
Expand Down
Loading