Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,212 changes: 1,018 additions & 194 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,12 @@ alloy = { version = "1.0.19", features = ["sol-types", "contract"] }
alloy-serde = { version = "1.0.19" }

# libraries required to build supra-contract bindings
# For more detaisl see crates/supra-extension/build.rs
# For more details see crates/supra-extension/build.rs
#forge = { git = "https://github.com/foundry-rs/foundry.git", tag="v1.4.1"}
#alloy-chains = { version = "0.2.13" }
#shlex = { version = "1.3.0" }
foundry-compilers = "0.19.14"
foundry-config = { git = "https://github.com/foundry-rs/foundry.git", tag="v1.4.1"}
toml = { version = "0.9.8"}

# precompiles
Expand Down Expand Up @@ -120,6 +121,7 @@ criterion = { package = "codspeed-criterion-compat", version = "2.10" }
# serde
serde = { version = "1.0", default-features = false }
serde_json = { version = "1.0.149", default-features = false }
serde_with = "3.18.0"

# misc
auto_impl = "1.3.0"
Expand Down
2 changes: 2 additions & 0 deletions crates/handler/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use interpreter::interpreter_action::FrameInit;
use interpreter::{Gas, InitialAndFloorGas, SharedMemory};
use primitives::supra_constants::{is_supra_reserved, is_vm_signer};
use primitives::U256;
use std::format;
use std::string::String;

/// Trait for errors that can occur during EVM execution.
///
Expand Down
2 changes: 2 additions & 0 deletions crates/supra-extension/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ foundry-compilers = { workspace = true }
serde_json = { workspace = true }
bincode = { workspace = true , features = ["serde"]}
once_cell = { workspace = true }
serde_with = { workspace = true , features = ["hex"]}

[lints]
workspace = true
Expand All @@ -39,6 +40,7 @@ workspace = true
#clap = { workspace = true }
#shlex = { workspace = true }
foundry-compilers = { workspace = true }
foundry-config = { workspace = true }
anyhow = { workspace = true }
toml = { workspace = true }
serde = {workspace = true }
Expand Down
192 changes: 138 additions & 54 deletions crates/supra-extension/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

use anyhow::Result;
use bincode;
use foundry_compilers::artifacts::Remapping;
use foundry_compilers::multi::MultiCompilerSettings;
use foundry_compilers::solc::SolcSettings;
use foundry_compilers::{utils, Project, ProjectPathsConfig};
use foundry_compilers::utils;
use foundry_config::Config;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::env;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

const CURRENT_DIR: &str = env!("CARGO_MANIFEST_DIR");

