stylus_proc/
lib.rs

1// Copyright 2022-2024, Offchain Labs, Inc.
2// For licensing, see https://github.com/OffchainLabs/stylus-sdk-rs/blob/main/licenses/COPYRIGHT.md
3
4//! Procedural macros for [The Stylus SDK][sdk].
5//!
6//! You can import these via
7//!
8//! ```
9//! use stylus_sdk::prelude::*;
10//! ```
11//!
12//! For a guided exploration of the features, please see the comprehensive [Feature Overview][overview].
13//!
14//! [overview]: https://docs.arbitrum.io/stylus/reference/rust-sdk-guide#calls
15//! [sdk]: https://docs.rs/stylus-sdk/latest/stylus_sdk/index.html
16
17#![warn(missing_docs)]
18
19use proc_macro::TokenStream;
20use proc_macro_error::proc_macro_error;
21
22/// Generates a pretty error message.
23/// Note that this macro is declared before all modules so that they can use it.
24macro_rules! error {
25    ($tokens:expr, $($msg:expr),+ $(,)?) => {{
26        let error = syn::Error::new(syn::spanned::Spanned::span(&$tokens), format!($($msg),+));
27        return error.to_compile_error().into();
28    }};
29    (@ $tokens:expr, $($msg:expr),+ $(,)?) => {{
30        return Err(syn::Error::new(syn::spanned::Spanned::span(&$tokens), format!($($msg),+)))
31    }};
32}
33
34mod consts;
35mod impls;
36mod imports;
37mod macros;
38mod types;
39mod utils;
40
41/// Allows a Rust `struct` to be used in persistent storage.
42///
43/// ```
44/// extern crate alloc;
45/// # use stylus_sdk::storage::{StorageAddress, StorageBool};
46/// # use stylus_proc::storage;
47/// # use stylus_sdk::prelude::*;
48/// #[storage]
49/// pub struct Contract {
50///    owner: StorageAddress,
51///    active: StorageBool,
52///    sub_struct: SubStruct,
53///}
54///
55///#[storage]
56///pub struct SubStruct {
57///    number: StorageBool,
58///}
59/// ```
60///
61/// Each field must implement [`StorageType`]. This includes other structs, which will
62/// implement the `trait` automatically when [`#[storage]`][storage] is applied.
63///
64/// One may even implement [`StorageType`] to define custom storage entries, though this is rarely necessary
65/// since the [Stylus SDK][sdk] intends to include all standard Solidity types out-of-the-box.
66///
67/// Please refer to the [SDK Feature Overview][overview] for more information on defining storage.
68///
69/// [storage]: macro@storage
70/// [`StorageType`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.StorageType.html
71/// [overview]: https://docs.arbitrum.io/stylus/reference/rust-sdk-guide#storage
72/// [sdk]: https://docs.rs/stylus-sdk/latest/stylus_sdk/index.html
73#[proc_macro_attribute]
74#[proc_macro_error]
75pub fn storage(attr: TokenStream, input: TokenStream) -> TokenStream {
76    macros::storage(attr, input)
77}
78
79/// The types in [`#[storage]`][storage] are laid out in the EVM state trie exactly
80/// as they are in [Solidity][solidity]. This means that the fields of a `struct` definition will map
81/// to the same storage slots as they would in EVM programming languages. Hence, it is often nice to
82/// define types using Solidity syntax, which makes this guarantee easier to see.
83///
84/// ```
85/// extern crate alloc;
86/// # use stylus_sdk::prelude::*;
87/// # use stylus_proc::sol_storage;
88/// sol_storage! {
89///     pub struct Contract {
90///         address owner;                      // becomes a StorageAddress
91///         bool active;                        // becomes a StorageBool
92///         SubStruct sub_struct;
93///     }
94///
95///     pub struct SubStruct {
96///         // other solidity fields, such as
97///         mapping(address => uint) balances;  // becomes a StorageMap
98///         Delegate[] delegates;               // becomes a StorageVec
99///     }
100///     pub struct Delegate {
101///     }
102/// }
103/// ```
104///
105/// The above will expand to equivalent definitions in Rust, with each structure implementing the [`StorageType`]
106/// `trait`. Many contracts, like [the ERC 20 example][erc20], do exactly this.
107///
108/// Because the layout is identical to [Solidity's][solidity], existing Solidity smart contracts can
109/// upgrade to Rust without fear of storage slots not lining up. You simply copy-paste your type definitions.
110///
111/// Consequently, the order of fields will affect the JSON ABIs produced that explorers and tooling might use.
112/// Most developers don't need to worry about this though and can freely order their types when working on a
113/// Rust contract from scratch.
114///
115///
116/// Please refer to the [SDK Feature Overview][overview] for more information on defining storage.
117///
118/// [storage]: macro@storage
119/// [`StorageType`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.StorageType.html
120/// [solidity]: https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html
121/// [overview]: https://docs.arbitrum.io/stylus/reference/rust-sdk-guide#erase-and-deriveerase
122/// [erc20]: https://github.com/OffchainLabs/stylus-sdk-rs/blob/main/examples/erc20/src/main.rs
123#[proc_macro]
124#[proc_macro_error]
125pub fn sol_storage(input: TokenStream) -> TokenStream {
126    macros::sol_storage(input)
127}
128
129/// Facilitates calls to other contracts.
130///
131/// This macro defines a `struct` for each of the Solidity interfaces provided.
132///
133/// ```
134/// # use stylus_proc::sol_interface;
135/// sol_interface! {
136///     interface IService {
137///         function makePayment(address user) external payable returns (string);
138///         function getConstant() external pure returns (bytes32);
139///     }
140///
141///     interface ITree {
142///         // other interface methods
143///     }
144/// }
145/// ```
146///
147/// The above will define `IService` and `ITree` for calling the methods of the two contracts.
148///
149/// For example, `IService` will have a `make_payment` method that accepts an [`Address`] and returns a [`B256`].
150///
151/// Currently only functions are supported, and any other items in the interface will cause an
152/// error. Additionally, each function must be marked `external`. Inheritance is not supported.
153///
154/// ```
155/// use stylus_sdk::prelude::*;
156/// use stylus_sdk::stylus_core::host::*;
157/// use stylus_sdk::stylus_core::calls::errors::*;
158/// use alloy_primitives::Address;
159/// # use stylus_proc::sol_interface;
160///
161/// # sol_interface! {
162/// #     interface IService {
163/// #         function makePayment(address user) external payable returns (string);
164/// #     }
165/// # }
166/// # mod evm { pub fn gas_left() -> u64 { 100 } }
167/// # mod msg { pub fn value() -> alloy_primitives::U256 { 100.try_into().unwrap() } }
168/// pub fn do_call(host: &impl Host, account: IService, user: Address) -> Result<String, Error> {
169///     let config = Call::new()
170///         .gas(host.evm_gas_left() / 2)       // limit to half the gas left
171///         .value(host.msg_value());           // set the callvalue
172///
173///     account.make_payment(host, config, user)  // note the snake case
174/// }
175/// ```
176///
177/// Observe the casing change. [`sol_interface!`] computes the selector based on the exact name passed in,
178/// which should almost always be `camelCase`. For aesthetics, the rust functions will instead use `snake_case`.
179///
180/// Note that structs may be used, as return types for example. Trying to reference structs using
181/// the Solidity path separator (`module.MyStruct`) is supported and paths will be converted to
182/// Rust syntax (`module::MyStruct`).
183///
184/// # Reentrant calls
185///
186/// Contracts that opt into reentrancy via the `reentrant` feature flag require extra care.
187/// When enabled, cross-contract calls must [`flush`] or [`clear`] the [`StorageCache`] to safeguard state.
188/// This happens automatically via the type system.
189///
190/// ```
191/// # extern crate alloc;
192/// # use stylus_sdk::prelude::*;
193/// # use stylus_proc::{entrypoint, public, sol_interface, storage};
194/// sol_interface! {
195///     interface IMethods {
196///         function pureFoo() external pure;
197///         function viewFoo() external view;
198///         function writeFoo() external;
199///     }
200/// }
201///
202/// #[entrypoint] #[storage] struct Contract {}
203/// #[public]
204/// impl Contract {
205///     pub fn call_pure(&self, methods: IMethods) -> Result<(), Vec<u8>> {
206///         let cfg = Call::new();
207///         Ok(methods.pure_foo(self.vm(), cfg)?)    // `pure` methods might lie about not being `view`
208///     }
209///
210///     pub fn call_view(&self, methods: IMethods) -> Result<(), Vec<u8>> {
211///         let cfg = Call::new();
212///         Ok(methods.view_foo(self.vm(), cfg)?)
213///     }
214///
215///     pub fn call_write(&mut self, methods: IMethods) -> Result<(), Vec<u8>> {
216///          let cfg = Call::new_mutating(self);
217///          Ok(methods.write_foo(self.vm(), cfg)?)
218///     }
219/// }
220/// ```
221///
222/// Another example of making a mutable, payable call to a contract using the [`sol_interface!`] macro.
223///
224/// ```
225/// use stylus_sdk::prelude::*;
226/// use stylus_sdk::stylus_core::calls::errors::*;
227/// use stylus_sdk::stylus_core::host::*;
228/// use alloy_primitives::Address;
229/// # use stylus_proc::sol_interface;
230///
231/// # sol_interface! {
232/// #     interface IService {
233/// #         function makePayment(address user) external payable returns (string);
234/// #     }
235/// # }
236/// # mod evm { pub fn gas_left() -> u64 { 100 } }
237/// # mod msg { pub fn value() -> alloy_primitives::U256 { 100.try_into().unwrap() } }
238/// pub fn do_call(
239///     host: &impl Host,
240///     account: IService,                   // serializes as an Address
241///     user: Address,
242/// ) -> Result<String, Error> {
243///
244///     let config = Call::new()
245///         .gas(evm::gas_left() / 2)        // limit to half the gas left
246///         .value(msg::value());            // set the callvalue
247///
248///     account.make_payment(host, config, user)   // note the snake case
249/// }
250/// ```
251///
252/// Note that in the context of a [`#[public]`][public] call, the `&mut impl` argument will correctly
253/// distinguish the method as being `write` or `payable`. This means you can write library code that will
254/// work regardless of whether the `reentrant` feature flag is enabled.
255///
256/// [sol_interface]: macro@sol_interface
257/// [public]: macro@public
258/// [`TopLevelStorage`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.TopLevelStorage.html
259/// [`StorageCache`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageCache.html
260/// [`flush`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageCache.html#method.flush
261/// [`clear`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageCache.html#method.clear
262/// [`Address`]: https://docs.rs/alloy-primitives/latest/alloy_primitives/struct.Address.html
263/// [`B256`]: https://docs.rs/alloy-primitives/latest/alloy_primitives/aliases/type.B256.html
264/// [`Call`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/struct.Call.html
265#[proc_macro]
266#[proc_macro_error]
267pub fn sol_interface(input: TokenStream) -> TokenStream {
268    macros::sol_interface(input)
269}
270
271/// Some [`StorageType`] values implement [`Erase`], which provides an [`erase()`] method for clearing state.
272/// [The Stylus SDK][sdk] implements [`Erase`] for all primitives, and for vectors of primitives, but not for maps.
273/// This is because a Solidity mapping does not provide iteration, and so it's generally impossible to
274/// know which slots to clear.
275///
276/// Structs may also be [`Erase`] if all of the fields are. `#[derive(Erase)]`
277/// lets you do this automatically.
278///
279/// ```
280/// extern crate alloc;
281/// # use stylus_proc::{Erase, sol_storage};
282/// # use stylus_sdk::prelude::*;
283/// sol_storage! {
284///    #[derive(Erase)]
285///    pub struct Contract {
286///        address owner;              // can erase primitive
287///        uint256[] hashes;           // can erase vector of primitive
288///    }
289///
290///    pub struct NotErase {
291///        mapping(address => uint) balances; // can't erase a map
292///        mapping(uint => uint)[] roots;     // can't erase vector of maps
293///    }
294/// }
295/// ```
296///
297/// You can also implement [`Erase`] manually if desired. Note that the reason we care about [`Erase`]
298/// at all is that you get storage refunds when clearing state, lowering fees. There's also
299/// minor implications for storage patterns using `unsafe` Rust.
300///
301/// Please refer to the [SDK Feature Overview][overview] for more information on defining storage.
302///
303/// [`StorageType`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.StorageType.html
304/// [`Erase`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.Erase.html
305/// [`erase()`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.Erase.html#tymethod.erase
306/// [overview]: https://docs.arbitrum.io/stylus/reference/rust-sdk-guide#storage
307/// [sdk]: https://docs.rs/stylus-sdk/latest/stylus_sdk/index.html
308#[proc_macro_derive(Erase)]
309#[proc_macro_error]
310pub fn derive_erase(input: TokenStream) -> TokenStream {
311    macros::derive_erase(input)
312}
313
314/// Allows an error `enum` to be used in method signatures.
315///
316/// ```
317/// # use alloy_sol_types::sol;
318/// # use stylus_proc::{public, SolidityError};
319/// # extern crate alloc;
320/// sol! {
321///     error InsufficientBalance(address from, uint256 have, uint256 want);
322///     error InsufficientAllowance(address owner, address spender, uint256 have, uint256 want);
323/// }
324///
325/// #[derive(SolidityError)]
326/// pub enum Erc20Error {
327///     InsufficientBalance(InsufficientBalance),
328///     InsufficientAllowance(InsufficientAllowance),
329/// }
330///
331/// # struct Contract {}
332/// #[public]
333/// impl Contract {
334///     pub fn fallible_method() -> Result<(), Erc20Error> {
335///         // code that might revert
336/// #       Ok(())
337///     }
338/// }
339/// ```
340///
341/// Under the hood, the above macro works by implementing `From<Erc20Error>` for `Vec<u8>`
342/// along with printing code for abi-export.
343#[proc_macro_derive(SolidityError)]
344#[proc_macro_error]
345pub fn derive_solidity_error(input: TokenStream) -> TokenStream {
346    macros::derive_solidity_error(input)
347}
348
349/// Defines the entrypoint, which is where Stylus execution begins.
350/// Without it the contract will fail to pass [`cargo stylus check`][check].
351/// Most commonly this macro is used to annotate the top level storage `struct`.
352///
353/// ```
354/// # extern crate alloc;
355/// # use stylus_proc::{entrypoint, public, sol_storage};
356/// # use stylus_sdk::prelude::*;
357/// sol_storage! {
358///     #[entrypoint]
359///     pub struct Contract {
360///     }
361///
362///     // only one entrypoint is allowed
363///     pub struct SubStruct {
364///     }
365/// }
366/// # #[public] impl Contract {}
367/// ```
368///
369/// The above will make the public methods of Contract the first to consider during invocation.
370/// See [`#[public]`][public] for more information on method selection.
371///
372/// # Bytes-in, bytes-out programming
373///
374/// A less common usage of [`#[entrypoint]`][entrypoint] is for low-level, bytes-in bytes-out programming.
375/// When applied to a free-standing function, a different way of writing smart contracts becomes possible,
376/// wherein the Stylus SDK's macros and storage types are entirely optional.
377///
378/// ```
379/// extern crate alloc;
380/// # use stylus_sdk::ArbResult;
381/// # use stylus_proc::entrypoint;
382/// # use stylus_sdk::prelude::*;
383/// #[entrypoint]
384/// fn entrypoint(calldata: Vec<u8>, _: alloc::boxed::Box<dyn stylus_sdk::stylus_core::Host>) -> ArbResult {
385///     // bytes-in, bytes-out programming
386/// #   Ok(Vec::new())
387/// }
388/// ```
389///
390/// # Reentrancy
391///
392/// If a contract calls another that then calls the first, it is said to be reentrant. By default,
393/// all Stylus programs revert when this happens. However, you can opt out of this behavior by
394/// recompiling with the `reentrant` flag.
395///
396/// ```toml
397/// stylus_sdk = { version = "0.3.0", features = ["reentrant"] }
398/// ```
399///
400/// This is dangerous, and should be done only after careful review -- ideally by 3rd-party auditors.
401/// Numerous exploits and hacks have in Web3 are attributable to developers misusing or not fully
402/// understanding reentrant patterns.
403///
404/// If enabled, the Stylus SDK will flush the storage cache in between reentrant calls, persisting values
405/// to state that might be used by inner calls. Note that preventing storage invalidation is only part
406/// of the battle in the fight against exploits. You can tell if a call is reentrant via
407/// [`msg::reentrant`][reentrant], and condition your business logic accordingly.
408///
409/// # [`TopLevelStorage`]
410///
411/// The [`#[entrypoint]`][entrypoint] macro will automatically implement the [`TopLevelStorage`] `trait`
412/// for the annotated `struct`. The single type implementing [`TopLevelStorage`] is special in that
413/// mutable access to it represents mutable access to the entire program's state.
414/// This has implications for calls via [`sol_interface`].
415///
416/// [`TopLevelStorage`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.TopLevelStorage.html
417/// [`sol_interface`]: macro@sol_interface
418/// [entrypoint]: macro@entrypoint
419/// [reentrant]: https://docs.rs/stylus-sdk/latest/stylus_sdk/msg/fn.reentrant.html
420/// [public]: macro@public
421/// [check]: https://github.com/OffchainLabs/cargo-stylus#developing-with-stylus
422#[proc_macro_attribute]
423#[proc_macro_error]
424pub fn entrypoint(attr: TokenStream, input: TokenStream) -> TokenStream {
425    macros::entrypoint(attr, input)
426}
427
428/// Just as with storage, Stylus SDK methods are Solidity ABI-equivalent. This means that contracts written
429/// in different programming languages are fully interoperable. You can even automatically export your
430/// Rust contract as a Solidity interface so that others can add it to their Solidity projects.
431///
432/// This macro makes methods "public" so that other contracts can call them by implementing the [`Router`] trait.
433///
434/// ```
435/// # extern crate alloc;
436/// # use stylus_sdk::storage::StorageAddress;
437/// # use stylus_proc::public;
438/// # use alloy_primitives::Address;
439/// # struct Contract {
440/// #     owner: StorageAddress,
441/// # }
442/// #[public]
443/// impl Contract {
444///     // our owner method is now callable by other contracts
445///     pub fn owner(&self) -> Result<Address, Vec<u8>> {
446///         Ok(self.owner.get())
447///     }
448/// }
449///
450/// impl Contract {
451///     // our set_owner method is not
452///     pub fn set_owner(&mut self, new_owner: Address) -> Result<(), Vec<u8>> {
453///         // ...
454/// #       Ok(())
455///     }
456/// }
457/// ```
458///
459/// In is example, [`Vec<u8>`] becomes the program's revert data.
460///
461/// # [`#[payable]`][payable]
462///
463/// As in Solidity, methods may accept ETH as call value.
464///
465/// ```
466/// # extern crate alloc;
467/// # use alloy_primitives::Address;
468/// # use stylus_proc::{entrypoint, public, storage};
469/// # use stylus_sdk::prelude::*;
470/// # #[entrypoint] #[storage] struct Contract { #[borrow] erc20: Erc20, }
471/// # mod msg {
472/// #     use alloy_primitives::Address;
473/// #     pub fn sender() -> Address { Address::ZERO }
474/// #     pub fn value() -> u32 { 0 }
475/// # }
476/// #[public]
477/// impl Contract {
478///     #[payable]
479///     pub fn credit(&mut self) -> Result<(), Vec<u8>> {
480///         self.erc20.add_balance(msg::sender(), msg::value())
481///     }
482/// }
483/// # #[storage] struct Erc20;
484/// # #[public]
485/// # impl Erc20 {
486/// #     pub fn add_balance(&self, sender: Address, value: u32) -> Result<(), Vec<u8>> {
487/// #         Ok(())
488/// #     }
489/// # }
490/// ```
491///
492/// In the above, [msg::value][value] is the amount of ETH passed to the contract in wei, which may be used
493/// to pay for something depending on the contract's business logic. Note that you have to annotate the method
494/// with [`#[payable]`][payable], or else calls to it will revert. This is required as a safety measure
495/// to prevent users losing funds to methods that didn't intend to accept ether.
496///
497/// # Constructor
498///
499/// Constructors provide a standard way to deploy, activate, and initialize a stylus contract atomically. Without
500/// them, it isn’t possible to guarantee that the Stylus contract initialization code will be executed before
501/// other methods. When using Stylus constructors, cargo-stylus sends a transaction to a proxy-contract called
502/// StylusDeployer that performs all necessary steps.
503///
504/// The constructor function must be annotated with the `#[constructor]` attribute. It can have any name, but it
505/// is advisable to call it `constructor`. There must be no constructor definition or a single constructor for a
506/// contract. Like Solidity, function overloading for constructors is not supported. Constructors may be
507/// annotated with the [`#[payable]`][payable] attribute if they are supposed to receive Ether.
508///
509/// The constructor must receive the self parameter, and it can have any number of other parameters. The values
510/// for these parameters will be passed to the constructor when deploying the contract. The constructor should
511/// return no value or a result value with a unit type and a vector of bytes (`Result<(), Vec<u8>>`). If the
512/// constructor returns an error, the deployment will revert.
513///
514/// The SDK will ensure the constructor is called only once. To do so, it will wrap the constructor with a
515/// function that reads and writes to a specific slot in storage. When called, the constructor wrapper will check
516/// the contents of the specific slot and revert if it is different from zero. Then, after executing the
517/// constructor method, the wrapper will write a value to the specific slot, ensuring the next call to the
518/// constructor will revert.
519///
520/// ```
521/// # extern crate alloc;
522/// # use stylus_sdk::storage::StorageAddress;
523/// # use stylus_proc::public;
524/// # use alloy_primitives::Address;
525/// # struct Contract {
526/// #     owner: StorageAddress,
527/// # }
528/// #[public]
529/// impl Contract {
530///     #[constructor]
531///     pub fn constructor(&mut self, owner: Address) -> Result<(), Vec<u8>> {
532///         self.owner.set(owner);
533///         Ok(())
534///     }
535/// }
536/// ```
537///
538/// In the example above, the constructor receives a single parameter: the address of the contract's owner. Note
539/// that we shouldn't use `self.vm().msg_sender()` because that will return the address of StylusDeployer.
540/// Instead, we explicitly pass the address of the contract's owner.
541///
542/// # [`pure`][pure] [`view`][view], and `write`
543///
544/// For non-payable methods the [`#[public]`][public] macro can figure state mutability out for you based
545/// on the types of the arguments. Functions with `&self` will be considered `view`, those with
546/// `&mut self` will be considered `write`, and those with neither will be considered `pure`. Please note that
547/// `pure` and `view` functions may change the state of other contracts by calling into them, or
548/// even this one if the `reentrant` feature is enabled.
549///
550/// Please refer to the [SDK Feature Overview][overview] for more information on defining methods.
551///
552/// # Exporting a Solidity interface
553///
554/// Recall that Stylus contracts are fully interoperable across all languages, including Solidity.
555/// The Stylus SDK provides tools for exporting a Solidity interface for your contract so that others
556/// can call it. This is usually done with the cargo stylus [CLI tool][cli].
557///
558/// The SDK does this automatically via a feature flag called `export-abi` that causes the
559/// [`#[public]`][public] and [`#[entrypoint]`][entrypoint] macros to generate a `main` function
560/// that prints the Solidity ABI to the console.
561///
562/// ```sh
563/// cargo run --features export-abi --target <triple>
564/// ```
565///
566/// Note that because the above actually generates a `main` function that you need to run, the target
567/// can't be `wasm32-unknown-unknown` like normal. Instead you'll need to pass in your target triple,
568/// which cargo stylus figures out for you. This `main` function is also why the following commonly
569/// appears in the `main.rs` file of Stylus contracts.
570///
571/// ```no_run
572/// #![cfg_attr(not(feature = "export-abi"), no_main)]
573/// ```
574///
575/// Here's an example output. Observe that the method names change from Rust's `snake_case` to Solidity's
576/// `camelCase`. For compatibility reasons, onchain method selectors are always `camelCase`. We'll provide
577/// the ability to customize selectors very soon. Note too that you can use argument names like "address"
578/// without fear. The SDK will prepend an `_` when necessary.
579///
580/// ```solidity
581/// interface Erc20 {
582///     function name() external pure returns (string memory);
583///
584///     function balanceOf(address _address) external view returns (uint256);
585/// }
586///
587/// interface Weth is Erc20 {
588///     function mint() external payable;
589///
590///     function burn(uint256 amount) external;
591/// }
592/// ```
593///
594/// [storage]: macro@storage
595/// [sol_storage]: macro@sol_storage
596/// [entrypoint]: macro@entrypoint
597/// [public]: macro@public
598/// [overview]: https://docs.arbitrum.io/stylus/reference/rust-sdk-guide#methods
599/// [`Router`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/abi/trait.Router.html
600/// [Borrow]: https://doc.rust-lang.org/std/borrow/trait.Borrow.html
601/// [BorrowMut]: https://doc.rust-lang.org/std/borrow/trait.BorrowMut.html
602/// [value]: https://docs.rs/stylus-sdk/latest/stylus_sdk/msg/fn.value.html
603/// [payable]: https://docs.alchemy.com/docs/solidity-payable-functions
604/// [view]: https://docs.soliditylang.org/en/develop/contracts.html#view-functions
605/// [pure]: https://docs.soliditylang.org/en/develop/contracts.html#pure-functions
606/// [cli]: https://github.com/OffchainLabs/cargo-stylus#exporting-solidity-abis
607/// [dfs]: https://en.wikipedia.org/wiki/Depth-first_search
608#[proc_macro_attribute]
609#[proc_macro_error]
610pub fn public(attr: TokenStream, input: TokenStream) -> TokenStream {
611    macros::public(attr, input)
612}
613
614/// Implements the AbiType for arbitrary structs, allowing them to be used in external method
615/// return types and parameters. This derive is intended to be used within the
616/// [alloy_sol_types::sol] macro.
617///
618/// ```
619/// # extern crate alloc;
620/// # use alloy_sol_types::sol;
621/// # use stylus_proc::AbiType;
622/// sol! {
623///     #[derive(AbiType)]
624///     struct Foo {
625///         uint256 bar;
626///     }
627/// }
628/// ```
629#[proc_macro_derive(AbiType)]
630#[proc_macro_error]
631pub fn derive_abi_type(input: TokenStream) -> TokenStream {
632    macros::derive_abi_type(input)
633}