elabs_solc/
lib.rs

1// Copyright (C) 2022 The Elabs Project Authors.
2// This file is part of the Elabs library.
3//
4// The Elabs library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, version 3 of the License.
7//
8// The Elabs library is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License along with The Elabs library.
14// If not, see <https://www.gnu.org/licenses/>.
15
16//! # Elabs
17//! Elabs-solc is a wrapper around the Solidity compiler.
18//! It is designed to be used as a library, and not as a command line tool.
19//! It will wrap `solc` cli tools, and provide a simple interface
20//! to compile solidity contracts.
21//! ## Usage
22//! To use the library, you need to import it in your project:
23//! ```toml
24//! [dependencies]
25//! elabs-solc = "0.1"
26//! ```
27//! ## Example
28//! ```rust
29//! use elabs_solc::Solc;
30//!
31//! fn main() {
32//!	    let solc = Solc::new();
33//!	    let input_path = "contracts/Simple.sol";
34//!	    let output_path = "artifacts";
35//!	    match solc.compile(input_path, output_path, vec![]) {
36//!		    Ok(_) => println!("{} compiled", input_path),
37//!		    Err(e) => panic!("{}", e),
38//!	    }
39//! }
40//! ```
41
42use std::process::Command;
43
44/// The solc struct.
45/// It is a wrapper around the solc compiler.
46pub struct Solc(String);
47
48impl Solc {
49    /// Create a new solc wrapper.
50    /// # Arguments
51    /// * `binary` - The binary to use. eg. `solc`.
52    /// # Returns
53    /// * `Solc` - The solc wrapper.
54    /// # TODO
55    /// * Add error handling.
56    /// * Add support for other compilers. eg `solcjs`.
57    pub fn new() -> Solc {
58        Solc("solc".to_string())
59    }
60
61    /// Parse version number.
62    /// # Arguments
63    /// * `version` - The version string.
64    /// # Returns
65    /// * `String` - The version number.
66    pub fn parse_version(version: &str) -> String {
67        version
68            .replace("Version: ", "")
69            .split("+")
70            .next()
71            .unwrap()
72            .to_string()
73    }
74
75    /// Get the solc version.
76    /// # Returns
77    /// * `String` - The solc version.
78    pub fn version(&self) -> String {
79        let mut cmd = Command::new(&self.0);
80        cmd.arg("--version");
81        let output = cmd.output().unwrap();
82        let out_str = String::from_utf8(output.stdout).unwrap();
83        let out_vec = out_str.split("\n").collect::<Vec<&str>>();
84        if out_vec.len() > 1 {
85            Solc::parse_version(out_vec[1])
86        } else {
87            Solc::parse_version(out_vec[0])
88        }
89    }
90
91    /// Compile solidity code.
92    /// # Arguments
93    /// * `input_path` - The path to the solidity file.
94    /// * `out_path` - The path to the output file.
95    /// * `opts` - Optional arguments.
96    /// # Returns
97    /// * `Ok(String)` - The compiled contract.
98    /// * `Err(String)` - The error message.
99    pub fn compile(
100        &self,
101        input_path: &str,
102        out_path: &str,
103        opts: Vec<&str>,
104    ) -> Result<String, String> {
105        let args = vec!["--bin", "--abi", "--overwrite"];
106
107        let cmd = Command::new(&self.0)
108            .args(args)
109            .args(opts)
110            .arg("--output-dir")
111            .arg(out_path)
112            .arg(input_path)
113            .output();
114
115        match cmd {
116            Err(err) => Err(format!("{}", err)),
117            Ok(res) => {
118                // check if stderr was empty, if not return it as error.
119                if res.stderr.len() > 0 {
120                    Err(String::from_utf8(res.stderr).unwrap())
121                } else {
122                    Ok(String::from_utf8(res.stdout).unwrap())
123                }
124            }
125        }
126    }
127}