Skip to content

Commit

Permalink
Merge pull request #176 from OffchainLabs/raul-audit-fixes-dec-2024
Browse files Browse the repository at this point in the history
Resolve Various Audit Findings, December 2024
  • Loading branch information
rauljordan authored Dec 11, 2024
2 parents c1a645c + 7801ef6 commit e54027e
Show file tree
Hide file tree
Showing 12 changed files with 160 additions and 58 deletions.
6 changes: 3 additions & 3 deletions examples/erc20/Cargo.lock

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

4 changes: 2 additions & 2 deletions examples/erc20/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ version = "0.1.0"
edition = "2021"

[dependencies]
alloy-primitives = "0.8.13"
alloy-sol-types = "0.8.13"
alloy-primitives = "=0.8.13"
alloy-sol-types = "=0.8.13"
stylus-sdk = { path = "../../stylus-sdk" }
mini-alloc = { path = "../../mini-alloc" }

Expand Down
6 changes: 3 additions & 3 deletions examples/erc721/Cargo.lock

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

4 changes: 2 additions & 2 deletions examples/erc721/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ version = "0.1.0"
edition = "2021"

[dependencies]
alloy-primitives = "0.8.13"
alloy-sol-types = "0.8.13"
alloy-primitives = "=0.8.13"
alloy-sol-types = "=0.8.13"
stylus-sdk = { path = "../../stylus-sdk" }
mini-alloc = { path = "../../mini-alloc" }

Expand Down
6 changes: 3 additions & 3 deletions examples/single_call/Cargo.lock

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

4 changes: 2 additions & 2 deletions examples/single_call/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ keywords = ["arbitrum", "ethereum", "stylus", "alloy"]
description = "Stylus single call router contract"