Expand Down Expand Up @@ -58,10 +58,14 @@ fn rebuild_rust_bindings() {

#[derive(Serialize, Deserialize, Debug)]
struct CompileConfig {
dapp_relative_path: PathBuf,
solc_settings: SolcSettings,
#[serde(default)]
remappings: Vec<(String, String)>,
/// Supra contracts relative path
supra_dapp_path: PathBuf,
/// Supra nova dapp repository
supra_nova_repo: String,
/// Supra nova dapp tag to reference to
supra_nova_tag: String,
/// Supra nova dapp relative path in repo
supra_nova_dapp_path: String,
}

impl CompileConfig {
Expand All @@ -72,45 +76,70 @@ impl CompileConfig {
.inspect_err(|e| println!("Error: {}", e))
}

fn dapp_path(&self) -> PathBuf {
utils::canonicalize(Path::new(CURRENT_DIR).join(&self.dapp_relative_path))
fn supra_contracts_dapp_path(&self) -> PathBuf {
utils::canonicalize(Path::new(CURRENT_DIR).join(&self.supra_dapp_path))
.expect("failed to canonicalize dapp path")
}

fn remappings(&self) -> Vec<Remapping> {
self.remappings
.iter()
.map(|(name, rel_path)| Remapping {
context: None,
name: name.clone(),
path: self
.dapp_path()
.join(rel_path)
.to_string_lossy()
.into_owned(),
})
.collect()
fn supra_nova_dapp_path(&self) -> Result<PathBuf> {
self.checkout_supra_nova_repo()
.map(|path| path.join(self.supra_nova_dapp_path.clone()))
}

fn to_multi_compiler_settings(self) -> MultiCompilerSettings {
let mut settings = MultiCompilerSettings::default();
settings.solc = self.solc_settings;
settings
}
}
fn checkout_supra_nova_repo(&self) -> Result<PathBuf> {
let out_dir = env::var("OUT_DIR")?;
let repo_dir = Path::new(&out_dir).join("supranova-contracts");

if repo_dir.exists() {
// Check whether the already-cloned repo is at the right tag.
let output = Command::new("git")
.args(["describe", "--tags", "--exact-match"])
.current_dir(&repo_dir)
.output()?;
let current_tag = String::from_utf8_lossy(&output.stdout).trim().to_string();
if current_tag == self.supra_nova_tag {
return Ok(repo_dir);
}
// Wrong tag – remove and re-clone.
std::fs::remove_dir_all(&repo_dir)?;
}

let status = Command::new("git")
.env(
"GIT_SSH_COMMAND",
"ssh -o BatchMode=yes -o StrictHostKeyChecking=no",
)
.args([
"clone",
"--recurse-submodules",
"--branch",
self.supra_nova_tag.as_str(),
"--depth",
"1",
self.supra_nova_repo.as_str(),
repo_dir
.to_str()
.ok_or_else(|| anyhow::anyhow!("non-UTF-8 OUT_DIR path"))?,
])
.status()?;

fn compile_contracts() -> Result<PathBuf> {
let config = CompileConfig::load()?;
if !status.success() {
return Err(anyhow::anyhow!(
"Failed to clone {} at tag {}",
self.supra_nova_repo,
self.supra_nova_tag
));
}

let mut paths = ProjectPathsConfig::dapptools(&config.dapp_path())?;
for (idx, value) in config.remappings().into_iter().enumerate() {
paths.remappings.insert(idx, value)
Ok(repo_dir)
}
}

fn compile_contracts(path: &impl AsRef<Path>) -> Result<PathBuf> {
let foundry_config = Config::load_with_root(path.as_ref())?.sanitized();
let _ = foundry_config.install_lib_dir();
let project = foundry_config.project()?;

let project = Project::builder()
.paths(paths)
.settings(config.to_multi_compiler_settings())
.build(Default::default())?;
let output = project.compile()?;
let _ = output.succeeded();
// Tell Cargo that if a source file changes, to rerun this build script.
Expand All @@ -126,24 +155,59 @@ fn compile_contracts() -> Result<PathBuf> {
Ok(artifacts_dir)
}

fn combine_and_dump_contracts_bytecode(artifacts_path: &Path) -> Result<()> {
fn load_supra_contracts_bytecode(
artifacts_path: &Path,
bytecodes: &mut BTreeMap<String, Vec<u8>>,
) -> Result<()> {
// Contract names to load
let contract_names = vec![
let contract_names = [
"MultiSignatureWallet",
"MultisigBeacon",
"BeaconProxy",
"ERC20Supra",
"ERC20SupraHandler",
"BlockMeta",
"ERC1967Proxy",
"AutomationCore",
"AutomationRegistry",
"AutomationController",
"DiamondCutFacet",
"Diamond",
"DiamondLoupeFacet",
"OwnershipFacet",
"ConfigFacet",
"RegistryFacet",
"CoreFacet",
"DiamondInit",
];
load_contracts_bytecode(&contract_names, artifacts_path, bytecodes)
}

let mut bytecodes = std::collections::BTreeMap::new();
fn load_supra_nova_contracts_bytecode(
artifacts_path: &Path,
bytecodes: &mut BTreeMap<String, Vec<u8>>,
) -> Result<()> {
// Contract names to load
let contract_names = [
"WrappedToken", // Impl
"WrappedTokenFactory", // Beacon
"WrappedTokenFactoryProxy", // Beacon Proxy
"TokenVault",
"TokenVaultProxy",
"Hypernova",
"HypernovaProxy",
"FeeOperator",
"FeeOperatorProxy",
"TokenBridge",
"TokenBridgeProxy",
];
load_contracts_bytecode(&contract_names, artifacts_path, bytecodes)
}

fn load_contracts_bytecode(
contract_names: &[&'static str],
artifacts_path: &Path,
bytecodes: &mut BTreeMap<String, Vec<u8>>,
) -> Result<()> {
// Load each contract's bytecode
for contract_name in &contract_names {
for contract_name in contract_names {
let path = artifacts_path
.join(format!("{contract_name}.sol"))
.join(format!("{contract_name}.json"));
Expand All @@ -169,12 +233,22 @@ fn combine_and_dump_contracts_bytecode(artifacts_path: &Path) -> Result<()> {
anyhow::anyhow!("Failed to load bytecode for contract: {contract_name}")
})?;

bytecodes.insert(contract_name.to_string(), bytecode);
let inserted = bytecodes.insert(contract_name.to_string(), bytecode);
if inserted.is_some() {
return Err(anyhow::anyhow!(
"Duplicate contract name: {contract_name} in {artifacts_path:?} path"
));
}
}
Ok(())
}

fn dump_bytecodes(bytecodes: BTreeMap<String, Vec<u8>>, bin_file_name: &str) -> Result<()> {
// Dump the combined contract bytecodes to be loaded at compile to by generator.
let out_dir = env::var("OUT_DIR")?;
let out_path = Path::new(&out_dir).join("contract_bytecodes.bin");
let out_path = Path::new(&out_dir)
.join(bin_file_name)
.with_extension("bin");

std::fs::write(
&out_path,
Expand All @@ -183,17 +257,27 @@ fn combine_and_dump_contracts_bytecode(artifacts_path: &Path) -> Result<()> {
)
.expect("Failed to write bytecodes to file");

println!("cargo:rustc-env=CONTRACTS_LOADED=1");
println!("cargo:rustc-env=CONTRACTS_DUMPED=1");
Ok(())
}

fn main() {
rebuild_rust_bindings();
let artifacts_dir = compile_contracts()
.inspect_err(|e| panic!("{e:?}"))
.unwrap();

combine_and_dump_contracts_bytecode(&artifacts_dir)
.inspect_err(|e| panic!("Failed to combine and dump contract bytecodes: {e:?}"))
.unwrap()
let config = CompileConfig::load().expect("Config should always be valid");
let supra_contracts_artifacts = compile_contracts(&config.supra_contracts_dapp_path())
.expect("Successful supra contracts compilation");
let supra_nova_artifacts = compile_contracts(
&config
.supra_nova_dapp_path()
.expect("Successful supra nova dapp path resolve"),
)
.expect("Successful supra nova contracts compilation");
let mut contracts_bytecode = BTreeMap::new();
load_supra_contracts_bytecode(&supra_contracts_artifacts, &mut contracts_bytecode)
.expect("Supra contracts loaded successfully");
load_supra_nova_contracts_bytecode(&supra_nova_artifacts, &mut contracts_bytecode)
.expect("Supra nova contracts loaded successfully");
dump_bytecodes(contracts_bytecode, "supra_contracts_bytecode")
.expect("Bytecodes dumped successfully");
}
15 changes: 4 additions & 11 deletions crates/supra-extension/compile_config.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
dapp_relative_path = "../../solidity/supra_contracts/"
remappings = [["@openzeppelin/contracts/", "lib/openzeppelin-contracts/contracts/"]]
supra_dapp_path = "../../solidity/supra_contracts/"

[solc_settings]
evmVersion = "prague"
viaIR = true
supra_nova_repo = "git@github.com:Entropy-Foundation/supranova-contracts-private.git"
supra_nova_tag = "supranova-evm-v2.0.0-beta.1"
supra_nova_dapp_path = "hypernova/evm"

[solc_settings.optimizer]
enabled = true
runs = 200

[solc_settings.outputSelection."*"]
"" = ["ast"]
"*" = ["abi", "evm.bytecode.object"]
Loading