ethers-rs/ethers-solc/src/hh.rs

149 lines
5.3 KiB
Rust
Raw Normal View History

//! Hardhat support
use crate::{
artifacts::{
bytecode::{Bytecode, BytecodeObject, DeployedBytecode},
contract::{CompactContract, CompactContractBytecode, Contract, ContractBytecode},
CompactContractBytecodeCow, LosslessAbi, Offsets,
},
refactor(solc): rewrite compiler passes and cache change detection (#802) * chore: clippy * refactor: rewrite compiler passes and cache * feat: more work on compile pipeline * feat: add cache constructor * add artifact filtering * fine tune api * feat: prepare version integration * docs: more docs * feat: add cacheentry2 * replace cacheentry types * integrate new api * docs: more docs * feat: implement new output handler * feat: integrate cached files in new compile pipeline * refactor: more cache refactor * docs: more docs * feat: add source name mapping * feat: implement new parallel solc * refactor: do a little cleanup * refactor: even more cleanup * even more cleanup * chore: make it compile * chore: make it compile with all features * chore: clippy fix * feat: integrate new compiler pipeline * docs: more docs * refactor: move stuff around * refactor: start deprecating output type * chore: make it compile again * chore(deps): bump solc version 0.2.0 * feat: unify output types * cargo fix * refactor: add contracts wrapper * chore: replace ProjectCompileOutput * docs: add more docs * feat: add offline mode * feat: more artifact helpers * chore: cleanup cache * chore: streamline types * fix: better artifacts mapping * chore: some cleanup * chore: change artifact * chore: add configure solc fn * feat: add artifact reading * feat: implement retain and extend * feat: add cache extending * feat: write to disk * chore: make clippy happy * feat: implement path mapping * chore: nits * feat: introduce states * feat: add compiler state machine * chore: move cache types to cache mod * chore: make clippy happy * feat: add debug derives * fix: use resolved import source unit names * fix: failing tests * test: test multiple libs properly * chore: make clippy happy * chore: update CHANGELOG * fix: doc tests * fix: set offline mode correctly * chore: make it compile again * Update ethers-solc/src/artifacts.rs Co-authored-by: Georgios Konstantopoulos <me@gakonst.com> * feat: find remappings by default * typos * add eth_syncing RPC (#848) * add eth_syncing RPC * Changelo updated * small comments * Intermediate SyncingStatus * fix(core): adjust Ganache for new cli output (#851) * fix: review comments * fix: cache relative path bug * chore: add cache example * chore: use absolute paths * fix: remove overwritten files from cache * fix: rustfmt * chore: more helper functions * chore: export AggregatedOutput * feat: implement helper functions * feat: even more helpers * fix: failing doc tests * refactor: remove source name map tracking * fix: determine artifacts in ephemeral mode * refactor: allowed paths should not fail Co-authored-by: Georgios Konstantopoulos <me@gakonst.com> Co-authored-by: rakita <rakita@users.noreply.github.com> Co-authored-by: wolflo <33909953+wolflo@users.noreply.github.com>
2022-02-04 16:20:24 +00:00
ArtifactOutput,
};
use serde::{Deserialize, Serialize};
use std::{borrow::Cow, collections::btree_map::BTreeMap};
const HH_ARTIFACT_VERSION: &str = "hh-sol-artifact-1";
/// A hardhat artifact
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HardhatArtifact {
#[serde(rename = "_format")]
pub format: String,
/// A string with the contract's name.
pub contract_name: String,
/// The source name of this contract in the workspace like `contracts/Greeter.sol`
pub source_name: String,
/// The contract's ABI
pub abi: LosslessAbi,
/// A "0x"-prefixed hex string of the unlinked deployment bytecode. If the contract is not
/// deployable, this has the string "0x"
2021-12-25 04:45:53 +00:00
pub bytecode: Option<BytecodeObject>,
/// A "0x"-prefixed hex string of the unlinked runtime/deployed bytecode. If the contract is
/// not deployable, this has the string "0x"
pub deployed_bytecode: Option<BytecodeObject>,
/// The bytecode's link references object as returned by solc. If the contract doesn't need to
/// be linked, this value contains an empty object.
#[serde(default)]
pub link_references: BTreeMap<String, BTreeMap<String, Vec<Offsets>>>,
/// The deployed bytecode's link references object as returned by solc. If the contract doesn't
/// need to be linked, this value contains an empty object.
#[serde(default)]
pub deployed_link_references: BTreeMap<String, BTreeMap<String, Vec<Offsets>>>,
}
impl<'a> From<&'a HardhatArtifact> for CompactContractBytecodeCow<'a> {
fn from(artifact: &'a HardhatArtifact) -> Self {
let c: ContractBytecode = artifact.clone().into();
CompactContractBytecodeCow {
abi: Some(Cow::Borrowed(&artifact.abi.abi)),
bytecode: c.bytecode.map(|b| Cow::Owned(b.into())),
deployed_bytecode: c.deployed_bytecode.map(|b| Cow::Owned(b.into())),
}
}
}
impl From<HardhatArtifact> for CompactContract {
fn from(artifact: HardhatArtifact) -> Self {
CompactContract {
abi: Some(artifact.abi.abi),
2021-12-25 04:45:53 +00:00
bin: artifact.bytecode,
bin_runtime: artifact.deployed_bytecode,
}
}
}
impl From<HardhatArtifact> for ContractBytecode {
fn from(artifact: HardhatArtifact) -> Self {
let bytecode: Option<Bytecode> = artifact.bytecode.as_ref().map(|t| {
let mut bcode: Bytecode = t.clone().into();
bcode.link_references = artifact.link_references.clone();
bcode
});
let deployed_bytecode: Option<DeployedBytecode> = artifact.bytecode.as_ref().map(|t| {
let mut bcode: Bytecode = t.clone().into();
bcode.link_references = artifact.deployed_link_references.clone();
bcode.into()
});
ContractBytecode { abi: Some(artifact.abi.abi), bytecode, deployed_bytecode }
}
}
impl From<HardhatArtifact> for CompactContractBytecode {
fn from(artifact: HardhatArtifact) -> Self {
let c: ContractBytecode = artifact.into();
c.into()
}
}
/// Hardhat style artifacts handler
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
pub struct HardhatArtifacts {
_priv: (),
}
impl ArtifactOutput for HardhatArtifacts {
type Artifact = HardhatArtifact;
fn contract_to_artifact(&self, file: &str, name: &str, contract: Contract) -> Self::Artifact {
let (bytecode, link_references, deployed_bytecode, deployed_link_references) =
if let Some(evm) = contract.evm {
let (deployed_bytecode, deployed_link_references) =
if let Some(code) = evm.deployed_bytecode.and_then(|code| code.bytecode) {
(Some(code.object), code.link_references)
} else {
(None, Default::default())
};
2021-12-25 04:45:53 +00:00
let (bytecode, link_ref) = if let Some(bc) = evm.bytecode {
(Some(bc.object), bc.link_references)
} else {
(None, Default::default())
};
(bytecode, link_ref, deployed_bytecode, deployed_link_references)
} else {
(Default::default(), Default::default(), None, Default::default())
};
HardhatArtifact {
format: HH_ARTIFACT_VERSION.to_string(),
contract_name: name.to_string(),
source_name: file.to_string(),
abi: contract.abi.unwrap_or_default(),
bytecode,
deployed_bytecode,
link_references,
deployed_link_references,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Artifact;
#[test]
fn can_parse_hh_artifact() {
let s = include_str!("../test-data/hh-greeter-artifact.json");
let artifact = serde_json::from_str::<HardhatArtifact>(s).unwrap();
let compact = artifact.into_compact_contract();
assert!(compact.abi.is_some());
assert!(compact.bin.is_some());
assert!(compact.bin_runtime.is_some());
}
}