Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cast) add creation-code method [#8973] #9029

Merged
merged 24 commits into from
Oct 29, 2024

Conversation

pawurb
Copy link
Contributor

@pawurb pawurb commented Oct 4, 2024

Motivation

As described in #8973, currently there's no simple way to obtain contract creation code without compiling them locally. It is needed to deploy contracts with sol! macro.

If this is accepted I'll add artifact method generating file that can be used directly with sol! macro.

Solution

This PR adds cast creation-code method. It outputs the contract creation code.

Example usage

cast creation-code 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 --etherscan-api-key API_KEY --rpc-url RPC_URL

@zerosnacks zerosnacks linked an issue Oct 4, 2024 that may be closed by this pull request
crates/cast/bin/cmd/creation_code.rs Outdated Show resolved Hide resolved
crates/cast/bin/cmd/creation_code.rs Outdated Show resolved Hide resolved
}
}

/// Fetches the creation code of a contract from Etherscan and RPC.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should document whether or not this includes constructor args appended to initcode

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mds1 right, I should probably strip them to make the bytecode useful for local deployment. Maybe worth returning constructor args separately?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm reading up there's is no a single unified convention for encoding constructor args with different solidity versions. So I think I'll just add a comment that they are appended.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the use case for this method? I think that impacts whether or not you want to strip the constructor args. If you do want to strip them you'll likely need to use blockscout or etherscan to fetch constructor args

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to get bytecode that I can use for deploying contracts locally, without compiling them myself. So prefer creation code without constructor args appended. But, optionally knowing what were the args values is also useful.

Eventually I want to add artifact method that will combine creation bytecode with JSON ABI, for simply use with sol! Alloy macro.

I'm thinking to add --without-args and --only-args flags. I think it's possible to know the size of appended args from the ABI. WDYT?

@pawurb
Copy link
Contributor Author

pawurb commented Oct 10, 2024

I've added --only-args and --without-args flags to creation-code and creation-args method. With these tools it's possible to get bytecode for local deployment and also inspect args that were used in the original contract deployment.

cast creation-code 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419 --only-args --etherscan-api-key API_KEY --rpc-url RPC_URL

# 0x000000000000000000000000f79d6afbb6da890132f9d7c355e3015f15f3406f0000000000000000000000000000000000000000000000000000000000000000
cast creation-args 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419  --etherscan-api-key API_KEY --rpc-url RPC_URL

# address 0x000000000000000000000000f79d6afbb6da890132f9d7c355e3015f15f3406f
# address 0x0000000000000000000000000000000000000000000000000000000000000000

@pawurb pawurb force-pushed the cast_bytecode branch 3 times, most recently from e1df312 to fd6ee4e Compare October 10, 2024 09:59
@pawurb pawurb requested a review from mds1 October 10, 2024 10:02
@mattsse
Copy link
Member

mattsse commented Oct 16, 2024

what's missing here @zerosnacks ?

@pawurb pawurb requested a review from louisbrown0212 October 18, 2024 10:19
crates/cast/bin/args.rs Outdated Show resolved Hide resolved
@zerosnacks zerosnacks self-requested a review October 23, 2024 09:48
Copy link
Member

@zerosnacks zerosnacks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved some nits I found

I think it makes sense to change creation_args to constructor_args as that is the common way to refer to it

@pawurb
Copy link
Contributor Author

pawurb commented Oct 23, 2024

@zerosnacks applied the review fixes. I've also added abi_path argument. It allows to use constructor-args for non verified contracts. I've implemented display in this format:

0x000000000000000000000000f79d6afbb6da890132f9d7c355e3015f15f3406f -> Address(0xf79d6afbb6da890132f9d7c355e3015f15f3406f)
0x0000000000000000000000000000000000000000000000000000000000000000 -> Address(0x0000000000000000000000000000000000000000)

Showing both raw and decoded values can be helpful for Etherscan contract verification that requires raw argument values.

@pawurb pawurb requested a review from zerosnacks October 28, 2024 08:12
crates/cast/bin/args.rs Outdated Show resolved Hide resolved
}

fn format_arg(ty: &str, arg: Vec<u8>) -> Result<String> {
let arg_type: DynSolType = ty.parse().expect("Invalid ABI type.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Elegant solution w/ DynSolType 👍

Copy link
Member

@zerosnacks zerosnacks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @pawurb! Tiny nits related to documentation, implementation looks good 👍

pawurb and others added 4 commits October 28, 2024 21:15
Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pedantic style nits, otherwise lgtm

Comment on lines 74 to 78
if abi.constructor.is_none() {
return Err(eyre!("No constructor found."));
}

let constructor = abi.constructor.unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this can be abi.constructor.ok_or_else? I think

Comment on lines 100 to 101
let bytes = Bytes::from(arg.clone());
let decoded = arg_type.abi_decode(&arg)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this alloc is likely not required and the function can also accept &[u8]

.chunks(32)
.enumerate()
.map(|(i, arg)| {
let arg = arg.to_vec();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then we also dont need the to_vec here I believe

Copy link
Collaborator

@grandizzy grandizzy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, thank you. I left a comment re using newly introduced sh_println macro

crates/cast/bin/cmd/constructor_args.rs Outdated Show resolved Hide resolved
@grandizzy grandizzy merged commit 3e901af into foundry-rs:master Oct 29, 2024
21 checks passed
rplusq pushed a commit to rplusq/foundry that referenced this pull request Nov 29, 2024
* feat(cast) add creation-code method [foundry-rs#8973]

* Fix typo

* Fix CI

* Code review fixes

* Add creation-code flags and creation-args

* Update comments

* eyre style fixes

* typo

* use r#".."# for snapbox

* Apply suggestions from code review

* fix test regression

* tag arguments as mutually exclusive

* use unreachable!

* Rename and add abi_path param

* Decode constructor args

* Update crates/cast/bin/cmd/constructor_args.rs

* fix test

* Update crates/cast/bin/args.rs

Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>

* Update crates/cast/bin/cmd/creation_code.rs

Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>

* Update crates/cast/bin/cmd/creation_code.rs

Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>

* Fix formatting

* Code review fixes

---------

Co-authored-by: zerosnacks <zerosnacks@protonmail.com>
Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com>
@grandizzy grandizzy added T-feature Type: feature C-cast Command: cast labels Dec 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-cast Command: cast T-feature Type: feature
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

feat(cast) add deploydata method
6 participants