Skip to content

Commit

Permalink
SolidityError derive macro
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Benfield committed Jan 25, 2024
1 parent f57b718 commit 210b993
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 19 deletions.
61 changes: 54 additions & 7 deletions examples/erc20/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 2 additions & 11 deletions examples/erc20/src/erc20.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use alloc::{string::String, vec::Vec};
use alloc::string::String;
use core::marker::PhantomData;
use stylus_sdk::{
alloy_primitives::{Address, U256},
Expand Down Expand Up @@ -36,21 +36,12 @@ sol! {
error InsufficientAllowance(address owner, address spender, uint256 have, uint256 want);
}

#[derive(SolidityError)]
pub enum Erc20Error {
InsufficientBalance(InsufficientBalance),
InsufficientAllowance(InsufficientAllowance),
}

// We will soon provide a #[derive(SolidityError)] to clean this up
impl From<Erc20Error> for Vec<u8> {
fn from(err: Erc20Error) -> Vec<u8> {
match err {
Erc20Error::InsufficientBalance(e) => e.encode(),
Erc20Error::InsufficientAllowance(e) => e.encode(),
}
}
}

// These methods aren't exposed to other contracts
// Note: modifying storage will become much prettier soon
impl<T: Erc20Params> Erc20<T> {
Expand Down
6 changes: 6 additions & 0 deletions stylus-proc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@ pub fn derive_erase(input: TokenStream) -> TokenStream {
storage::derive_erase(input)
}

/// For an error type `E`, implement `From<E>` for `Vec<u8>`.
#[proc_macro_derive(SolidityError)]
pub fn derive_solidity_error(input: TokenStream) -> TokenStream {
storage::derive_solidity_error(input)
}

/// Defines the entrypoint, which is where Stylus execution begins.
/// Without it the contract will fail to pass [`cargo stylus check`][check].
/// Most commonly this macro is used to annotate the top level storage `struct`.
Expand Down
28 changes: 27 additions & 1 deletion stylus-proc/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::storage::proc::{SolidityField, SolidityFields, SolidityStruct, Solidi
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use std::mem;
use syn::{parse_macro_input, punctuated::Punctuated, Index, ItemStruct, Token, Type};
use syn::{parse_macro_input, punctuated::Punctuated, Fields, Index, ItemEnum, ItemStruct, Token, Type};

mod proc;

Expand Down Expand Up @@ -223,3 +223,29 @@ pub fn derive_erase(input: TokenStream) -> TokenStream {
};
output.into()
}

pub fn derive_solidity_error(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemEnum);
let name = &input.ident;
let mut match_arms = quote! {};
for variant in input.variants.iter() {
let variant_name = &variant.ident;
match variant.fields {
Fields::Unnamed(_) if variant.fields.len() == 1 => {}
_ => panic!("SolidityError: Each variant must be a tuple struct with one field"),
}
match_arms.extend(quote! {
#name::#variant_name(e) => e.encode(),
})
}
let output = quote! {
impl From<#name> for ::alloc::vec::Vec<u8> {
fn from(err: #name) -> ::alloc::vec::Vec<u8> {
match err {
#match_arms
}
}
}
};
output.into()
}

0 comments on commit 210b993

Please sign in to comment.