Skip to main content

huff_neo_js/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3#![warn(unused_extern_crates)]
4#![forbid(unsafe_code)]
5
6use std::{collections::HashMap, sync::Arc};
7
8use wasm_bindgen::prelude::*;
9
10use huff_neo_core::Compiler;
11use huff_neo_utils::{
12    abi::Abi,
13    artifact::{self, Artifact},
14    prelude::EVMVersion,
15};
16use serde::{Deserialize, Serialize};
17use tsify::Tsify;
18
19/// Input configuration for the Huff compiler
20#[derive(Serialize, Deserialize, Tsify)]
21#[tsify(into_wasm_abi, from_wasm_abi)]
22pub struct CompilerInput {
23    evm_version: Option<String>,
24    sources: Vec<String>,
25    files: HashMap<String, String>,
26    construct_args: Option<Vec<String>>,
27    alternative_main: Option<String>,
28    alternative_constructor: Option<String>,
29}
30
31/// Compiled artifact for a Huff contract
32#[derive(Serialize, Deserialize, Tsify)]
33#[tsify(into_wasm_abi, from_wasm_abi)]
34pub struct CompilerArtifact {
35    bytecode: String,
36    runtime: String,
37    abi: Option<Abi>,
38    constructor_map: Option<Vec<artifact::SourceMapEntry>>,
39    runtime_map: Option<Vec<artifact::SourceMapEntry>>,
40}
41
42/// Output from the Huff compiler
43#[derive(Serialize, Deserialize, Tsify)]
44#[tsify(into_wasm_abi, from_wasm_abi)]
45pub struct CompilerOutput {
46    errors: Option<Vec<String>>,
47    contracts: Option<HashMap<String, CompilerArtifact>>,
48}
49
50/// Compiles contracts with typed input and output
51#[wasm_bindgen]
52pub fn compile(input: CompilerInput) -> CompilerOutput {
53    let evm_version = EVMVersion::from(input.evm_version);
54
55    let compiler = Compiler::new_in_memory(
56        &evm_version,
57        Arc::new(input.sources.clone()),
58        input.files,
59        input.alternative_main,
60        input.alternative_constructor,
61        input.construct_args,
62        None,
63        false,
64    );
65
66    // Handle compilation errors gracefully by returning them in the output
67    let res: Vec<Arc<Artifact>> = match compiler.execute() {
68        Ok(artifacts) => artifacts,
69        Err(err) => {
70            // Return compilation errors as part of the output
71            return CompilerOutput { errors: Some(vec![format!("{}", *err)]), contracts: None };
72        }
73    };
74
75    // If no artifacts generated, return a debug error
76    if res.is_empty() {
77        return CompilerOutput {
78            errors: Some(vec!["No artifacts generated. Check that files are accessible and contain valid Huff code.".to_string()]),
79            contracts: None,
80        };
81    }
82
83    let mut contracts: HashMap<String, CompilerArtifact> = HashMap::new();
84
85    res.into_iter().for_each(|artifact| {
86        contracts.insert(
87            artifact.file.path.clone(),
88            CompilerArtifact {
89                bytecode: artifact.bytecode.clone(),
90                runtime: artifact.runtime.clone(),
91                abi: artifact.abi.clone(),
92                constructor_map: artifact.constructor_map.clone(),
93                runtime_map: artifact.runtime_map.clone(),
94            },
95        );
96    });
97
98    CompilerOutput { errors: None, contracts: Some(contracts) }
99}