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

Commit

Permalink
feat: support parsing bytecode from evm object (#2024)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattsse authored Jan 7, 2023
1 parent 2aa7bc3 commit 01d3e43
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 9 deletions.
86 changes: 77 additions & 9 deletions ethers-core/src/abi/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,26 @@ pub enum JsonAbi {
Array(RawAbi),
}

// === impl JsonAbi ===

impl JsonAbi {
/// Returns the bytecode object
pub fn bytecode(&self) -> Option<Bytes> {
match self {
JsonAbi::Object(abi) => abi.bytecode.clone(),
JsonAbi::Array(_) => None,
}
}

/// Returns the deployed bytecode object
pub fn deployed_bytecode(&self) -> Option<Bytes> {
match self {
JsonAbi::Object(abi) => abi.deployed_bytecode.clone(),
JsonAbi::Array(_) => None,
}
}
}

fn deserialize_abi_array<'de, D>(deserializer: D) -> Result<RawAbi, D::Error>
where
D: Deserializer<'de>,
Expand All @@ -128,6 +148,7 @@ where
pub struct AbiObject {
pub abi: RawAbi,
pub bytecode: Option<Bytes>,
pub deployed_bytecode: Option<Bytes>,
}

struct AbiObjectVisitor;
Expand All @@ -145,6 +166,7 @@ impl<'de> Visitor<'de> for AbiObjectVisitor {
{
let mut abi = None;
let mut bytecode = None;
let mut deployed_bytecode = None;

#[derive(Deserialize)]
#[serde(untagged)]
Expand All @@ -153,6 +175,28 @@ impl<'de> Visitor<'de> for AbiObjectVisitor {
Bytes(Bytes),
}

impl Bytecode {
fn into_bytes(self) -> Option<Bytes> {
let bytecode = match self {
Bytecode::Object { object } => object,
Bytecode::Bytes(bytes) => bytes,
};
if bytecode.is_empty() {
None
} else {
Some(bytecode)
}
}
}

/// represents nested bytecode objects of the `evm` value
#[derive(Deserialize)]
struct EvmObj {
bytecode: Option<Bytecode>,
#[serde(rename = "deployedBytecode")]
deployed_bytecode: Option<Bytecode>,
}

struct DeserializeBytes(Bytes);

impl<'de> Deserialize<'de> for DeserializeBytes {
Expand All @@ -169,15 +213,18 @@ impl<'de> Visitor<'de> for AbiObjectVisitor {
"abi" => {
abi = Some(RawAbi(map.next_value::<Vec<Item>>()?));
}
"evm" => {
if let Ok(evm) = map.next_value::<EvmObj>() {
bytecode = evm.bytecode.and_then(|b| b.into_bytes());
deployed_bytecode = evm.deployed_bytecode.and_then(|b| b.into_bytes())
}
}
"bytecode" | "byteCode" => {
bytecode = map
.next_value::<Bytecode>()
.ok()
.map(|obj| match obj {
Bytecode::Object { object } => object,
Bytecode::Bytes(bytes) => bytes,
})
.filter(|bytecode| !bytecode.0.is_empty());
bytecode = map.next_value::<Bytecode>().ok().and_then(|b| b.into_bytes());
}
"deployedbytecode" | "deployedBytecode" => {
deployed_bytecode =
map.next_value::<Bytecode>().ok().and_then(|b| b.into_bytes());
}
"bin" => {
bytecode = map
Expand All @@ -186,14 +233,21 @@ impl<'de> Visitor<'de> for AbiObjectVisitor {
.map(|b| b.0)
.filter(|b| !b.0.is_empty());
}
"runtimebin" | "runtimeBin" => {
deployed_bytecode = map
.next_value::<DeserializeBytes>()
.ok()
.map(|b| b.0)
.filter(|b| !b.0.is_empty());
}
_ => {
map.next_value::<serde::de::IgnoredAny>()?;
}
}
}

let abi = abi.ok_or_else(|| serde::de::Error::missing_field("abi"))?;
Ok(AbiObject { abi, bytecode })
Ok(AbiObject { abi, bytecode, deployed_bytecode })
}
}

Expand Down Expand Up @@ -316,4 +370,18 @@ mod tests {
}
}
}

#[test]
fn can_parse_deployed_bytecode() {
let artifact = include_str!("../../testdata/solc-obj.json");
match serde_json::from_str::<JsonAbi>(artifact).unwrap() {
JsonAbi::Object(abi) => {
assert!(abi.bytecode.is_some());
assert!(abi.deployed_bytecode.is_some());
}
_ => {
panic!("expected abi object")
}
}
}
}
1 change: 1 addition & 0 deletions ethers-core/testdata/solc-obj.json

Large diffs are not rendered by default.

0 comments on commit 01d3e43

Please sign in to comment.