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}