Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(solc): better metadata support
Browse files Browse the repository at this point in the history
mattsse committed Feb 10, 2022
1 parent 0a5b0d3 commit 6f8cc45
Showing 2 changed files with 97 additions and 2 deletions.
88 changes: 86 additions & 2 deletions ethers-solc/src/artifacts.rs
Original file line number Diff line number Diff line change
@@ -103,9 +103,14 @@ impl Default for CompilerInput {
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Settings {
/// Stop compilation after the given stage.
/// since 0.8.11: only "parsing" is valid here
#[serde(default, skip_serializing_if = "Option::is_none")]
pub stop_after: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub remappings: Vec<Remapping>,
pub optimizer: Optimizer,
/// Metadata settings
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<SettingsMetadata>,
/// This field can be used to select desired outputs based
@@ -199,6 +204,50 @@ impl Settings {
output_selection
}

/// Inserts the value for all files and contracts
pub fn push_output_selection(&mut self, value: impl Into<String>) {
self.push_contract_output_selection("*", value)
}

/// Inserts the `key` `value` pair to the `output_selection` for all files
///
/// If the `key` already exists, then the value is added to the existing list
pub fn push_contract_output_selection(
&mut self,
contracts: impl Into<String>,
value: impl Into<String>,
) {
let value = value.into();
let values = self
.output_selection
.entry("*".to_string())
.or_default()
.entry(contracts.into())
.or_default();
if !values.contains(&value) {
values.push(value)
}
}

/// Sets the value for all files and contracts
pub fn set_output_selection(&mut self, values: impl IntoIterator<Item = impl Into<String>>) {
self.set_contract_output_selection("*", values)
}

/// Sets the `key` to the `values` pair to the `output_selection` for all files
///
/// This will replace the existing values for `key` if they're present
pub fn set_contract_output_selection(
&mut self,
key: impl Into<String>,
values: impl IntoIterator<Item = impl Into<String>>,
) {
self.output_selection
.entry("*".to_string())
.or_default()
.insert(key.into(), values.into_iter().map(Into::into).collect());
}

/// Adds `ast` to output
#[must_use]
pub fn with_ast(mut self) -> Self {
@@ -211,6 +260,7 @@ impl Settings {
impl Default for Settings {
fn default() -> Self {
Self {
stop_after: None,
optimizer: Default::default(),
metadata: None,
output_selection: Self::default_output_selection(),
@@ -392,26 +442,60 @@ impl FromStr for EvmVersion {
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct SettingsMetadata {
/// Use only literal content and not URLs (false by default)
#[serde(default, rename = "useLiteralContent", skip_serializing_if = "Option::is_none")]
pub use_literal_content: Option<bool>,
/// Use the given hash method for the metadata hash that is appended to the bytecode.
/// The metadata hash can be removed from the bytecode via option "none".
/// The other options are "ipfs" and "bzzr1".
/// If the option is omitted, "ipfs" is used by default.
#[serde(default, rename = "bytecodeHash", skip_serializing_if = "Option::is_none")]
pub bytecode_hash: Option<String>,
}

/// Bindings for [`solc` contract metadata](https://docs.soliditylang.org/en/latest/metadata.html)
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Metadata {
pub compiler: Compiler,
pub language: String,
pub output: Output,
pub settings: Settings,
pub settings: MetadataSettings,
pub sources: MetadataSources,
pub version: i64,
}

/// Compiler settings
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct MetadataSettings {
/// Required for Solidity: File and name of the contract or library this metadata is created
/// for.
#[serde(default, rename = "compilationTarget")]
pub compilation_target: BTreeMap<String, String>,
#[serde(flatten)]
pub inner: Settings,
}

/// Compilation source files/source units, keys are file names
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct MetadataSources {
#[serde(flatten)]
pub inner: BTreeMap<String, serde_json::Value>,
pub inner: BTreeMap<String, MetadataSource>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct MetadataSource {
/// Required: keccak256 hash of the source file
pub keccak256: String,
/// Required (unless "content" is used, see below): Sorted URL(s)
/// to the source file, protocol is more or less arbitrary, but a
/// Swarm URL is recommended
#[serde(default)]
pub urls: Vec<String>,
/// Required (unless "url" is used): literal contents of the source file
#[serde(default, skip_serializing_if = "Option::is_none")]
pub content: Option<String>,
/// Optional: SPDX license identifier as given in the source file
pub license: Option<String>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
11 changes: 11 additions & 0 deletions ethers-solc/src/compile/mod.rs
Original file line number Diff line number Diff line change
@@ -726,6 +726,17 @@ mod tests {
assert_eq!(out, other);
}

#[test]
fn solc_metadata_works() {
let input = include_str!("../../test-data/in/compiler-in-1.json");
let mut input: CompilerInput = serde_json::from_str(input).unwrap();
input.settings.push_output_selection("metadata");
let out = solc().compile(&input).unwrap();
for (_, c) in out.split().1.contracts_iter() {
assert!(c.metadata.is_some());
}
}

#[cfg(feature = "async")]
#[tokio::test]
async fn async_solc_compile_works() {

0 comments on commit 6f8cc45

Please sign in to comment.