stylus_tools/core/reflection/
mod.rs

1// Copyright 2025, Offchain Labs, Inc.
2// For licensing, see https://github.com/OffchainLabs/stylus-sdk-rs/blob/main/licenses/COPYRIGHT.md
3
4//! Get information about a Stylus contract at build time
5//!
6//! This uses the mechanism of running a Stylus contract crate as a binary to return information
7//! about the contract. This does not depend on a deployment of the contract.
8
9use std::{path::PathBuf, process::Stdio};
10
11pub use constructor::constructor;
12use escargot::Cargo;
13
14use crate::utils::sys;
15
16mod constructor;
17
18/// Feature that enables reflection when running the contract binary.
19const FEATURE: &str = "export-abi";
20
21fn reflect(command: &str, mut features: Vec<String>) -> Result<Vec<u8>, ReflectionError> {
22    features.push(FEATURE.to_string());
23    let output = Cargo::new()
24        .into_command()
25        .stderr(Stdio::inherit())
26        .args(["run", "--quiet"])
27        .args(["--target", &sys::host_arch()?])
28        .args(["--features", &features.join(",")])
29        .args(["--", command])
30        .output()?;
31    if !output.status.success() {
32        let out = String::from_utf8_lossy(&output.stdout);
33        let out = (!out.is_empty())
34            .then_some(format!(" : {out}"))
35            .unwrap_or_default();
36        return Err(ReflectionError::FailedToRunContract(out));
37    }
38    Ok(output.stdout)
39}
40
41#[derive(Debug)]
42pub struct ReflectionConfig {
43    pub file: Option<PathBuf>,
44    pub json: bool,
45    pub rust_features: Option<Vec<String>>,
46}
47
48#[derive(Debug, thiserror::Error)]
49pub enum ReflectionError {
50    #[error("io error: {0}")]
51    Io(#[from] std::io::Error),
52    #[error("{0}")]
53    Utf8(#[from] std::str::Utf8Error),
54
55    #[error("{0}")]
56    AlloyDynAbiParser(#[from] alloy::dyn_abi::parser::Error),
57    #[error("{0}")]
58    Host(#[from] rustc_host::Error),
59
60    #[error("failed to run contract{0}")]
61    FailedToRunContract(String),
62}