[dependencies]
alloy-primitives = "0.8.13"
alloy-sol-types = "0.8.13"
alloy-primitives = "=0.8.13"
alloy-sol-types = "=0.8.13"
hex = "0.4.3"
stylus-sdk = { path = "../../stylus-sdk" }
mini-alloc = { path = "../../mini-alloc" }
Expand Down
22 changes: 21 additions & 1 deletion stylus-proc/src/macros/public/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,17 @@ impl<E: FnExtension> From<&mut syn::ImplItemFn> for PublicFn<E> {
let receive = consume_flag(&mut node.attrs, "receive");

let kind = match (fallback, receive) {
(true, false) => FnKind::Fallback,
(true, false) => {
// Fallback functions may have two signatures, either
// with input calldata and output bytes, or no input and output.
// node.sig.
let has_inputs = node.sig.inputs.len() > 1;
if has_inputs {
FnKind::FallbackWithArgs
} else {
FnKind::FallbackNoArgs
}
}
(false, true) => FnKind::Receive,
(false, false) => FnKind::Function,
(true, true) => {
Expand All @@ -116,6 +126,16 @@ impl<E: FnExtension> From<&mut syn::ImplItemFn> for PublicFn<E> {

// name for generated rust, and solidity abi
let name = node.sig.ident.clone();

if matches!(kind, FnKind::Function) && (name == "receive" || name == "fallback") {
emit_error!(
node.span(),
"receive and/or fallback functions can only be defined using the #[receive] or "
.to_string()
+ "#[fallback] attribute instead of names",
);
}

let sol_name = syn_solidity::SolIdent::new(
&selector_override.unwrap_or(name.to_string().to_case(Case::Camel)),
);
Expand Down
89 changes: 74 additions & 15 deletions stylus-proc/src/macros/public/types.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2022-2024, Offchain Labs, Inc.
// For licensing, see https://github.com/OffchainLabs/stylus-sdk-rs/blob/main/licenses/COPYRIGHT.md

use proc_macro2::{Span, TokenStream};
use proc_macro_error::emit_error;
use quote::{quote, ToTokens};
use syn::{
parse::Nothing, parse_quote, parse_quote_spanned, punctuated::Punctuated, spanned::Spanned,
Expand Down Expand Up @@ -37,23 +37,39 @@ impl PublicImpl {
inheritance,
..
} = self;
let selector_consts = self.funcs.iter().map(PublicFn::selector_const);
let selector_arms = self
let function_iter = self
.funcs
.iter()
.filter(|&func| matches!(func.kind, FnKind::Function));
let selector_consts = function_iter.clone().map(PublicFn::selector_const);
let selector_arms = function_iter
.map(PublicFn::selector_arm)
.collect::<Vec<_>>();
let inheritance_routes = self.inheritance_routes();

let call_fallback = self.call_fallback();
let inheritance_fallback = self.inheritance_fallback();
let fallback = call_fallback.unwrap_or_else(|| {
parse_quote!({
#(#inheritance_fallback)*
None
})

let (fallback, fallback_purity) = call_fallback.unwrap_or_else(|| {
// If there is no fallback function specified, we rely on any inherited fallback.
(
parse_quote!({
#(#inheritance_fallback)*
None
}),
Purity::Payable, // Let the inherited fallback deal with purity.
)
});

let fallback_deny: Option<syn::ExprIf> = match fallback_purity {
Purity::Payable => None,
_ => Some(parse_quote! {
if let Err(err) = stylus_sdk::abi::internal::deny_value("fallback") {
return Some(Err(err));
}
}),
};

let call_receive = self.call_receive();
let inheritance_receive = self.inheritance_receive();
let receive = call_receive.unwrap_or_else(|| {
Expand Down Expand Up @@ -96,11 +112,12 @@ impl PublicImpl {

#[inline(always)]
fn fallback(storage: &mut S, input: &[u8]) -> Option<stylus_sdk::ArbResult> {
#fallback_deny
#fallback
}

#[inline(always)]
fn receive(storage: &mut S) -> Option<stylus_sdk::ArbResult> {
fn receive(storage: &mut S) -> Option<()> {
#receive
}
}
Expand All @@ -117,11 +134,35 @@ impl PublicImpl {
})
}

fn call_fallback(&self) -> Option<syn::Stmt> {
self.funcs
fn call_fallback(&self) -> Option<(syn::Stmt, Purity)> {
let mut fallback_purity = Purity::View;
let fallbacks: Vec<syn::Stmt> = self
.funcs
.iter()
.find(|&func| matches!(func.kind, FnKind::Fallback))
.filter(|&func| {
if matches!(func.kind, FnKind::FallbackWithArgs)
|| matches!(func.kind, FnKind::FallbackNoArgs)
{
fallback_purity = func.purity;
return true;
}
false
})
.map(PublicFn::call_fallback)
.collect();
if fallbacks.is_empty() {
return None;
}
if fallbacks.len() > 1 {
emit_error!(
"multiple fallbacks",
"contract can only have one #[fallback] method defined"
);
}
fallbacks
.first()
.cloned()
.map(|func| (func, fallback_purity))
}

fn inheritance_fallback(&self) -> impl Iterator<Item = syn::ExprIf> + '_ {
Expand All @@ -135,10 +176,22 @@ impl PublicImpl {
}

fn call_receive(&self) -> Option<syn::Stmt> {
self.funcs
let receives: Vec<syn::Stmt> = self
.funcs
.iter()
.find(|&func| matches!(func.kind, FnKind::Receive))
.filter(|&func| matches!(func.kind, FnKind::Receive))
.map(PublicFn::call_receive)
.collect();
if receives.is_empty() {
return None;
}
if receives.len() > 1 {
emit_error!(
"multiple receives",
"contract can only have one #[receive] method defined"
);
}
receives.first().cloned()
}

fn inheritance_receive(&self) -> impl Iterator<Item = syn::ExprIf> + '_ {
Expand All @@ -155,7 +208,8 @@ impl PublicImpl {
#[derive(Debug)]
pub enum FnKind {
Function,
Fallback,
FallbackWithArgs,
FallbackNoArgs,
Receive,
}

Expand Down Expand Up @@ -279,6 +333,11 @@ impl<E: FnExtension> PublicFn<E> {
fn call_fallback(&self) -> syn::Stmt {
let name = &self.name;
let storage_arg = self.storage_arg();
if matches!(self.kind, FnKind::FallbackNoArgs) {
return parse_quote! {
return Some(Self::#name(#storage_arg));
};
}
parse_quote! {
return Some(Self::#name(#storage_arg input));
}
Expand Down
2 changes: 1 addition & 1 deletion stylus-proc/src/macros/sol_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ impl FunctionParameters {
}
}

impl<'ast> Visit<'ast> for FunctionParameters {
impl Visit<'_> for FunctionParameters {
fn visit_variable_declaration(&mut self, var: &syn_solidity::VariableDeclaration) {
let type_info = SolidityTypeInfo::from(&var.ty);
let name = match &var.name {
Expand Down
Loading

0 comments on commit e54027e

Please sign in to comment.