Repository: huff-language/huff-rs
Pull request #190 (2022-08-03 13:54:02)

fix(huff_codegen): Constants as Macro Args
## Overview

Fixes an issue where constants weren't recognized if passed as a macro argument.

Branches off of #188, merge after that one.


Patch:
diff --git a/huff_cli/src/huffc.rs b/huff_cli/src/huffc.rs
index 1eda490..12ed0f9 100644
--- a/huff_cli/src/huffc.rs
+++ b/huff_cli/src/huffc.rs
@@ -7,7 +7,7 @@
 #![forbid(where_clauses_object_safety)]
 #![allow(deprecated)]
 
-use clap::{App, CommandFactory, Parser as ClapParser};
+use clap::Parser as ClapParser;
 use ethers_core::utils::hex;
 use huff_codegen::Codegen;
 use huff_core::Compiler;
@@ -56,8 +56,8 @@ struct Huff {
     optimize: bool,
 
     /// Generate solidity interface for a Huff artifact
-    #[clap(short = 'g', min_values = 0, long = "interface")]
-    interface: Option<String>,
+    #[clap(short = 'g', long = "interface")]
+    interface: bool,
 
     /// Generate and log bytecode.
     #[clap(short = 'b', long = "bytecode")]
@@ -89,9 +89,6 @@ pub(crate) fn get_input(prompt: &str) -> String {
 }
 
 fn main() {
-    // Into App
-    let app: App = Huff::into_app();
-
     // Parse the command line arguments
     let mut cli = Huff::parse();
 
@@ -207,35 +204,9 @@ fn main() {
                 std::process::exit(1);
             }
 
-            if app.get_matches().is_present("interface") {
-                let mut interface: Option<String> = None;
-                if artifacts.len() == 1 {
-                    let gen_interface: Option<String> = match artifacts[0]
-                        .file
-                        .path
-                        .split('/')
-                        .last()
-                    {
-                        Some(p) => match p.split('.').next() {
-                            Some(p) => Some(format!("I{}", p)),
-                            None => {
-                                tracing::warn!(target: "cli", "No file name found for artifact");
-                                None
-                            }
-                        },
-                        None => {
-                            tracing::warn!(target: "cli", "No trailing string");
-                            None
-                        }
-                    };
-                    interface = Some(cli.interface.unwrap_or_else(|| {
-                        gen_interface.unwrap_or_else(|| "Interface".to_string())
-                    }));
-                } else if cli.interface.is_some() {
-                    tracing::warn!(target: "cli", "Interface override ignored since multiple artifacts were generated");
-                }
+            if cli.interface {
                 tracing::info!(target: "cli", "GENERATING SOLIDITY INTERFACES FROM ARTIFACTS");
-                let interfaces = gen_sol_interfaces(&artifacts, interface);
+                let interfaces = gen_sol_interfaces(&artifacts);
                 if export_interfaces(&interfaces).is_ok() {
                     tracing::info!(target: "cli", "GENERATED SOLIDITY INTERFACES FROM ARTIFACTS SUCCESSFULLY");
                     println!(
@@ -243,7 +214,7 @@ fn main() {
                         Paint::blue(
                             interfaces
                                 .into_iter()
-                                .map(|(_, i, _)| format!("{}.sol", i))
+                                .map(|(_, i, _)| format!("I{}.sol", i))
                                 .collect::<Vec<_>>()
                                 .join(", ")
                         )
diff --git a/huff_codegen/src/irgen/arg_calls.rs b/huff_codegen/src/irgen/arg_calls.rs
index f1bc6f5..73f7d23 100644
--- a/huff_codegen/src/irgen/arg_calls.rs
+++ b/huff_codegen/src/irgen/arg_calls.rs
@@ -21,39 +21,8 @@ pub fn bubble_arg_call(
 ) -> Result<(), CodegenError> {
     let starting_offset = *offset;
 
-    // Check Constant Definitions
-    if let Some(constant) =
-        contract.constants.borrow().iter().find(|const_def| const_def.name.eq(arg_name))
-    {
-        tracing::info!(target: "codegen", "ARGCALL IS CONSTANT: {:?}", constant);
-        let push_bytes = match &constant.value {
-            ConstVal::Literal(l) => {
-                let hex_literal: String = bytes32_to_string(l, false);
-                format!("{:02x}{}", 95 + hex_literal.len() / 2, hex_literal)
-            }
-            ConstVal::FreeStoragePointer(fsp) => {
-                // If this is reached in codegen stage,
-                // `derive_storage_pointers`
-                // method was not called on the AST.
-                tracing::error!(target: "codegen", "STORAGE POINTERS INCORRECTLY DERIVED FOR \"{:?}\"", fsp);
-                return Err(CodegenError {
-                    kind: CodegenErrorKind::StoragePointersNotDerived,
-                    span: AstSpan(vec![]),
-                    token: None,
-                })
-            }
-        };
-        *offset += push_bytes.len() / 2;
-        tracing::info!(target: "codegen", "OFFSET: {}, PUSH BYTES: {:?}", offset, push_bytes);
-        bytes.push((starting_offset, Bytes(push_bytes)));
-    } else if let Ok(o) = Opcode::from_str(arg_name) {
-        // Check Opcode Definition
-        let b = Bytes(o.to_string());
-        *offset += b.0.len() / 2;
-        tracing::info!(target: "codegen", "RECURSE_BYTECODE ARG CALL FOUND OPCODE: {:?}", b);
-        bytes.push((starting_offset, b));
-    } else if let Some(macro_invoc) = mis.last() {
-        // Literal & Arg Call Check
+    if let Some(macro_invoc) = mis.last() {
+        // Literal, Ident & Arg Call Check
         // First get this arg_nam position in the macro definition params
         if let Some(pos) = macro_def
             .parameters
@@ -122,21 +91,56 @@ pub fn bubble_arg_call(
                         }
                     }
                     MacroArg::Ident(iden) => {
-                        tracing::debug!(target: "codegen", "FOUND IDENT ARG IN \"{}\" MACRO INVOCATION: \"{}\"!", macro_invoc.1.macro_name, iden);
-                        tracing::debug!(target: "codegen", "Macro invocation index: {}", macro_invoc.0);
-                        tracing::debug!(target: "codegen", "At offset: {}", *offset);
+                        tracing::debug!(target: "codegen", "Found MacroArg::Ident IN \"{}\" Macro Invocation: \"{}\"!", macro_invoc.1.macro_name, iden);
 
-                        // This should be equivalent to a label call.
-                        bytes.push((*offset, Bytes(format!("{}xxxx", Opcode::Push2))));
-                        jump_table.insert(
-                            *offset,
-                            vec![Jump {
-                                label: iden.to_owned(),
-                                bytecode_index: 0,
-                                span: macro_invoc.1.span.clone(),
-                            }],
-                        );
-                        *offset += 3;
+                        // Check for a constant first
+                        if let Some(constant) = contract
+                            .constants
+                            .borrow()
+                            .iter()
+                            .find(|const_def| const_def.name.eq(iden))
+                        {
+                            tracing::info!(target: "codegen", "ARGCALL IS CONSTANT: {:?}", constant);
+                            let push_bytes = match &constant.value {
+                                ConstVal::Literal(l) => {
+                                    let hex_literal: String = bytes32_to_string(l, false);
+                                    format!("{:02x}{}", 95 + hex_literal.len() / 2, hex_literal)
+                                }
+                                ConstVal::FreeStoragePointer(fsp) => {
+                                    // If this is reached in codegen stage,
+                                    // `derive_storage_pointers`
+                                    // method was not called on the AST.
+                                    tracing::error!(target: "codegen", "STORAGE POINTERS INCORRECTLY DERIVED FOR \"{:?}\"", fsp);
+                                    return Err(CodegenError {
+                                        kind: CodegenErrorKind::StoragePointersNotDerived,
+                                        span: AstSpan(vec![]),
+                                        token: None,
+                                    })
+                                }
+                            };
+                            *offset += push_bytes.len() / 2;
+                            tracing::info!(target: "codegen", "OFFSET: {}, PUSH BYTES: {:?}", offset, push_bytes);
+                            bytes.push((starting_offset, Bytes(push_bytes)));
+                        } else if let Ok(o) = Opcode::from_str(iden) {
+                            tracing::debug!(target: "codegen", "Found Opcode: {}", o);
+                            let b = Bytes(o.to_string());
+                            *offset += b.0.len() / 2;
+                            bytes.push((starting_offset, b));
+                        } else {
+                            tracing::debug!(target: "codegen", "Found Label Call: {}", iden);
+
+                            // This should be equivalent to a label call.
+                            bytes.push((*offset, Bytes(format!("{}xxxx", Opcode::Push2))));
+                            jump_table.insert(
+                                *offset,
+                                vec![Jump {
+                                    label: iden.to_owned(),
+                                    bytecode_index: 0,
+                                    span: macro_invoc.1.span.clone(),
+                                }],
+                            );
+                            *offset += 3;
+                        }
                     }
                 }
             } else {
diff --git a/huff_codegen/src/irgen/statements.rs b/huff_codegen/src/irgen/statements.rs
index 722c1a9..037105e 100644
--- a/huff_codegen/src/irgen/statements.rs
+++ b/huff_codegen/src/irgen/statements.rs
@@ -280,15 +280,16 @@ pub fn statement_gen(
                         .iter()
                         .find(|f| bf.args[0].name.as_ref().unwrap().eq(&f.name))
                     {
-                        let push_bytes =
-                            format!("{}{}", Opcode::Push4, hex::encode(func.signature));
+                        let sig = hex::encode(func.signature);
+                        let push_bytes = format!("{:02x}{}", 95 + sig.len() / 2, sig);
                         *offset += push_bytes.len() / 2;
                         bytes.push((starting_offset, Bytes(push_bytes)));
                     } else if let Some(s) = &bf.args[0].name {
                         let mut signature = [0u8; 4]; // Only keep first 4 bytes
                         hash_bytes(&mut signature, s);
 
-                        let push_bytes = format!("{}{}", Opcode::Push4, hex::encode(signature));
+                        let sig = hex::encode(signature);
+                        let push_bytes = format!("{:02x}{}", 95 + sig.len() / 2, sig);
                         *offset += push_bytes.len() / 2;
                         bytes.push((starting_offset, Bytes(push_bytes)));
                     } else {
@@ -331,14 +332,15 @@ pub fn statement_gen(
                         .find(|e| bf.args[0].name.as_ref().unwrap().eq(&e.name))
                     {
                         let hash = bytes32_to_string(&event.hash, false);
-                        let push_bytes = format!("{}{}", Opcode::Push32, hash);
+                        let push_bytes = format!("{:02x}{}", 95 + hash.len() / 2, hash);
                         *offset += push_bytes.len() / 2;
                         bytes.push((starting_offset, Bytes(push_bytes)));
                     } else if let Some(s) = &bf.args[0].name {
                         let mut hash = [0u8; 32];
                         hash_bytes(&mut hash, s);
 
-                        let push_bytes = format!("{}{}", Opcode::Push32, hex::encode(hash));
+                        let hash = hex::encode(hash);
+                        let push_bytes = format!("{:02x}{}", 95 + hash.len() / 2, hash);
                         *offset += push_bytes.len() / 2;
                         bytes.push((starting_offset, Bytes(push_bytes)));
                     } else {
@@ -381,7 +383,7 @@ pub fn statement_gen(
                         // Add 28 bytes to left-pad the 4 byte selector
                         let selector =
                             format!("{}{}", hex::encode(error.selector), "00".repeat(28));
-                        let push_bytes = format!("{}{}", Opcode::Push32, selector);
+                        let push_bytes = format!("{:02x}{}", 95 + selector.len() / 2, selector);
                         *offset += push_bytes.len() / 2;
                         bytes.push((starting_offset, Bytes(push_bytes)));
                     } else {
@@ -399,29 +401,6 @@ pub fn statement_gen(
                         })
                     }
                 }
-                BuiltinFunctionKind::RightPad => {
-                    if bf.args.len() != 1 {
-                        tracing::error!(
-                            target = "codegen",
-                            "Incorrect number of arguments passed to __RIGHTPAD, should be 1: {}",
-                            bf.args.len()
-                        );
-                        return Err(CodegenError {
-                            kind: CodegenErrorKind::InvalidArguments(format!(
-                                "Incorrect number of arguments passed to __RIGHTPAD, should be 1: {}",
-                                bf.args.len()
-                            )),
-                            span: bf.span.clone(),
-                            token: None,
-                        })
-                    }
-
-                    let hex = format_even_bytes(bf.args[0].name.as_ref().unwrap().clone());
-                    let push_bytes =
-                        format!("{}{}{}", Opcode::Push32, hex, "0".repeat(64 - hex.len()));
-                    *offset += push_bytes.len() / 2;
-                    bytes.push((starting_offset, Bytes(push_bytes)));
-                }
             }
         }
         sty => {
diff --git a/huff_parser/src/lib.rs b/huff_parser/src/lib.rs
index d9edec9..1b2db6f 100644
--- a/huff_parser/src/lib.rs
+++ b/huff_parser/src/lib.rs
@@ -7,7 +7,7 @@
 use huff_utils::{
     ast::*,
     error::*,
-    prelude::{bytes32_to_string, hash_bytes, str_to_bytes32, FileSource, Span},
+    prelude::{hash_bytes, str_to_bytes32, FileSource, Span},
     token::{Token, TokenKind},
     types::*,
 };
@@ -405,18 +405,18 @@ impl Parser {
         };
 
         // Get arguments for signature
-        let parameters = self.parse_args(true, true, false, false)?;
+        let inputs = self.parse_args(true, true, false, false)?;
 
         let mut selector = [0u8; 4]; // Only keep first 4 bytes
         let input_types =
-            parameters.iter().map(|i| i.arg_type.as_ref().unwrap().clone()).collect::<Vec<_>>();
+            inputs.iter().map(|i| i.arg_type.as_ref().unwrap().clone()).collect::<Vec<_>>();
         hash_bytes(&mut selector, &format!("{}({})", name, input_types.join(",")));
 
         // Clone spans and set to nothing
         let new_spans = self.spans.clone();
         self.spans = vec![];
 
-        Ok(ErrorDefinition { name, selector, parameters, span: AstSpan(new_spans) })
+        Ok(ErrorDefinition { name, selector, span: AstSpan(new_spans) })
     }
 
     /// Parses a macro.
@@ -705,37 +705,26 @@ impl Parser {
         self.match_kind(TokenKind::OpenParen)?;
         tracing::debug!(target: "parser", "PARSING ARGs: {:?}", self.current_token.kind);
         while !self.check(TokenKind::CloseParen) {
-            if is_builtin {
-                // The builtin functions `__FUNC_SIG` and `__EVENT_HASH` can accept a single string
-                // as input. If the `is_builtin` flag was passed, check to see if a
-                // single string is present.
-                if let TokenKind::Str(s) = &self.current_token.kind {
-                    args.push(Argument {
-                        name: Some(s.to_owned()), // Place the string in the "name" field
-                        arg_type: None,
-                        indexed: false,
-                        span: AstSpan(vec![self.current_token.span.clone()]),
-                    });
-
-                    self.consume();
-                    continue
+            // The builtin functions `__FUNC_SIG` and `__EVENT_HASH` can accept a single string as
+            // input. If the `is_builtin` flag was passed, check to see if a single
+            // string is present.
+            if let TokenKind::Str(s) = &self.current_token.kind {
+                if !is_builtin {
+                    return Err(ParserError {
+                        kind: ParserErrorKind::InvalidArgs(self.current_token.kind.clone()),
+                        hint: None,
+                        spans: AstSpan(vec![self.current_token.span.clone()]),
+                    })
                 }
 
-                // The builtin function `__RIGHTPAD` can accept a single literal as input. If the
-                // `is_builtin` flag was passed, check to see if a single literal is
-                // present.
-                if let TokenKind::Literal(l) = &self.current_token.kind {
-                    args.push(Argument {
-                        name: Some(bytes32_to_string(l, false)), /* Place the literal in the
-                                                                  * "name" field */
-                        arg_type: None,
-                        indexed: false,
-                        span: AstSpan(vec![self.current_token.span.clone()]),
-                    });
-
-                    self.consume();
-                    continue
-                }
+                args.push(Argument {
+                    name: Some(s.to_owned()), // Place the string in the "name" field
+                    arg_type: None,
+                    indexed: false,
+                    span: AstSpan(vec![self.current_token.span.clone()]),
+                });
+                self.consume();
+                continue
             }
 
             let mut arg = Argument::default();
diff --git a/huff_utils/src/abi.rs b/huff_utils/src/abi.rs
index 27d8fbb..bc820d9 100644
--- a/huff_utils/src/abi.rs
+++ b/huff_utils/src/abi.rs
@@ -53,8 +53,6 @@ pub struct Abi {
     pub functions: BTreeMap<String, Function>,
     /// A list of events and their definitions
     pub events: BTreeMap<String, Event>,
-    /// A list of errors and their definitions
-    pub errors: BTreeMap<String, Error>,
     /// If the contract defines receive logic
     pub receive: bool,
     /// If the contract defines fallback logic
@@ -115,85 +113,72 @@ impl From<ast::Contract> for Abi {
         // Instantiate functions and events
         let mut functions = BTreeMap::new();
         let mut events = BTreeMap::new();
-        let mut errors = BTreeMap::new();
 
         // Translate contract functions
         // Excluding constructor
-        functions.extend(
-            contract
-                .functions
-                .iter()
-                .filter(|function: &&ast::Function| function.name != "CONSTRUCTOR")
-                .map(|function| {
-                    (
-                        function.name.to_string(),
-                        Function {
-                            name: function.name.to_string(),
-                            inputs: function
-                                .inputs
-                                .iter()
-                                .map(|argument| FunctionParam {
-                                    name: argument.name.clone().unwrap_or_default(),
-                                    kind: argument.arg_type.clone().unwrap_or_default().into(),
-                                    internal_type: None,
-                                })
-                                .collect(),
-                            outputs: function
-                                .outputs
-                                .iter()
-                                .map(|argument| FunctionParam {
-                                    name: argument.name.clone().unwrap_or_default(),
-                                    kind: argument.arg_type.clone().unwrap_or_default().into(),
-                                    internal_type: None,
-                                })
-                                .collect(),
-                            constant: false,
-                            state_mutability: function.fn_type.clone(),
-                        },
-                    )
-                }),
-        );
+        contract
+            .functions
+            .iter()
+            .filter(|function: &&ast::Function| function.name != "CONSTRUCTOR")
+            .map(|function| {
+                (
+                    function.name.to_string(),
+                    Function {
+                        name: function.name.to_string(),
+                        inputs: function
+                            .inputs
+                            .iter()
+                            .map(|argument| FunctionParam {
+                                name: argument.name.clone().unwrap_or_default(),
+                                kind: argument.arg_type.clone().unwrap_or_default().into(),
+                                internal_type: None,
+                            })
+                            .collect(),
+                        outputs: function
+                            .outputs
+                            .iter()
+                            .map(|argument| FunctionParam {
+                                name: argument.name.clone().unwrap_or_default(),
+                                kind: argument.arg_type.clone().unwrap_or_default().into(),
+                                internal_type: None,
+                            })
+                            .collect(),
+                        constant: false,
+                        state_mutability: function.fn_type.clone(),
+                    },
+                )
+            })
+            .for_each(|val| {
+                let _ = functions.insert(val.0, val.1);
+            });
 
         // Translate contract events
-        events.extend(contract.events.iter().map(|event| {
-            (
-                event.name.to_string(),
-                Event {
-                    name: event.name.to_string(),
-                    inputs: event
-                        .parameters
-                        .iter()
-                        .map(|argument| EventParam {
-                            name: argument.name.clone().unwrap_or_default(),
-                            kind: argument.arg_type.clone().unwrap_or_default().into(),
-                            indexed: argument.indexed,
-                        })
-                        .collect(),
-                    anonymous: false,
-                },
-            )
-        }));
-
-        // Translate contract errors
-        errors.extend(contract.errors.iter().map(|error| {
-            (
-                error.name.to_string(),
-                Error {
-                    name: error.name.to_string(),
-                    inputs: error
-                        .parameters
-                        .iter()
-                        .map(|argument| FunctionParam {
-                            name: argument.name.clone().unwrap_or_default(),
-                            kind: argument.arg_type.clone().unwrap_or_default().into(),
-                            internal_type: None,
-                        })
-                        .collect(),
-                },
-            )
-        }));
+        contract
+            .events
+            .iter()
+            .map(|event| {
+                (
+                    event.name.to_string(),
+                    Event {
+                        name: event.name.to_string(),
+                        inputs: event
+                            .parameters
+                            .iter()
+                            .map(|argument| EventParam {
+                                name: argument.name.clone().unwrap_or_default(),
+                                kind: argument.arg_type.clone().unwrap_or_default().into(),
+                                indexed: argument.indexed,
+                            })
+                            .collect(),
+                        anonymous: false,
+                    },
+                )
+            })
+            .for_each(|val| {
+                let _ = events.insert(val.0, val.1);
+            });
 
-        Self { constructor, functions, events, errors, receive: false, fallback: false }
+        Self { constructor, functions, events, receive: false, fallback: false }
     }
 }
 
@@ -240,17 +225,6 @@ pub struct EventParam {
     pub indexed: bool,
 }
 
-/// #### Error
-///
-/// An Error definition.
-#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
-pub struct Error {
-    /// The error name
-    pub name: String,
-    /// The error inputs
-    pub inputs: Vec<FunctionParam>,
-}
-
 /// #### Constructor
 ///
 /// The contract constructor
diff --git a/huff_utils/src/ast.rs b/huff_utils/src/ast.rs
index 6a9f8ec..53c676d 100644
--- a/huff_utils/src/ast.rs
+++ b/huff_utils/src/ast.rs
@@ -631,8 +631,6 @@ pub struct ErrorDefinition {
     pub name: String,
     /// The Error's selector
     pub selector: [u8; 4],
-    /// The parameters of the error
-    pub parameters: Vec<Argument>,
     /// The Span of the Constant Definition
     pub span: AstSpan,
 }
@@ -676,8 +674,6 @@ pub enum BuiltinFunctionKind {
     EventHash,
     /// Error selector function
     Error,
-    /// Rightpad function
-    RightPad,
 }
 
 impl From<String> for BuiltinFunctionKind {
@@ -689,7 +685,6 @@ impl From<String> for BuiltinFunctionKind {
             "__FUNC_SIG" => BuiltinFunctionKind::FunctionSignature,
             "__EVENT_HASH" => BuiltinFunctionKind::EventHash,
             "__ERROR" => BuiltinFunctionKind::Error,
-            "__RIGHTPAD" => BuiltinFunctionKind::RightPad,
             _ => panic!("Invalid Builtin Function Kind"), /* This should never be reached,
                                                            * builtins are validated with a
                                                            * `try_from` call in the lexer. */
@@ -708,7 +703,6 @@ impl TryFrom<&String> for BuiltinFunctionKind {
             "__FUNC_SIG" => Ok(BuiltinFunctionKind::FunctionSignature),
             "__EVENT_HASH" => Ok(BuiltinFunctionKind::EventHash),
             "__ERROR" => Ok(BuiltinFunctionKind::Error),
-            "__RIGHTPAD" => Ok(BuiltinFunctionKind::RightPad),
             _ => Err(()),
         }
     }
diff --git a/huff_utils/src/evm.rs b/huff_utils/src/evm.rs
index 6cc7f2f..6c3d3a3 100644
--- a/huff_utils/src/evm.rs
+++ b/huff_utils/src/evm.rs
@@ -302,15 +302,13 @@ pub static OPCODES_MAP: phf::Map<&'static str, Opcode> = phf_map! {
 /// EVM Opcodes
 /// References <https://evm.codes>
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, EnumString)]
+#[strum(serialize_all = "lowercase")]
 pub enum Opcode {
     /// Halts execution.
-    #[strum(serialize = "stop")]
     Stop,
     /// Addition operation
-    #[strum(serialize = "add")]
     Add,
     /// Multiplication Operation
-    #[strum(serialize = "mul")]
     Mul,
     /// Subtraction Operation
     Sub,
diff --git a/huff_utils/src/sol_interface.rs b/huff_utils/src/sol_interface.rs
index 6a68929..047d417 100644
--- a/huff_utils/src/sol_interface.rs
+++ b/huff_utils/src/sol_interface.rs
@@ -9,10 +9,7 @@ use std::{
 ///
 /// @param artifacts The vector of artifacts to generate interfaces from.
 /// @return The vector of generated interfaces.
-pub fn gen_sol_interfaces(
-    artifacts: &Vec<Arc<Artifact>>,
-    interface: Option<String>,
-) -> Vec<(PathBuf, String, String)> {
+pub fn gen_sol_interfaces(artifacts: &Vec<Arc<Artifact>>) -> Vec<(PathBuf, &str, String)> {
     let mut interfaces = Vec::new();
 
     for artifact in artifacts {
@@ -40,22 +37,6 @@ pub fn gen_sol_interfaces(
                         .join(", "),
                 ));
             });
-            a.errors.iter().for_each(|(_, e)| {
-                defs.push(format!(
-                    "{}error {}({});",
-                    "\t",
-                    e.name,
-                    e.inputs
-                        .iter()
-                        .map(|i| format!(
-                            "{}{}",
-                            i.kind,
-                            if i.kind.is_memory_type() { " memory" } else { "" }
-                        ))
-                        .collect::<Vec<_>>()
-                        .join(", "),
-                ));
-            });
             a.functions.iter().for_each(|(_, f)| {
                 defs.push(format!(
                     "{}function {}({}) external{}{};",
@@ -90,17 +71,12 @@ pub fn gen_sol_interfaces(
                 ));
             });
 
-            let interface_name = interface.clone().unwrap_or_else(|| {
-                format!(
-                    "I{}",
-                    artifact.file.path.split('/').last().unwrap().split('.').next().unwrap()
-                )
-            });
-            let formatted_str = format!("interface {} {{\n{}\n}}", interface_name, defs.join("\n"));
+            let interface_name =
+                artifact.file.path.split('/').last().unwrap().split('.').next().unwrap();
             interfaces.push((
                 Path::new(&artifact.file.path).parent().unwrap().to_path_buf(),
                 interface_name,
-                formatted_str,
+                format!("interface I{} {{\n{}\n}}", interface_name, defs.join("\n"),),
             ));
         }
     }
@@ -112,11 +88,9 @@ pub fn gen_sol_interfaces(
 ///
 /// @param interfaces The vector of generated interfaces.
 /// @return Unit type if success, error if failure.
-pub fn export_interfaces(
-    interfaces: &Vec<(PathBuf, String, String)>,
-) -> Result<(), std::io::Error> {
+pub fn export_interfaces(interfaces: &Vec<(PathBuf, &str, String)>) -> Result<(), std::io::Error> {
     for (path, name, interface) in interfaces {
-        let path_str = format!("{}/{}.sol", path.to_str().unwrap_or(""), name);
+        let path_str = format!("{}/I{}.sol", path.to_str().unwrap_or(""), name);
         let file_path = Path::new(&path_str);
         fs::write(file_path, interface)?;
     }


Test patch:
diff --git a/huff_codegen/tests/abigen.rs b/huff_codegen/tests/abigen.rs
index 94b91bc..1761e30 100644
--- a/huff_codegen/tests/abigen.rs
+++ b/huff_codegen/tests/abigen.rs
@@ -34,7 +34,6 @@ fn constructs_valid_abi() {
             constructor: Some(Constructor { inputs: vec![] }),
             functions: BTreeMap::new(),
             events: BTreeMap::new(),
-            errors: BTreeMap::new(),
             receive: false,
             fallback: false
         }
diff --git a/huff_core/tests/builtins.rs b/huff_core/tests/builtins.rs
index d233936..55592c8 100644
--- a/huff_core/tests/builtins.rs
+++ b/huff_core/tests/builtins.rs
@@ -548,51 +548,3 @@ fn test_error_selector_builtin() {
         )
     );
 }
-
-#[test]
-fn test_rightpad_builtin() {
-    let source: &str = r#"
-        #define macro MAIN() = takes (0) returns (0) {
-            __RIGHTPAD(0xa57b)
-            __RIGHTPAD(0x48656c6c6f2c20576f726c6421)
-            __RIGHTPAD(0x6d6f6f7365)
-        }
-    "#;
-
-    // Parse tokens
-    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
-    let lexer = Lexer::new(flattened_source);
-    let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
-    let mut parser = Parser::new(tokens, None);
-
-    // Parse the AST
-    let mut contract = parser.parse().unwrap();
-
-    // Derive storage pointers
-    contract.derive_storage_pointers();
-
-    // Instantiate Codegen
-    let cg = Codegen::new();
-
-    // The codegen instance should have no artifact
-    assert!(cg.artifact.is_none());
-
-    // Have Codegen create the runtime bytecode
-    let r_bytes = Codegen::generate_main_bytecode(&contract).unwrap();
-    assert_eq!(&r_bytes[2..66], "a57b000000000000000000000000000000000000000000000000000000000000");
-    assert_eq!(
-        &r_bytes[68..132],
-        "48656c6c6f2c20576f726c642100000000000000000000000000000000000000"
-    );
-    assert_eq!(
-        &r_bytes[134..198],
-        "6d6f6f7365000000000000000000000000000000000000000000000000000000"
-    );
-    assert_eq!(r_bytes.len(), (32 * 3 + 3) * 2);
-    assert_eq!(
-        r_bytes,
-        String::from(
-            "7fa57b0000000000000000000000000000000000000000000000000000000000007f48656c6c6f2c20576f726c6421000000000000000000000000000000000000007f6d6f6f7365000000000000000000000000000000000000000000000000000000"
-        )
-    );
-}
diff --git a/huff_core/tests/macro_invoc_args.rs b/huff_core/tests/macro_invoc_args.rs
new file mode 100644
index 0000000..9db1731
--- /dev/null
+++ b/huff_core/tests/macro_invoc_args.rs
@@ -0,0 +1,263 @@
+use huff_codegen::Codegen;
+use huff_lexer::Lexer;
+use huff_parser::Parser;
+use huff_utils::prelude::*;
+use std::str::FromStr;
+
+#[test]
+fn test_opcode_macro_args() {
+    let source = r#"
+        #define macro RETURN1(zero) = takes(0) returns(0) {
+            <zero> mstore
+            0x20 <zero> return
+        }
+
+        #define macro MAIN() = takes(0) returns(0) {
+            RETURN1(returndatasize)
+        }
+    "#;
+
+    // Lex + Parse
+    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
+    let lexer = Lexer::new(flattened_source);
+    let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
+    let mut parser = Parser::new(tokens, None);
+    let mut contract = parser.parse().unwrap();
+    contract.derive_storage_pointers();
+
+    // Create main and constructor bytecode
+    let main_bytecode = Codegen::generate_main_bytecode(&contract).unwrap();
+
+    // Full expected bytecode output (generated from huffc) (placed here as a reference)
+    let expected_bytecode = "60088060093d393df360ff3d5260203df3";
+
+    // Create bytecode
+    let bytecode = format!("60088060093d393df360ff{}", main_bytecode);
+
+    // Check the bytecode
+    assert_eq!(bytecode.to_lowercase(), expected_bytecode.to_lowercase());
+}
+
+#[test]
+fn test_all_opcodes_in_macro_args() {
+    for o in OPCODES {
+        let source = format!(
+            r#"
+            #define macro RETURN1(zero) = takes(0) returns(0) {{
+                <zero>
+            }}
+
+            #define macro MAIN() = takes(0) returns(0) {{
+                RETURN1({})
+            }}
+        "#,
+            o
+        );
+
+        // Lex + Parse
+        let flattened_source = FullFileSource { source: &source, file: None, spans: vec![] };
+        let lexer = Lexer::new(flattened_source);
+        let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
+        let mut parser = Parser::new(tokens, None);
+        let mut contract = parser.parse().unwrap();
+        contract.derive_storage_pointers();
+
+        // Create main and constructor bytecode
+        let main_bytecode = Codegen::generate_main_bytecode(&contract).unwrap();
+
+        // Full expected bytecode output (generated from huffc) (placed here as a reference)
+        let expected_bytecode = format!("60088060093d393df360ff{}", Opcode::from_str(o).unwrap());
+
+        // Create bytecode
+        let bytecode = format!("60088060093d393df360ff{}", main_bytecode);
+
+        // Check the bytecode
+        assert_eq!(bytecode.to_lowercase(), expected_bytecode.to_lowercase());
+    }
+}
+
+#[test]
+fn test_constant_macro_arg() {
+    let source = r#"
+            #define constant A = 0x02
+
+            #define macro RETURN1(zero) = takes(0) returns(0) {
+                <zero>
+            }
+
+            #define macro MAIN() = takes(0) returns(0) {
+                RETURN1(A)
+            }
+        "#;
+
+    // Lex + Parse
+    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
+    let lexer = Lexer::new(flattened_source);
+    let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
+    let mut parser = Parser::new(tokens, None);
+    let mut contract = parser.parse().unwrap();
+    contract.derive_storage_pointers();
+
+    // Create main and constructor bytecode
+    let main_bytecode = Codegen::generate_main_bytecode(&contract).unwrap();
+
+    // Full expected bytecode output (generated from huffc) (placed here as a reference)
+    let expected_bytecode = "60088060093d393df360ff6002";
+
+    // Create bytecode
+    let bytecode = format!("60088060093d393df360ff{}", main_bytecode);
+
+    // Check the bytecode
+    assert_eq!(bytecode.to_lowercase(), expected_bytecode.to_lowercase());
+}
+
+#[test]
+fn test_bubbled_label_call_macro_arg() {
+    let source = r#"
+            #define macro MACRO_A(zero) = takes(0) returns(0) {
+                MACRO_B(<zero>)
+            }
+
+            #define macro MACRO_B(zero) = takes(0) returns(0) {
+                <zero>
+            }
+
+            #define macro MAIN() = takes(0) returns(0) {
+                label:
+                    MACRO_A(label)
+            }
+        "#;
+
+    // Lex + Parse
+    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
+    let lexer = Lexer::new(flattened_source);
+    let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
+    let mut parser = Parser::new(tokens, None);
+    let mut contract = parser.parse().unwrap();
+    contract.derive_storage_pointers();
+
+    // Create main and constructor bytecode
+    let main_bytecode = Codegen::generate_main_bytecode(&contract).unwrap();
+
+    // Full expected bytecode output (generated from huffc) (placed here as a reference)
+    let expected_bytecode = "60088060093d393df360ff5b610000";
+
+    // Create bytecode
+    let bytecode = format!("60088060093d393df360ff{}", main_bytecode);
+
+    // Check the bytecode
+    assert_eq!(bytecode.to_lowercase(), expected_bytecode.to_lowercase());
+}
+
+#[test]
+fn test_bubbled_literal_macro_arg() {
+    let source = r#"
+            #define macro MACRO_A(zero) = takes(0) returns(0) {
+                MACRO_B(<zero>)
+            }
+
+            #define macro MACRO_B(zero) = takes(0) returns(0) {
+                <zero>
+            }
+
+            #define macro MAIN() = takes(0) returns(0) {
+                MACRO_A(0x420)
+            }
+        "#;
+
+    // Lex + Parse
+    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
+    let lexer = Lexer::new(flattened_source);
+    let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
+    let mut parser = Parser::new(tokens, None);
+    let mut contract = parser.parse().unwrap();
+    contract.derive_storage_pointers();
+
+    // Create main and constructor bytecode
+    let main_bytecode = Codegen::generate_main_bytecode(&contract).unwrap();
+
+    // Full expected bytecode output (generated from huffc) (placed here as a reference)
+    let expected_bytecode = "60088060093d393df360ff610420";
+
+    // Create bytecode
+    let bytecode = format!("60088060093d393df360ff{}", main_bytecode);
+
+    // Check the bytecode
+    assert_eq!(bytecode.to_lowercase(), expected_bytecode.to_lowercase());
+}
+
+#[test]
+fn test_bubbled_opcode_macro_arg() {
+    let source = r#"
+            #define macro MACRO_A(zero) = takes(0) returns(0) {
+                MACRO_B(<zero>)
+            }
+
+            #define macro MACRO_B(zero) = takes(0) returns(0) {
+                <zero>
+            }
+
+            #define macro MAIN() = takes(0) returns(0) {
+                MACRO_A(returndatasize)
+            }
+        "#;
+
+    // Lex + Parse
+    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
+    let lexer = Lexer::new(flattened_source);
+    let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
+    let mut parser = Parser::new(tokens, None);
+    let mut contract = parser.parse().unwrap();
+    contract.derive_storage_pointers();
+
+    // Create main and constructor bytecode
+    let main_bytecode = Codegen::generate_main_bytecode(&contract).unwrap();
+
+    // Full expected bytecode output (generated from huffc) (placed here as a reference)
+    let expected_bytecode = "60088060093d393df360ff3d";
+
+    // Create bytecode
+    let bytecode = format!("60088060093d393df360ff{}", main_bytecode);
+
+    // Check the bytecode
+    assert_eq!(bytecode.to_lowercase(), expected_bytecode.to_lowercase());
+}
+
+#[test]
+fn test_bubbled_constant_macro_arg() {
+    let source = r#"
+            #define constant A = 0x02
+
+            #define macro MACRO_A(zero) = takes(0) returns(0) {
+                MACRO_B(<zero>)
+            }
+
+            #define macro MACRO_B(zero) = takes(0) returns(0) {
+                <zero>
+            }
+
+            #define macro MAIN() = takes(0) returns(0) {
+                MACRO_A(A)
+            }
+        "#;
+
+    // Lex + Parse
+    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
+    let lexer = Lexer::new(flattened_source);
+    let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
+    let mut parser = Parser::new(tokens, None);
+    let mut contract = parser.parse().unwrap();
+    contract.derive_storage_pointers();
+
+    // Create main and constructor bytecode
+    let main_bytecode = Codegen::generate_main_bytecode(&contract).unwrap();
+
+    // Full expected bytecode output (generated from huffc) (placed here as a reference)
+    let expected_bytecode = "60088060093d393df360ff6002";
+
+    // Create bytecode
+    let bytecode = format!("60088060093d393df360ff{}", main_bytecode);
+
+    // Check the bytecode
+    assert_eq!(bytecode.to_lowercase(), expected_bytecode.to_lowercase());
+}
diff --git a/huff_core/tests/parser_errors.rs b/huff_core/tests/parser_errors.rs
index a70776b..e09cb7f 100644
--- a/huff_core/tests/parser_errors.rs
+++ b/huff_core/tests/parser_errors.rs
@@ -247,7 +247,7 @@ fn test_invalid_token_in_label_definition() {
 
 #[test]
 fn test_invalid_single_arg() {
-    for _ in [0..10_000] {
+    for _ in 0..10_000 {
         let random_char = rand::random::<u8>() as char;
         if random_char.is_numeric() ||
             !random_char.is_alphabetic() ||
diff --git a/huff_lexer/tests/builtins.rs b/huff_lexer/tests/builtins.rs
index 929085a..d69295c 100644
--- a/huff_lexer/tests/builtins.rs
+++ b/huff_lexer/tests/builtins.rs
@@ -4,15 +4,8 @@ use std::ops::Deref;
 
 #[test]
 fn parses_builtin_function_in_macro_body() {
-    let builtin_funcs = [
-        "__codesize",
-        "__tablesize",
-        "__tablestart",
-        "__FUNC_SIG",
-        "__EVENT_HASH",
-        "__ERROR",
-        "__RIGHTPAD",
-    ];
+    let builtin_funcs =
+        ["__codesize", "__tablesize", "__tablestart", "__FUNC_SIG", "__EVENT_HASH", "__ERROR"];
 
     for builtin in builtin_funcs {
         let source = &format!(
@@ -77,15 +70,8 @@ fn parses_builtin_function_in_macro_body() {
 #[test]
 #[should_panic]
 fn fails_to_parse_builtin_outside_macro_body() {
-    let builtin_funcs = [
-        "__codesize",
-        "__tablesize",
-        "__tablestart",
-        "__FUNC_SIG",
-        "__EVENT_HASH",
-        "__ERROR",
-        "__RIGHTPAD",
-    ];
+    let builtin_funcs =
+        ["__codesize", "__tablesize", "__tablestart", "__FUNC_SIG", "__EVENT_HASH", "__ERROR"];
 
     for builtin in builtin_funcs {
         let source = &format!("{}(MAIN)", builtin);
diff --git a/huff_parser/tests/error.rs b/huff_parser/tests/error.rs
index 7395864..8ffcc6a 100644
--- a/huff_parser/tests/error.rs
+++ b/huff_parser/tests/error.rs
@@ -18,12 +18,6 @@ fn test_parses_custom_error() {
         ErrorDefinition {
             name: String::from("TestError"),
             selector: [124, 104, 44, 83],
-            parameters: vec![Argument {
-                arg_type: Some(String::from("uint256")),
-                name: None,
-                indexed: false,
-                span: AstSpan(vec![Span { start: 24, end: 31, file: None }])
-            }],
             span: AstSpan(vec![
                 Span { start: 0, end: 7, file: None },
                 Span { start: 8, end: 13, file: None },
diff --git a/huff_parser/tests/labels.rs b/huff_parser/tests/labels.rs
index f7222f1..d87ca9d 100644
--- a/huff_parser/tests/labels.rs
+++ b/huff_parser/tests/labels.rs
@@ -198,7 +198,6 @@ pub fn builtins_under_labels() {
             __codesize(SMALL_MACRO)
             __FUNC_SIG(myFunc)
             __ERROR(TestError)
-            __RIGHTPAD(0xBB)
     }
     "#;
     let flattened_source = FullFileSource { source, file: None, spans: vec![] };
@@ -310,25 +309,6 @@ pub fn builtins_under_labels() {
                             Span { start: 477, end: 486, file: None },
                         ]),
                     },
-                    Statement {
-                        ty: StatementType::BuiltinFunctionCall(BuiltinFunctionCall {
-                            kind: BuiltinFunctionKind::RightPad,
-                            args: vec![Argument {
-                                arg_type: None,
-                                name: Some(String::from("bb")),
-                                indexed: false,
-                                span: AstSpan(vec![Span { start: 513, end: 515, file: None }]),
-                            }],
-                            span: AstSpan(vec![
-                                Span { start: 500, end: 510, file: None },
-                                Span { start: 513, end: 515, file: None },
-                            ]),
-                        }),
-                        span: AstSpan(vec![
-                            Span { start: 500, end: 510, file: None },
-                            Span { start: 513, end: 515, file: None },
-                        ]),
-                    },
                 ],
                 span: AstSpan(vec![
                     Span { start: 307, end: 315, file: None },
@@ -342,8 +322,6 @@ pub fn builtins_under_labels() {
                     Span { start: 449, end: 455, file: None },
                     Span { start: 469, end: 476, file: None },
                     Span { start: 477, end: 486, file: None },
-                    Span { start: 500, end: 510, file: None },
-                    Span { start: 513, end: 515, file: None },
                 ]),
             }),
             span: AstSpan(vec![
@@ -358,8 +336,6 @@ pub fn builtins_under_labels() {
                 Span { start: 449, end: 455, file: None },
                 Span { start: 469, end: 476, file: None },
                 Span { start: 477, end: 486, file: None },
-                Span { start: 500, end: 510, file: None },
-                Span { start: 513, end: 515, file: None },
             ]),
         }],
         takes: 3,
@@ -402,11 +378,7 @@ pub fn builtins_under_labels() {
             Span { start: 476, end: 477, file: None },
             Span { start: 477, end: 486, file: None },
             Span { start: 486, end: 487, file: None },
-            Span { start: 500, end: 510, file: None },
-            Span { start: 510, end: 511, file: None },
-            Span { start: 513, end: 515, file: None },
-            Span { start: 515, end: 516, file: None },
-            Span { start: 521, end: 522, file: None },
+            Span { start: 492, end: 493, file: None },
         ]),
         outlined: false,
     };
diff --git a/huff_parser/tests/macro.rs b/huff_parser/tests/macro.rs
index 34aacae..9dd24f5 100644
--- a/huff_parser/tests/macro.rs
+++ b/huff_parser/tests/macro.rs
@@ -605,6 +605,73 @@ fn macro_invocation_with_arg_call() {
     assert_eq!(parser.current_token.kind, TokenKind::Eof);
 }
 
+#[test]
+fn test_macro_opcode_arguments() {
+    let source = r#"
+    #define macro MAIN() = takes(0) returns(0) {
+        RETURN1(returndatasize)
+    }
+    "#;
+
+    // Parse tokens
+    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
+    let lexer = Lexer::new(flattened_source);
+    let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
+    let mut parser = Parser::new(tokens, None);
+
+    // Grab the first macro
+    let macro_definition = parser.parse().unwrap().macros[0].clone();
+    let expected = MacroDefinition {
+        name: "MAIN".to_string(),
+        parameters: vec![],
+        statements: vec![Statement {
+            ty: StatementType::MacroInvocation(MacroInvocation {
+                macro_name: "RETURN1".to_string(),
+                args: vec![MacroArg::Ident("returndatasize".to_string())],
+                span: AstSpan(vec![
+                    Span { start: 58, end: 65, file: None },
+                    Span { start: 65, end: 66, file: None },
+                    Span { start: 66, end: 80, file: None },
+                    Span { start: 80, end: 81, file: None },
+                ]),
+            }),
+            span: AstSpan(vec![
+                Span { start: 58, end: 65, file: None },
+                Span { start: 65, end: 66, file: None },
+                Span { start: 66, end: 80, file: None },
+                Span { start: 80, end: 81, file: None },
+            ]),
+        }],
+        takes: 0,
+        returns: 0,
+        span: AstSpan(vec![
+            Span { start: 5, end: 12, file: None },
+            Span { start: 13, end: 18, file: None },
+            Span { start: 19, end: 23, file: None },
+            Span { start: 23, end: 24, file: None },
+            Span { start: 24, end: 25, file: None },
+            Span { start: 26, end: 27, file: None },
+            Span { start: 28, end: 33, file: None },
+            Span { start: 33, end: 34, file: None },
+            Span { start: 34, end: 35, file: None },
+            Span { start: 35, end: 36, file: None },
+            Span { start: 37, end: 44, file: None },
+            Span { start: 44, end: 45, file: None },
+            Span { start: 45, end: 46, file: None },
+            Span { start: 46, end: 47, file: None },
+            Span { start: 48, end: 49, file: None },
+            Span { start: 58, end: 65, file: None },
+            Span { start: 65, end: 66, file: None },
+            Span { start: 66, end: 80, file: None },
+            Span { start: 80, end: 81, file: None },
+            Span { start: 86, end: 87, file: None },
+        ]),
+        outlined: false,
+    };
+    assert_eq!(macro_definition, expected);
+    assert_eq!(parser.current_token.kind, TokenKind::Eof);
+}
+
 #[test]
 fn macro_with_builtin_fn_call() {
     // Not valid source, just for testing