Skip to content

Commit

Permalink
EVM-IT: Check in generated ABI code.
Browse files Browse the repository at this point in the history
  • Loading branch information
aakoshh committed Jan 19, 2023
1 parent ddd68e1 commit f20de2f
Show file tree
Hide file tree
Showing 9 changed files with 349 additions and 46 deletions.
3 changes: 2 additions & 1 deletion 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 testing/integration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ fil_create_actor = { path = "tests/fil-create-actor" }
evm_contracts = { path = "tests/evm" }

actors-v10 = { package = "fil_builtin_actors_bundle", git = "https://github.com/filecoin-project/builtin-actors", branch = "next", features = ["m2-native"] }
fil_actor_evm = { package = "fil_actor_evm", git = "https://github.com/filecoin-project/builtin-actors", branch = "next", features = ["m2-native"] }


cucumber = "0.19"
ethers = { version = "1.0" }

[[test]]
name = "fevm" # The EVM tests are using Cucumber
Expand Down
4 changes: 2 additions & 2 deletions testing/integration/tests/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ edition = "2021"
publish = false

[dependencies]
fil_actor_evm = { package = "fil_actor_evm", git = "https://github.com/filecoin-project/builtin-actors", branch = "next", features = ["m2-native"] }
ethers = { version = "1.0", features = ["abigen"] }
ethers = { version = "1.0" }

[build-dependencies]
ethers = { version = "1.0", features = ["abigen"] }
ethers-core = "1.0"
ethers-solc = "1.0"
serde = "1.0"
Expand Down
63 changes: 56 additions & 7 deletions testing/integration/tests/evm/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ fn main() {
// It looks like it could write the ABI files with [ArtifactOutput::write_contract_extras],
// but the [ExtraOutputFiles] used by default doesn't write bytecode, so I stopped looking.

// NOTE: Only running on what changed.
// NOTE: Only running on what changed. If something changes here, either delete the artifacts first to force regeneration,
// or change the contract source, or change this line to include cached artifacts. The benefit of only working
// on changed artifacts is that it's faster and also that it won't do anything on CI, so it shouldn't need `solc`.
for (contract_path, artifacts) in output.compiled_artifacts() {
assert_eq!(1, artifacts.len());

Expand All @@ -50,18 +52,23 @@ fn main() {
let mk_path = |ext: &str| artifacts_dir.join(format!("{contract_name}.{ext}"));
let artifact = &artifacts[0].artifact;

let abi = artifact
.abi
.as_ref()
.expect("ABI is part of the default outputs");

// Export the bytecode as hex so we can load it into FEVM.
let bytecode = artifact
.bytecode
.as_ref()
.expect("Bytecode is part of the default outputs");

export_json(&mk_path("abi"), abi);
export_hex(&mk_path("hex"), bytecode.object.as_bytes().unwrap());

// Export the ABI as JSON so we can use `abigen!` to generate facades.
let abi = artifact
.abi
.as_ref()
.expect("ABI is part of the default outputs");

let abi_path = mk_path("abi");
export_json(&abi_path, abi);
generate_facade(&abi_path, contract_name);
}
}

Expand All @@ -84,3 +91,45 @@ fn export_str(path: &PathBuf, line: &str) {
let mut output = std::fs::File::create(path).unwrap();
writeln!(&mut output, "{line}").unwrap();
}

/// We can use `abigen!` in the code to create a contract facade on the fly like this:
///
/// ```ignore
/// abigen!(SimpleCoin, "./artifacts/SimpleCoin.sol/SimpleCoin.abi");
/// ```
///
/// However, it doesn't work well with Rust Analyzer (at least for me), often showing `{unknown}`
/// where you'd expect code completion.
///
/// Instead of that, we can actually generate all the Rust code and check it into git,
/// which makes it easier to see what's going on and works better in the editor as well.
fn generate_facade(abi_path: &PathBuf, contract_name: &str) {
ethers::prelude::Abigen::new(contract_name, abi_path.to_string_lossy())
.unwrap()
.generate()
.unwrap()
.write_to_file(format!("./src/{}.rs", camel_to_snake(contract_name)))
.unwrap();
}

/// Convert ContractName to contract_name so we can use it as a Rust module.
///
/// We could just lowercase, but this is what `Abigen` does as well, and it's more readable with complex names.
fn camel_to_snake(name: &str) -> String {
let mut out = String::new();
for (i, c) in name.chars().enumerate() {
match (i, c) {
(0, c) if c.is_uppercase() => {
out.push(c.to_ascii_lowercase());
}
(_, c) if c.is_uppercase() => {
out.push('_');
out.push(c.to_ascii_lowercase());
}
(_, c) => {
out.push(c);
}
}
}
out
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"files": {
"contracts/SimpleCoin.sol": {
"lastModificationDate": 1674050186018,
"lastModificationDate": 1674123287549,
"contentHash": "58aca481d2d1bc8153222e2af627229e",
"sourceName": "contracts/SimpleCoin.sol",
"solcConfig": {
Expand Down
26 changes: 1 addition & 25 deletions testing/integration/tests/evm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1 @@
pub mod simplecoin;

/// Create a `new` method in a module with a smart contract.
///
/// # Example
///
/// ```ignore
/// abigen!(SimpleCoin, "./artifacts/SimpleCoin.sol/SimpleCoin.abi");
///
/// new_with_mock_provider!(SimpleCoin);
/// ```
#[macro_export]
macro_rules! new_with_mock_provider {
($contract:ident) => {
pub fn new(
owner: fil_actor_evm::interpreter::address::EthAddress,
) -> $contract<ethers::providers::Provider<ethers::providers::MockProvider>> {
// The owner of the contract is expected to be the 160 bit hash used on Ethereum.
let address = ethers::core::types::Address::from_slice(owner.as_ref());
// A dummy client that we don't intend to use to call the contract or send transactions.
let (client, _mock) = ethers::providers::Provider::mocked();
$contract::new(address, std::sync::Arc::new(client))
}
};
}
pub mod simple_coin;
Loading

0 comments on commit f20de2f

Please sign in to comment.