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#[doc(hidden)]
80#[deprecated = "please use `#[storage]` instead"]
81#[proc_macro_attribute]
82#[proc_macro_error]
83pub fn solidity_storage(attr: TokenStream, input: TokenStream) -> TokenStream {
84    macros::storage(attr, input)
85}
86
87/// The types in [`#[storage]`][storage] are laid out in the EVM state trie exactly
88/// as they are in [Solidity][solidity]. This means that the fields of a `struct` definition will map
89/// to the same storage slots as they would in EVM programming languages. Hence, it is often nice to
90/// define types using Solidity syntax, which makes this guarantee easier to see.
91///
92/// ```
93/// extern crate alloc;
94/// # use stylus_sdk::prelude::*;
95/// # use stylus_proc::sol_storage;
96/// sol_storage! {
97///     pub struct Contract {
98///         address owner;                      // becomes a StorageAddress
99///         bool active;                        // becomes a StorageBool
100///         SubStruct sub_struct;
101///     }
102///
103///     pub struct SubStruct {
104///         // other solidity fields, such as
105///         mapping(address => uint) balances;  // becomes a StorageMap
106///         Delegate[] delegates;               // becomes a StorageVec
107///     }
108///     pub struct Delegate {
109///     }
110/// }
111/// ```
112///
113/// The above will expand to equivalent definitions in Rust, with each structure implementing the [`StorageType`]
114/// `trait`. Many contracts, like [the ERC 20 example][erc20], do exactly this.
115///
116/// Because the layout is identical to [Solidity's][solidity], existing Solidity smart contracts can
117/// upgrade to Rust without fear of storage slots not lining up. You simply copy-paste your type definitions.
118///
119/// Note that one exception to this storage layout guarantee is contracts which utilize
120/// inheritance. The current solution in Stylus using `#[borrow]` and `#[inherits(...)]` packs
121/// nested (inherited) structs into their own slots. This is consistent with regular struct nesting
122/// in solidity, but not inherited structs. We plan to revisit this behavior in an upcoming
123/// release.
124///
125/// Consequently, the order of fields will affect the JSON ABIs produced that explorers and tooling might use.
126/// Most developers don't need to worry about this though and can freely order their types when working on a
127/// Rust contract from scratch.
128///
129///
130/// Please refer to the [SDK Feature Overview][overview] for more information on defining storage.
131///
132/// [storage]: macro@storage
133/// [`StorageType`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.StorageType.html
134/// [solidity]: https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html
135/// [overview]: https://docs.arbitrum.io/stylus/reference/rust-sdk-guide#erase-and-deriveerase
136/// [erc20]: https://github.com/OffchainLabs/stylus-sdk-rs/blob/main/examples/erc20/src/main.rs
137#[proc_macro]
138#[proc_macro_error]
139pub fn sol_storage(input: TokenStream) -> TokenStream {
140    macros::sol_storage(input)
141}
142
143/// Facilitates calls to other contracts.
144///
145/// This macro defines a `struct` for each of the Solidity interfaces provided.
146///
147/// ```
148/// # use stylus_proc::sol_interface;
149/// sol_interface! {
150///     interface IService {
151///         function makePayment(address user) external payable returns (string);
152///         function getConstant() external pure returns (bytes32);
153///     }
154///
155///     interface ITree {
156///         // other interface methods
157///     }
158/// }
159/// ```
160///
161/// The above will define `IService` and `ITree` for calling the methods of the two contracts.
162///
163/// For example, `IService` will have a `make_payment` method that accepts an [`Address`] and returns a [`B256`].
164///
165/// Currently only functions are supported, and any other items in the interface will cause an
166/// error. Additionally, each function must be marked `external`. Inheritance is not supported.
167///
168/// ```
169/// use stylus_sdk::call::{Call, Error};
170/// use alloy_primitives::Address;
171/// # use stylus_proc::sol_interface;
172///
173/// # sol_interface! {
174/// #     interface IService {
175/// #         function makePayment(address user) external payable returns (string);
176/// #     }
177/// # }
178/// # mod evm { pub fn gas_left() -> u64 { 100 } }
179/// # mod msg { pub fn value() -> alloy_primitives::U256 { 100.try_into().unwrap() } }
180/// pub fn do_call(account: IService, user: Address) -> Result<String, Error> {
181///     let config = Call::new()
182///         .gas(evm::gas_left() / 2)       // limit to half the gas left
183///         .value(msg::value());           // set the callvalue
184///
185///     account.make_payment(config, user)  // note the snake case
186/// }
187/// ```
188///
189/// Observe the casing change. [`sol_interface!`] computes the selector based on the exact name passed in,
190/// which should almost always be `camelCase`. For aesthetics, the rust functions will instead use `snake_case`.
191///
192/// Note that structs may be used, as return types for example. Trying to reference structs using
193/// the Solidity path separator (`module.MyStruct`) is supported and paths will be converted to
194/// Rust syntax (`module::MyStruct`).
195///
196/// # Reentrant calls
197///
198/// Contracts that opt into reentrancy via the `reentrant` feature flag require extra care.
199/// When enabled, cross-contract calls must [`flush`] or [`clear`] the [`StorageCache`] to safeguard state.
200/// This happens automatically via the type system.
201///
202/// ```
203/// # extern crate alloc;
204/// # use stylus_sdk::call::Call;
205/// # use stylus_sdk::prelude::*;
206/// # use stylus_proc::{entrypoint, public, sol_interface, storage};
207/// sol_interface! {
208///     interface IMethods {
209///         function pureFoo() external pure;
210///         function viewFoo() external view;
211///         function writeFoo() external;
212///         function payableFoo() external payable;
213///     }
214/// }
215///
216/// #[entrypoint] #[storage] struct Contract {}
217/// #[public]
218/// impl Contract {
219///     pub fn call_pure(&self, methods: IMethods) -> Result<(), Vec<u8>> {
220///         Ok(methods.pure_foo(self)?)    // `pure` methods might lie about not being `view`
221///     }
222///
223///     pub fn call_view(&self, methods: IMethods) -> Result<(), Vec<u8>> {
224///         Ok(methods.view_foo(self)?)
225///     }
226///
227///     pub fn call_write(&mut self, methods: IMethods) -> Result<(), Vec<u8>> {
228///         methods.view_foo(&mut *self)?;       // allows `pure` and `view` methods too
229///         Ok(methods.write_foo(self)?)
230///     }
231///
232///     #[payable]
233///     pub fn call_payable(&mut self, methods: IMethods) -> Result<(), Vec<u8>> {
234///         methods.write_foo(Call::new_in(self))?;   // these are the same
235///         Ok(methods.payable_foo(self)?)            // ------------------
236///     }
237/// }
238/// ```
239///
240/// In the above, we're able to pass `&self` and `&mut self` because `Contract` implements
241/// [`TopLevelStorage`], which means that a reference to it entails access to the entirety of
242/// the contract's state. This is the reason it is sound to make a call, since it ensures all
243/// cached values are invalidated and/or persisted to state at the right time.
244///
245/// When writing Stylus libraries, a type might not be [`TopLevelStorage`] and therefore
246/// `&self` or `&mut self` won't work. Building a [`Call`] from a generic parameter is the usual solution.
247///
248/// ```
249/// use stylus_sdk::{call::{Call, Error}};
250/// use stylus_sdk::stylus_core::storage::TopLevelStorage;
251/// use alloy_primitives::Address;
252/// # use stylus_proc::sol_interface;
253///
254/// # sol_interface! {
255/// #     interface IService {
256/// #         function makePayment(address user) external payable returns (string);
257/// #     }
258/// # }
259/// # mod evm { pub fn gas_left() -> u64 { 100 } }
260/// # mod msg { pub fn value() -> alloy_primitives::U256 { 100.try_into().unwrap() } }
261/// pub fn do_call(
262///     storage: &mut impl TopLevelStorage,  // can be generic, but often just &mut self
263///     account: IService,                   // serializes as an Address
264///     user: Address,
265/// ) -> Result<String, Error> {
266///
267///     let config = Call::new_in(storage)
268///         .gas(evm::gas_left() / 2)        // limit to half the gas left
269///         .value(msg::value());            // set the callvalue
270///
271///     account.make_payment(config, user)   // note the snake case
272/// }
273/// ```
274///
275/// Note that in the context of a [`#[public]`][public] call, the `&mut impl` argument will correctly
276/// distinguish the method as being `write` or `payable`. This means you can write library code that will
277/// work regardless of whether the `reentrant` feature flag is enabled.
278///
279/// [sol_interface]: macro@sol_interface
280/// [public]: macro@public
281/// [`TopLevelStorage`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.TopLevelStorage.html
282/// [`StorageCache`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageCache.html
283/// [`flush`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageCache.html#method.flush
284/// [`clear`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/struct.StorageCache.html#method.clear
285/// [`Address`]: https://docs.rs/alloy-primitives/latest/alloy_primitives/struct.Address.html
286/// [`B256`]: https://docs.rs/alloy-primitives/latest/alloy_primitives/aliases/type.B256.html
287/// [`Call`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/call/struct.Call.html
288#[proc_macro]
289#[proc_macro_error]
290pub fn sol_interface(input: TokenStream) -> TokenStream {
291    macros::sol_interface(input)
292}
293
294/// Some [`StorageType`] values implement [`Erase`], which provides an [`erase()`] method for clearing state.
295/// [The Stylus SDK][sdk] implements [`Erase`] for all primitives, and for vectors of primitives, but not for maps.
296/// This is because a Solidity mapping does not provide iteration, and so it's generally impossible to
297/// know which slots to clear.
298///
299/// Structs may also be [`Erase`] if all of the fields are. `#[derive(Erase)]`
300/// lets you do this automatically.
301///
302/// ```
303/// extern crate alloc;
304/// # use stylus_proc::{Erase, sol_storage};
305/// # use stylus_sdk::prelude::*;
306/// sol_storage! {
307///    #[derive(Erase)]
308///    pub struct Contract {
309///        address owner;              // can erase primitive
310///        uint256[] hashes;           // can erase vector of primitive
311///    }
312///
313///    pub struct NotErase {
314///        mapping(address => uint) balances; // can't erase a map
315///        mapping(uint => uint)[] roots;     // can't erase vector of maps
316///    }
317/// }
318/// ```
319///
320/// You can also implement [`Erase`] manually if desired. Note that the reason we care about [`Erase`]
321/// at all is that you get storage refunds when clearing state, lowering fees. There's also
322/// minor implications for storage patterns using `unsafe` Rust.
323///
324/// Please refer to the [SDK Feature Overview][overview] for more information on defining storage.
325///
326/// [`StorageType`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.StorageType.html
327/// [`Erase`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.Erase.html
328/// [`erase()`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.Erase.html#tymethod.erase
329/// [overview]: https://docs.arbitrum.io/stylus/reference/rust-sdk-guide#storage
330/// [sdk]: https://docs.rs/stylus-sdk/latest/stylus_sdk/index.html
331#[proc_macro_derive(Erase)]
332#[proc_macro_error]
333pub fn derive_erase(input: TokenStream) -> TokenStream {
334    macros::derive_erase(input)
335}
336
337/// Allows an error `enum` to be used in method signatures.
338///
339/// ```
340/// # use alloy_sol_types::sol;
341/// # use stylus_proc::{public, SolidityError};
342/// # extern crate alloc;
343/// sol! {
344///     error InsufficientBalance(address from, uint256 have, uint256 want);
345///     error InsufficientAllowance(address owner, address spender, uint256 have, uint256 want);
346/// }
347///
348/// #[derive(SolidityError)]
349/// pub enum Erc20Error {
350///     InsufficientBalance(InsufficientBalance),
351///     InsufficientAllowance(InsufficientAllowance),
352/// }
353///
354/// # struct Contract {}
355/// #[public]
356/// impl Contract {
357///     pub fn fallible_method() -> Result<(), Erc20Error> {
358///         // code that might revert
359/// #       Ok(())
360///     }
361/// }
362/// ```
363///
364/// Under the hood, the above macro works by implementing `From<Erc20Error>` for `Vec<u8>`
365/// along with printing code for abi-export.
366#[proc_macro_derive(SolidityError)]
367#[proc_macro_error]
368pub fn derive_solidity_error(input: TokenStream) -> TokenStream {
369    macros::derive_solidity_error(input)
370}
371
372/// Defines the entrypoint, which is where Stylus execution begins.
373/// Without it the contract will fail to pass [`cargo stylus check`][check].
374/// Most commonly this macro is used to annotate the top level storage `struct`.
375///
376/// ```
377/// # extern crate alloc;
378/// # use stylus_proc::{entrypoint, public, sol_storage};
379/// # use stylus_sdk::prelude::*;
380/// sol_storage! {
381///     #[entrypoint]
382///     pub struct Contract {
383///     }
384///
385///     // only one entrypoint is allowed
386///     pub struct SubStruct {
387///     }
388/// }
389/// # #[public] impl Contract {}
390/// ```
391///
392/// The above will make the public methods of Contract the first to consider during invocation.
393/// See [`#[public]`][public] for more information on method selection.
394///
395/// # Bytes-in, bytes-out programming
396///
397/// A less common usage of [`#[entrypoint]`][entrypoint] is for low-level, bytes-in bytes-out programming.
398/// When applied to a free-standing function, a different way of writing smart contracts becomes possible,
399/// wherein the Stylus SDK's macros and storage types are entirely optional.
400///
401/// ```
402/// extern crate alloc;
403/// # use stylus_sdk::ArbResult;
404/// # use stylus_proc::entrypoint;
405/// # use stylus_sdk::prelude::*;
406/// #[entrypoint]
407/// fn entrypoint(calldata: Vec<u8>, _: alloc::boxed::Box<dyn stylus_sdk::stylus_core::Host>) -> ArbResult {
408///     // bytes-in, bytes-out programming
409/// #   Ok(Vec::new())
410/// }
411/// ```
412///
413/// # Reentrancy
414///
415/// If a contract calls another that then calls the first, it is said to be reentrant. By default,
416/// all Stylus programs revert when this happens. However, you can opt out of this behavior by
417/// recompiling with the `reentrant` flag.
418///
419/// ```toml
420/// stylus_sdk = { version = "0.3.0", features = ["reentrant"] }
421/// ```
422///
423/// This is dangerous, and should be done only after careful review -- ideally by 3rd-party auditors.
424/// Numerous exploits and hacks have in Web3 are attributable to developers misusing or not fully
425/// understanding reentrant patterns.
426///
427/// If enabled, the Stylus SDK will flush the storage cache in between reentrant calls, persisting values
428/// to state that might be used by inner calls. Note that preventing storage invalidation is only part
429/// of the battle in the fight against exploits. You can tell if a call is reentrant via
430/// [`msg::reentrant`][reentrant], and condition your business logic accordingly.
431///
432/// # [`TopLevelStorage`]
433///
434/// The [`#[entrypoint]`][entrypoint] macro will automatically implement the [`TopLevelStorage`] `trait`
435/// for the annotated `struct`. The single type implementing [`TopLevelStorage`] is special in that
436/// mutable access to it represents mutable access to the entire program's state.
437/// This has implications for calls via [`sol_interface`].
438///
439/// [`TopLevelStorage`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/storage/trait.TopLevelStorage.html
440/// [`sol_interface`]: macro@sol_interface
441/// [entrypoint]: macro@entrypoint
442/// [reentrant]: https://docs.rs/stylus-sdk/latest/stylus_sdk/msg/fn.reentrant.html
443/// [public]: macro@public
444/// [check]: https://github.com/OffchainLabs/cargo-stylus#developing-with-stylus
445#[proc_macro_attribute]
446#[proc_macro_error]
447pub fn entrypoint(attr: TokenStream, input: TokenStream) -> TokenStream {
448    macros::entrypoint(attr, input)
449}
450
451/// Just as with storage, Stylus SDK methods are Solidity ABI-equivalent. This means that contracts written
452/// in different programming languages are fully interoperable. You can even automatically export your
453/// Rust contract as a Solidity interface so that others can add it to their Solidity projects.
454///
455/// This macro makes methods "public" so that other contracts can call them by implementing the [`Router`] trait.
456///
457/// ```
458/// # extern crate alloc;
459/// # use stylus_sdk::storage::StorageAddress;
460/// # use stylus_proc::public;
461/// # use alloy_primitives::Address;
462/// # struct Contract {
463/// #     owner: StorageAddress,
464/// # }
465/// #[public]
466/// impl Contract {
467///     // our owner method is now callable by other contracts
468///     pub fn owner(&self) -> Result<Address, Vec<u8>> {
469///         Ok(self.owner.get())
470///     }
471/// }
472///
473/// impl Contract {
474///     // our set_owner method is not
475///     pub fn set_owner(&mut self, new_owner: Address) -> Result<(), Vec<u8>> {
476///         // ...
477/// #       Ok(())
478///     }
479/// }
480/// ```
481///
482/// In is example, [`Vec<u8>`] becomes the program's revert data.
483///
484/// # [`#[payable]`][payable]
485///
486/// As in Solidity, methods may accept ETH as call value.
487///
488/// ```
489/// # extern crate alloc;
490/// # use alloy_primitives::Address;
491/// # use stylus_proc::{entrypoint, public, storage};
492/// # use stylus_sdk::prelude::*;
493/// # #[entrypoint] #[storage] struct Contract { #[borrow] erc20: Erc20, }
494/// # mod msg {
495/// #     use alloy_primitives::Address;
496/// #     pub fn sender() -> Address { Address::ZERO }
497/// #     pub fn value() -> u32 { 0 }
498/// # }
499/// #[public]
500/// impl Contract {
501///     #[payable]
502///     pub fn credit(&mut self) -> Result<(), Vec<u8>> {
503///         self.erc20.add_balance(msg::sender(), msg::value())
504///     }
505/// }
506/// # #[storage] struct Erc20;
507/// # #[public]
508/// # impl Erc20 {
509/// #     pub fn add_balance(&self, sender: Address, value: u32) -> Result<(), Vec<u8>> {
510/// #         Ok(())
511/// #     }
512/// # }
513/// ```
514///
515/// In the above, [msg::value][value] is the amount of ETH passed to the contract in wei, which may be used
516/// to pay for something depending on the contract's business logic. Note that you have to annotate the method
517/// with [`#[payable]`][payable], or else calls to it will revert. This is required as a safety measure
518/// to prevent users losing funds to methods that didn't intend to accept ether.
519///
520/// # [`pure`][pure] [`view`][view], and `write`
521///
522/// For non-payable methods the [`#[public]`][public] macro can figure state mutability out for you based
523/// on the types of the arguments. Functions with `&self` will be considered `view`, those with
524/// `&mut self` will be considered `write`, and those with neither will be considered `pure`. Please note that
525/// `pure` and `view` functions may change the state of other contracts by calling into them, or
526/// even this one if the `reentrant` feature is enabled.
527///
528/// Please refer to the [SDK Feature Overview][overview] for more information on defining methods.
529///
530/// # Inheritance, `#[inherit]`, and `#[borrow]`
531///
532/// Composition in Rust follows that of Solidity. Types that implement [`Router`], the trait that
533/// [`#[public]`][public] provides, can be connected via inheritance.
534///
535/// ```
536/// # extern crate alloc;
537/// # use alloy_primitives::U256;
538/// # use stylus_proc::{entrypoint, public, storage};
539/// # use stylus_sdk::prelude::*;
540/// # #[entrypoint] #[storage] struct Token { #[borrow] erc20: Erc20, }
541/// #[public]
542/// #[inherit(Erc20)]
543/// impl Token {
544///     pub fn mint(&mut self, amount: U256) -> Result<(), Vec<u8>> {
545///         // ...
546/// #       Ok(())
547///     }
548/// }
549///
550/// #[storage] struct Erc20;
551/// #[public]
552/// impl Erc20 {
553///     pub fn balance_of() -> Result<U256, Vec<u8>> {
554///         // ...
555/// #       Ok(U256::ZERO)
556///     }
557/// }
558/// ```
559///
560/// Because `Token` inherits `Erc20` in the above, if `Token` has the [`#[entrypoint]`][entrypoint], calls to the
561/// contract will first check if the requested method exists within `Token`. If a matching function is not found,
562/// it will then try the `Erc20`. Only after trying everything `Token` inherits will the call revert.
563///
564/// Note that because methods are checked in that order, if both implement the same method, the one in `Token`
565/// will override the one in `Erc20`, which won't be callable. This allows for patterns where the developer
566/// imports a crate implementing a standard, like ERC 20, and then adds or overrides just the methods they
567/// want to without modifying the imported `Erc20` type.
568///
569/// Stylus does not currently contain explicit `override` or `virtual` keywords for explicitly
570/// marking override functions. It is important, therefore, to carefully ensure that contracts are
571/// only overriding the functions.
572///
573/// Inheritance can also be chained. `#[inherit(Erc20, Erc721)]` will inherit both `Erc20` and `Erc721`, checking
574/// for methods in that order. `Erc20` and `Erc721` may also inherit other types themselves. Method resolution
575/// finds the first matching method by [`Depth First Search`][dfs].
576///
577/// Note that for the above to work, Token must implement [`Borrow<Erc20>`][Borrow] and
578/// [`BorrowMut<Erc20>`][BorrowMut]. You can implement this yourself, but for simplicity,
579/// [`#[storage]`][storage] and [`sol_storage!`][sol_storage] provide a
580/// `#[borrow]` annotation.
581///
582/// ```
583/// # extern crate alloc;
584/// # use stylus_sdk::prelude::*;
585/// # use stylus_proc::{entrypoint, public, sol_storage};
586/// sol_storage! {
587///     #[entrypoint]
588///     pub struct Token {
589///         #[borrow]
590///         Erc20 erc20;
591///     }
592///
593///     pub struct Erc20 {
594///         uint256 total;
595///     }
596/// }
597/// # #[public] impl Token {}
598/// # #[public] impl Erc20 {}
599/// ```
600///
601/// In the future we plan to simplify the SDK so that [`Borrow`][Borrow] isn't needed and so that
602/// [`Router`] composition is more configurable. The motivation for this becomes clearer in complex
603/// cases of multi-level inheritance, which we intend to improve.
604///
605/// # Exporting a Solidity interface
606///
607/// Recall that Stylus contracts are fully interoperable across all languages, including Solidity.
608/// The Stylus SDK provides tools for exporting a Solidity interface for your contract so that others
609/// can call it. This is usually done with the cargo stylus [CLI tool][cli].
610///
611/// The SDK does this automatically via a feature flag called `export-abi` that causes the
612/// [`#[public]`][public] and [`#[entrypoint]`][entrypoint] macros to generate a `main` function
613/// that prints the Solidity ABI to the console.
614///
615/// ```sh
616/// cargo run --features export-abi --target <triple>
617/// ```
618///
619/// Note that because the above actually generates a `main` function that you need to run, the target
620/// can't be `wasm32-unknown-unknown` like normal. Instead you'll need to pass in your target triple,
621/// which cargo stylus figures out for you. This `main` function is also why the following commonly
622/// appears in the `main.rs` file of Stylus contracts.
623///
624/// ```no_run
625/// #![cfg_attr(not(feature = "export-abi"), no_main)]
626/// ```
627///
628/// Here's an example output. Observe that the method names change from Rust's `snake_case` to Solidity's
629/// `camelCase`. For compatibility reasons, onchain method selectors are always `camelCase`. We'll provide
630/// the ability to customize selectors very soon. Note too that you can use argument names like "address"
631/// without fear. The SDK will prepend an `_` when necessary.
632///
633/// ```solidity
634/// interface Erc20 {
635///     function name() external pure returns (string memory);
636///
637///     function balanceOf(address _address) external view returns (uint256);
638/// }
639///
640/// interface Weth is Erc20 {
641///     function mint() external payable;
642///
643///     function burn(uint256 amount) external;
644/// }
645/// ```
646///
647/// [storage]: macro@storage
648/// [sol_storage]: macro@sol_storage
649/// [entrypoint]: macro@entrypoint
650/// [public]: macro@public
651/// [overview]: https://docs.arbitrum.io/stylus/reference/rust-sdk-guide#methods
652/// [`Router`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/abi/trait.Router.html
653/// [Borrow]: https://doc.rust-lang.org/std/borrow/trait.Borrow.html
654/// [BorrowMut]: https://doc.rust-lang.org/std/borrow/trait.BorrowMut.html
655/// [value]: https://docs.rs/stylus-sdk/latest/stylus_sdk/msg/fn.value.html
656/// [payable]: https://docs.alchemy.com/docs/solidity-payable-functions
657/// [view]: https://docs.soliditylang.org/en/develop/contracts.html#view-functions
658/// [pure]: https://docs.soliditylang.org/en/develop/contracts.html#pure-functions
659/// [cli]: https://github.com/OffchainLabs/cargo-stylus#exporting-solidity-abis
660/// [dfs]: https://en.wikipedia.org/wiki/Depth-first_search
661#[proc_macro_attribute]
662#[proc_macro_error]
663pub fn public(attr: TokenStream, input: TokenStream) -> TokenStream {
664    macros::public(attr, input)
665}
666
667#[doc(hidden)]
668#[deprecated = "please use `#[public]` instead"]
669#[proc_macro_attribute]
670#[proc_macro_error]
671pub fn external(attr: TokenStream, input: TokenStream) -> TokenStream {
672    public(attr, input)
673}
674
675/// Implements the AbiType for arbitrary structs, allowing them to be used in external method
676/// return types and parameters. This derive is intended to be used within the
677/// [alloy_sol_types::sol] macro.
678///
679/// ```
680/// # use alloy_sol_types::sol;
681/// # use stylus_proc::AbiType;
682/// sol! {
683///     #[derive(AbiType)]
684///     struct Foo {
685///         uint256 bar;
686///     }
687/// }
688/// ```
689#[proc_macro_derive(AbiType)]
690#[proc_macro_error]
691pub fn derive_abi_type(input: TokenStream) -> TokenStream {
692    macros::derive_abi_type(input)
693}