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/// # Constructor
521///
522/// Constructors provide a standard way to deploy, activate, and initialize a stylus contract atomically. Without
523/// them, it isn’t possible to guarantee that the Stylus contract initialization code will be executed before
524/// other methods. When using Stylus constructors, cargo-stylus sends a transaction to a proxy-contract called
525/// StylusDeployer that performs all necessary steps.
526///
527/// The constructor function must be annotated with the `#[constructor]` attribute. It can have any name, but it
528/// is advisable to call it `constructor`. There must be no constructor definition or a single constructor for a
529/// contract. Like Solidity, function overloading for constructors is not supported. Constructors may be
530/// annotated with the [`#[payable]`][payable] attribute if they are supposed to receive Ether.
531///
532/// The SDK does not automatically call the constructor of inherited contracts. You must explicitly call them in
533/// the child contract constructor. If the child contract doesn't define a constructor, the SDK won't attempt to
534/// call the parent contract constructor.
535///
536/// The constructor must receive the self parameter, and it can have any number of other parameters. The values
537/// for these parameters will be passed to the constructor when deploying the contract. The constructor should
538/// return no value or a result value with a unit type and a vector of bytes (`Result<(), Vec<u8>>`). If the
539/// constructor returns an error, the deployment will revert.
540///
541/// The SDK will ensure the constructor is called only once. To do so, it will wrap the constructor with a
542/// function that reads and writes to a specific slot in storage. When called, the constructor wrapper will check
543/// the contents of the specific slot and revert if it is different from zero. Then, after executing the
544/// constructor method, the wrapper will write a value to the specific slot, ensuring the next call to the
545/// constructor will revert.
546///
547/// ```
548/// # extern crate alloc;
549/// # use stylus_sdk::storage::StorageAddress;
550/// # use stylus_proc::public;
551/// # use alloy_primitives::Address;
552/// # struct Contract {
553/// # owner: StorageAddress,
554/// # }
555/// #[public]
556/// impl Contract {
557/// #[constructor]
558/// pub fn constructor(&mut self, owner: Address) -> Result<(), Vec<u8>> {
559/// self.owner.set(owner);
560/// Ok(())
561/// }
562/// }
563/// ```
564///
565/// In the example above, the constructor receives a single parameter: the address of the contract's owner. Note
566/// that we shouldn't use `self.vm().msg_sender()` because that will return the address of StylusDeployer.
567/// Instead, we explicitly pass the address of the contract's owner.
568///
569/// # [`pure`][pure] [`view`][view], and `write`
570///
571/// For non-payable methods the [`#[public]`][public] macro can figure state mutability out for you based
572/// on the types of the arguments. Functions with `&self` will be considered `view`, those with
573/// `&mut self` will be considered `write`, and those with neither will be considered `pure`. Please note that
574/// `pure` and `view` functions may change the state of other contracts by calling into them, or
575/// even this one if the `reentrant` feature is enabled.
576///
577/// Please refer to the [SDK Feature Overview][overview] for more information on defining methods.
578///
579/// # Inheritance, `#[inherit]`, and `#[borrow]`
580///
581/// Composition in Rust follows that of Solidity. Types that implement [`Router`], the trait that
582/// [`#[public]`][public] provides, can be connected via inheritance.
583///
584/// ```
585/// # extern crate alloc;
586/// # use alloy_primitives::U256;
587/// # use stylus_proc::{entrypoint, public, storage};
588/// # use stylus_sdk::prelude::*;
589/// # #[entrypoint] #[storage] struct Token { #[borrow] erc20: Erc20, }
590/// #[public]
591/// #[inherit(Erc20)]
592/// impl Token {
593/// pub fn mint(&mut self, amount: U256) -> Result<(), Vec<u8>> {
594/// // ...
595/// # Ok(())
596/// }
597/// }
598///
599/// #[storage] struct Erc20;
600/// #[public]
601/// impl Erc20 {
602/// pub fn balance_of() -> Result<U256, Vec<u8>> {
603/// // ...
604/// # Ok(U256::ZERO)
605/// }
606/// }
607/// ```
608///
609/// Because `Token` inherits `Erc20` in the above, if `Token` has the [`#[entrypoint]`][entrypoint], calls to the
610/// contract will first check if the requested method exists within `Token`. If a matching function is not found,
611/// it will then try the `Erc20`. Only after trying everything `Token` inherits will the call revert.
612///
613/// Note that because methods are checked in that order, if both implement the same method, the one in `Token`
614/// will override the one in `Erc20`, which won't be callable. This allows for patterns where the developer
615/// imports a crate implementing a standard, like ERC 20, and then adds or overrides just the methods they
616/// want to without modifying the imported `Erc20` type.
617///
618/// Stylus does not currently contain explicit `override` or `virtual` keywords for explicitly
619/// marking override functions. It is important, therefore, to carefully ensure that contracts are
620/// only overriding the functions.
621///
622/// Inheritance can also be chained. `#[inherit(Erc20, Erc721)]` will inherit both `Erc20` and `Erc721`, checking
623/// for methods in that order. `Erc20` and `Erc721` may also inherit other types themselves. Method resolution
624/// finds the first matching method by [`Depth First Search`][dfs].
625///
626/// Note that for the above to work, Token must implement [`Borrow<Erc20>`][Borrow] and
627/// [`BorrowMut<Erc20>`][BorrowMut]. You can implement this yourself, but for simplicity,
628/// [`#[storage]`][storage] and [`sol_storage!`][sol_storage] provide a
629/// `#[borrow]` annotation.
630///
631/// ```
632/// # extern crate alloc;
633/// # use stylus_sdk::prelude::*;
634/// # use stylus_proc::{entrypoint, public, sol_storage};
635/// sol_storage! {
636/// #[entrypoint]
637/// pub struct Token {
638/// #[borrow]
639/// Erc20 erc20;
640/// }
641///
642/// pub struct Erc20 {
643/// uint256 total;
644/// }
645/// }
646/// # #[public] impl Token {}
647/// # #[public] impl Erc20 {}
648/// ```
649///
650/// In the future we plan to simplify the SDK so that [`Borrow`][Borrow] isn't needed and so that
651/// [`Router`] composition is more configurable. The motivation for this becomes clearer in complex
652/// cases of multi-level inheritance, which we intend to improve.
653///
654/// # Exporting a Solidity interface
655///
656/// Recall that Stylus contracts are fully interoperable across all languages, including Solidity.
657/// The Stylus SDK provides tools for exporting a Solidity interface for your contract so that others
658/// can call it. This is usually done with the cargo stylus [CLI tool][cli].
659///
660/// The SDK does this automatically via a feature flag called `export-abi` that causes the
661/// [`#[public]`][public] and [`#[entrypoint]`][entrypoint] macros to generate a `main` function
662/// that prints the Solidity ABI to the console.
663///
664/// ```sh
665/// cargo run --features export-abi --target <triple>
666/// ```
667///
668/// Note that because the above actually generates a `main` function that you need to run, the target
669/// can't be `wasm32-unknown-unknown` like normal. Instead you'll need to pass in your target triple,
670/// which cargo stylus figures out for you. This `main` function is also why the following commonly
671/// appears in the `main.rs` file of Stylus contracts.
672///
673/// ```no_run
674/// #![cfg_attr(not(feature = "export-abi"), no_main)]
675/// ```
676///
677/// Here's an example output. Observe that the method names change from Rust's `snake_case` to Solidity's
678/// `camelCase`. For compatibility reasons, onchain method selectors are always `camelCase`. We'll provide
679/// the ability to customize selectors very soon. Note too that you can use argument names like "address"
680/// without fear. The SDK will prepend an `_` when necessary.
681///
682/// ```solidity
683/// interface Erc20 {
684/// function name() external pure returns (string memory);
685///
686/// function balanceOf(address _address) external view returns (uint256);
687/// }
688///
689/// interface Weth is Erc20 {
690/// function mint() external payable;
691///
692/// function burn(uint256 amount) external;
693/// }
694/// ```
695///
696/// [storage]: macro@storage
697/// [sol_storage]: macro@sol_storage
698/// [entrypoint]: macro@entrypoint
699/// [public]: macro@public
700/// [overview]: https://docs.arbitrum.io/stylus/reference/rust-sdk-guide#methods
701/// [`Router`]: https://docs.rs/stylus-sdk/latest/stylus_sdk/abi/trait.Router.html
702/// [Borrow]: https://doc.rust-lang.org/std/borrow/trait.Borrow.html
703/// [BorrowMut]: https://doc.rust-lang.org/std/borrow/trait.BorrowMut.html
704/// [value]: https://docs.rs/stylus-sdk/latest/stylus_sdk/msg/fn.value.html
705/// [payable]: https://docs.alchemy.com/docs/solidity-payable-functions
706/// [view]: https://docs.soliditylang.org/en/develop/contracts.html#view-functions
707/// [pure]: https://docs.soliditylang.org/en/develop/contracts.html#pure-functions
708/// [cli]: https://github.com/OffchainLabs/cargo-stylus#exporting-solidity-abis
709/// [dfs]: https://en.wikipedia.org/wiki/Depth-first_search
710#[proc_macro_attribute]
711#[proc_macro_error]
712pub fn public(attr: TokenStream, input: TokenStream) -> TokenStream {
713 macros::public(attr, input)
714}
715
716#[doc(hidden)]
717#[deprecated = "please use `#[public]` instead"]
718#[proc_macro_attribute]
719#[proc_macro_error]
720pub fn external(attr: TokenStream, input: TokenStream) -> TokenStream {
721 public(attr, input)
722}
723
724/// Implements the AbiType for arbitrary structs, allowing them to be used in external method
725/// return types and parameters. This derive is intended to be used within the
726/// [alloy_sol_types::sol] macro.
727///
728/// ```
729/// # use alloy_sol_types::sol;
730/// # use stylus_proc::AbiType;
731/// sol! {
732/// #[derive(AbiType)]
733/// struct Foo {
734/// uint256 bar;
735/// }
736/// }
737/// ```
738#[proc_macro_derive(AbiType)]
739#[proc_macro_error]
740pub fn derive_abi_type(input: TokenStream) -> TokenStream {
741 macros::derive_abi_type(input)
742}