ab_contracts_macros/
lib.rs

1//! Macros for contracts
2#![no_std]
3
4#[doc(hidden)]
5pub mod __private;
6
7/// `#[contract]` macro to derive contract implementation.
8///
9/// This macro is supposed to be applied to an implementation of the struct that in turn implements
10/// [`IoType`] trait. [`IoType`] is most commonly obtained by deriving [`TrivialType`] ([`IoType`]
11/// is implemented for all types that implement [`TrivialType`]).
12///
13/// `#[contract]` macro will process *public* methods annotated with the following attributes:
14/// * `#[init]` - method that can be called to produce an initial state of the contract,
15///   called once during contacts lifetime
16/// * `#[update]` - method that can read and/or modify state and/or slots of the contact, may be
17///   called by user transaction directly or by another contract
18/// * `#[view]` - method that can only read blockchain data, can read state or slots of the
19///   contract, but can't modify their contents
20///
21/// Each argument (except `self`) of these methods has to be annotated with one of the following
22/// attributes (must be in this order):
23/// * `#[env]` - environment variable, used to access ephemeral execution environment, call methods
24///   on other contracts, etc.
25/// * `#[tmp]` - temporary ephemeral value to store auxiliary data while processing a transaction
26/// * `#[slot]` - slot corresponding to this contract
27/// * `#[input]` - method input coming from user transaction or invocation from another contract
28/// * `#[output]` - method output, may serve as an alternative to returning values from a function
29///   directly, useful to reduce stack usage
30///
31/// # For struct implementation
32///
33/// ## #\[init]
34///
35/// Initializer's purpose is to produce the initial state of the contract.
36///
37/// The following arguments are supported by this method (must be in this order):
38/// * `#[env]` read-only and read-write
39/// * `#[tmp]` read-only and read-write
40/// * `#[slot]` read-only and read-write
41/// * `#[input]`
42/// * `#[output]`
43///
44/// `self` argument is not supported in any way in this context since the state of the contract is
45/// just being created.
46///
47/// ## #\[update]
48///
49/// Generic method contract that can both update contract's own state and contents of slots.
50///
51/// The following arguments are supported by this method (must be in this order):
52/// * `&self` or `&mut self` depending on whether state reads and/or modification are required
53/// * `#[env]` read-only and read-write
54/// * `#[tmp]` read-only and read-write
55/// * `#[slot]` read-only and read-write
56/// * `#[input]`
57/// * `#[output]`
58///
59/// ## #\[view]
60///
61/// Similar to `#[update]`, but can only access read-only view of the state and slots, can be called
62/// outside of block context and can only call other `#[view]` methods.
63///
64/// The following arguments are supported by this method (must be in this order):
65/// * `&self`
66/// * `#[env]` read-only
67/// * `#[slot]` read-only
68/// * `#[input]`
69/// * `#[output]`
70///
71/// # For trait definition and trait implementation
72///
73/// ## #\[update]
74///
75/// Generic method contract that can (in case of trait indirectly) both update contract's own state
76/// and contents of slots.
77///
78/// The following arguments are supported by this method in trait context (must be in this order):
79/// * `#[env]` read-only and read-write
80/// * `#[input]`
81/// * `#[output]`
82///
83/// ## #\[view]
84///
85/// Similar to `#[update]`, but can only access (in case of trait indirectly) read-only view of the
86/// state and slots, can be called outside of block context and can only call other `#[view]`
87/// methods.
88///
89/// The following arguments are supported by this method in trait context (must be in this order):
90/// * `#[env]` read-only
91/// * `#[input]`
92/// * `#[output]`
93///
94/// # Generated code
95///
96/// This macro will produce several key outputs:
97/// * [`Contract`] trait implementation (for struct implementation)
98/// * FFI function for every method, which can be used by the host to call into the guest
99///   environment (for struct and trait implementation)
100/// * `InternalArgs` struct corresponding to each method, used as its sole input for FFI function
101/// * Struct implementing [`ExternalArgs`] trait for each method, usable by other contracts to call
102///   into this contract through the host, host will interpret it based on metadata and generate
103///   `InternalArgs` (for struct and trait implementation, trait definitions)
104/// * Extension trait (for struct and trait implementation) that simplifies interaction with host
105///   and removes the need to construct [`ExternalArgs`] manually, providing nice strongly typed
106///   methods instead, implemented for [`Env`] struct (for struct and trait implementation, trait
107///   definitions)
108/// * Metadata as defined in [`ContractMetadataKind`] stored in `CONTRACT_METADATA` link section
109///   when compiled with `guest` feature enabled (for method, struct and trait implementation)
110///
111/// ## [`Contract`] trait implementation
112///
113/// [`Contract`] trait is required by a few other components in the system, so it is automatically
114/// implemented by the macro, see trait details.
115///
116/// ## FFI function
117///
118/// Macro generates FFI function with C ABI that looks like this:
119/// ```ignore
120/// #[cfg_attr(feature = "guest", unsafe(no_mangle))]
121/// pub unsafe extern "C" fn {prefix}_{method}(
122///     args: NonNull<InternalArgs>,
123/// ) -> ExitCode {
124///     // ...
125/// }
126/// ```
127///
128/// Where `{prefix}` is derived from struct or trait name and `{method}` is the original method name
129/// from struct or trait implementation.
130///
131/// Example with struct implementation:
132/// ```ignore
133/// // This
134/// #[contract]
135/// impl Example {
136///     #[view]
137///     pub fn hello() {}
138/// }
139///
140/// // Will generate this
141/// #[cfg_attr(feature = "guest", unsafe(no_mangle))]
142/// pub unsafe extern "C" fn example_hello(
143///     args: NonNull<InternalArgs>,
144/// ) -> ExitCode {
145///     // ...
146/// }
147/// ```
148///
149/// Example with trait implementation:
150/// ```ignore
151/// // This
152/// #[contract]
153/// impl Fungible for Token {
154///     #[view]
155///     pub fn balance(#[slot] address: &Address) -> Balance {}
156/// }
157///
158/// // Will generate this
159/// #[cfg_attr(feature = "guest", unsafe(no_mangle))]
160/// pub unsafe extern "C" fn fungible_balance(
161///     args: NonNull<InternalArgs>,
162/// ) -> ExitCode {
163///     // ...
164/// }
165/// ```
166///
167/// These generated functions are public and available in generated submodules, but there should
168/// generally be no need to call them directly.
169///
170/// ## `InternalArgs` struct
171///
172/// `InternalArgs` is generated for each method and is used as input to the above FFI functions. Its
173/// fields are generated based on function arguments, processing them in the same order as in
174/// function signature. It is possible for host to build this data structure dynamically using
175/// available contact metadata.
176///
177/// All fields in the data structure are pointers, some are read-only, some can be written to if
178/// changes need to be communicated back to the host.
179///
180/// ### `&self`
181///
182/// `&self` is a read-only state of the contract and generates two fields, both of which are
183/// read-only:
184/// ```ignore
185/// #[repr(C)]
186/// pub struct InternalArgs {
187///     pub state_ptr: NonNull<<StructName as IoType>::PointerType>,
188///     pub state_size: NonNull<u32>,
189///     // ...
190/// }
191/// ```
192///
193/// This allows a contract to read the current state of the contract.
194///
195/// ### `&mut self`
196///
197/// `&mut self` is a read-write state of the contract and generates three fields, `state_ptr` and
198/// `state_size` can be written to, while `state_capacity` is read-only:
199/// ```ignore
200/// #[repr(C)]
201/// pub struct InternalArgs {
202///     pub state_ptr: NonNull<<StructName as IoType>::PointerType>,
203///     pub state_size: *mut u32,
204///     pub state_capacity: NonNull<u32>,
205///     // ...
206/// }
207/// ```
208///
209/// This allows a contract to not only read, but also change the current state of the contract.
210/// `state_capacity` is defined by both the type used and the size of the value used (whichever is
211/// bigger in case of a variable-sized types) and corresponds to the amount of memory that host
212/// allocated for the guest behind `state_ptr`. In the case of a variable-sized types, guest can
213/// replace`state_ptr` with a pointer to a guest-allocated region of memory that host must read
214/// updated value from. This is helpful in case increase of the value size beyond allocated capacity
215/// is needed.
216///
217/// ### `#[env] env: &Env`
218///
219/// `#[env] env: &Env` is for accessing ephemeral environment with method calls restricted to
220/// `#[view]`. Since this is a system-provided data structure with known layout, only read-only
221/// pointer field is generated:
222/// ```ignore
223/// #[repr(C)]
224/// pub struct InternalArgs<'internal_args> {
225///     // ...
226///     pub env_ptr: NonNull<Env<'internal_args>>,
227///     // ...
228/// }
229/// ```
230///
231/// ### `#[env] env: &mut Env`
232///
233/// `#[env] env: &Env` is for accessing ephemeral environment without method calls restrictions.
234/// Since this is a system-provided data structure with known layout, only read-write pointer field
235/// is generated:
236/// ```ignore
237/// #[repr(C)]
238/// pub struct InternalArgs<'internal_args> {
239///     // ...
240///     pub env_ptr: NonNull<Env<'internal_args>>,
241///     // ...
242/// }
243/// ```
244///
245/// ### `#[tmp] tmp: &MaybeData<Tmp>`
246///
247/// `#[tmp] tmp: &MaybeData<Tmp>` is for accessing ephemeral value with auxiliary data and generates
248/// two fields, both of which are read-only:
249/// ```ignore
250/// #[repr(C)]
251/// pub struct InternalArgs {
252///     // ...
253///     pub tmp_ptr: NonNull<
254///         <
255///             <StructName as Contract>::Tmp as IoType
256///         >::PointerType,
257///     >,
258///     pub tmp_size: NonNull<u32>,
259///     // ...
260/// }
261/// ```
262///
263/// This allows a contract to read the current ephemeral value of the contract.
264///
265/// ### `#[tmp] tmp: &mut MaybeData<Tmp>`
266///
267/// `#[tmp] tmp: &MaybeData<Tmp>` is for accessing ephemeral value with auxiliary data and generates
268/// three fields, `tmp_ptr` and `tmp_size` can be written to, while `tmp_capacity` is read-only:
269/// ```ignore
270/// #[repr(C)]
271/// pub struct InternalArgs {
272///     // ...
273///     pub tmp_ptr: NonNull<
274///         <
275///             <StructName as Contract>::Tmp as IoType
276///         >::PointerType,
277///     >,
278///     pub tmp_size: *mut u32,
279///     pub tmp_capacity: NonNull<u32>,
280///     // ...
281/// }
282/// ```
283///
284/// This allows a contract to not only read, but also change the ephemeral value of the contract.
285/// `tmp_capacity` is defined by both the type used and the size of the value used (whichever is
286/// bigger in case of a variable-sized types) and corresponds to the amount of memory that host
287/// allocated for the guest behind `tmp_ptr`. In the case of a variable-sized types, guest can
288/// replace`tmp_ptr` with a pointer to a guest-allocated region of memory that host must read
289/// updated value from. This is helpful in case increase of the value size beyond allocated capacity
290/// is needed.
291///
292/// ### `#[slot] slot: &MaybeData<Slot>` and `#[slot] (address, slot): (&Address, &MaybeData<Slot>)`
293///
294/// `#[slot] slot: &MaybeData<Slot>` and its variant with explicit address argument are for
295/// accessing slot data (that corresponds to optional `address` argument) and generates 3 fields,
296/// all of which are read-only:
297/// ```ignore
298/// #[repr(C)]
299/// pub struct InternalArgs {
300///     // ...
301///     pub slot_address_ptr: NonNull<Address>,
302///     pub slot_ptr: NonNull<
303///         <
304///             <StructName as Contract>::Slot as IoType
305///         >::PointerType,
306///     >,
307///     pub slot_size: NonNull<u32>,
308///     // ...
309/// }
310/// ```
311///
312/// This allows a contract to read slot data.
313///
314/// ### `#[slot] slot: &mut MaybeData<Slot>` and `#[slot] (address, slot): (&Address, &mut MaybeData<Slot>)`
315///
316/// `#[slot] slot: &mut MaybeData<Slot>` and its variant with explicit address argument are for
317/// accessing slot data (that corresponds to optional `address` argument) and generates 4 fields,
318/// `slot_ptr` and `slot_size` can be written to, while `slot_address_ptr` and `slot_capacity` are
319/// read-only:
320/// ```ignore
321/// #[repr(C)]
322/// pub struct InternalArgs {
323///     // ...
324///     pub slot_address_ptr: NonNull<Address>,
325///     pub slot_ptr: NonNull<
326///         <
327///             <StructName as Contract>::Slot as IoType
328///         >::PointerType,
329///     >,
330///     pub slot_size: *mut u32,
331///     pub slot_capacity: NonNull<u32>,
332///     // ...
333/// }
334/// ```
335///
336/// This allows a contract to not only read, but also change slot data.
337/// `slot_capacity` is defined by both the type used and the size of the value used (whichever is
338/// bigger in case of a variable-sized types) and corresponds to the amount of memory that host
339/// allocated for the guest behind `slot_ptr`. In the case of a variable-sized types, guest can
340/// replace`slot_ptr` with a pointer to a guest-allocated region of memory that host must read
341/// updated value from. This is helpful in case increase of the value size beyond allocated capacity
342/// is needed.
343///
344/// Slot changes done by the method call will not be persisted if it returns an error.
345///
346/// ### `#[input] input: &InputValue`
347///
348/// `#[input] input: &InputValue` is a read-only input to the contract call and generates two
349/// fields, both of which are read-only:
350/// ```ignore
351/// #[repr(C)]
352/// pub struct InternalArgs {
353///     // ...
354///     pub input_ptr: NonNull<<InputValue as IoType>::PointerType>,
355///     pub input_size: NonNull<u32>,
356///     // ...
357/// }
358/// ```
359///
360/// ### `#[output] output: &mut MaybeData<OutputValue>` and `-> ReturnValue`/`-> Result<ReturnValue, ContractError>`
361///
362/// `#[output] output: &mut MaybeData<OutputValue>` and regular return value is a read-write output
363/// to the contract call and generates tree fields, `output_ptr` and `output_size` can be written
364/// to, while `output_capacity` is read-only:
365/// ```ignore
366/// #[repr(C)]
367/// pub struct InternalArgs {
368///     // ...
369///     pub output_ptr: NonNull<<OutputValue as IoType>::PointerType>,
370///     pub output_size: *mut u32,
371///     pub output_capacity: NonNull<u32>,
372///     // ...
373/// }
374/// ```
375///
376/// Initially output is empty, but contract can write something useful there and written value will
377/// be propagated back to the caller to observe. `output_ptr` pointer *must not be changed* as the
378/// host will not follow it to the new address, the output size is fully constrained by capacity
379/// specified in `output_capacity`. The only exception is the last `#[output]` of `#[init]` method
380/// (or `ReturnValue` if present), which is the contract's initial state. In this case, its pointer
381/// can be changed to point to a different data structure and not being limited by `result_capacity`
382/// allocation from the host.
383///
384/// NOTE: Even in case the method call fails, the host may modify the contents of the output.
385///
386/// `#[output]` may be used as an alternative to `-> ReturnValue` and
387/// `-> Result<ReturnValue, ContractError>` in case the data structure is large and allocation on
388/// the stack is undesirable, which is especially helpful in case of a variable-sized contract
389/// state.
390///
391/// NOTE: In case `ReturnValue` in `-> ReturnValue` or `-> Result<ReturnValue, ContractError>` is
392/// `()`, it will be skipped in `InternalArgs`.
393///
394///
395/// ## [`ExternalArgs`] implementation
396///
397/// Macro generates a struct that implements [`ExternalArgs`] for each method that other contracts
398/// give to the host when they want to call into another (or even the same) contract.
399///
400/// Here is an example with struct implementation, but it works the same way with trait definition
401/// and implementation too:
402/// ```ignore
403/// // This
404/// #[contract]
405/// impl Example {
406///     #[view]
407///     pub fn hello() {}
408/// }
409///
410/// #[repr(C)]
411/// pub struct ExampleHelloArgs {
412///     // ...
413/// }
414///
415/// #[automatically_derived]
416/// unsafe impl ExternalArgs for ExampleHelloArgs {
417///     // ...
418/// }
419///
420/// impl ExternalArgs {
421///     pub fn new(
422///         // ...
423///     ) -> Self {
424///         // ...
425///     }
426/// }
427/// ```
428///
429/// Struct name if generated by concatenating struct or trait name on which name wsa generated,
430/// method name and `Args` suffix, which is done to make it more convenient to use externally.
431///
432/// `&self`, `&mut self`, `#[env]` and `#[tmp]` arguments of the method are controlled fully by the
433/// host and not present in `ExternalArgs`.
434///
435/// `ExternalArgs::new()` method is generated for convenient construction of the instance, though in
436/// most cases [Extension trait] is used with more convenient API.
437///
438/// [Extension trait]: #extension-trait
439///
440/// ### `#[slot]`
441///
442/// Each `#[slot]` argument in `ExternalArgs` is represented by a single read-only address pointer:
443/// ```ignore
444/// #[repr(C)]
445/// pub struct ExternalArgs {
446///     // ...
447///     pub slot_ptr: NonNull<Address>,
448///     // ...
449/// }
450/// ```
451///
452/// ### `#[input]`
453///
454/// Each `#[input]` argument in `ExternalArgs` is represented by two read-only fields, pointer to
455/// data and its size:
456/// ```ignore
457/// #[repr(C)]
458/// pub struct ExternalArgs {
459///     // ...
460///     pub input_ptr: NonNull<<InputValue as IoType>::PointerType>,
461///     pub input_size: NonNull<u32>,
462///     // ...
463/// }
464/// ```
465///
466/// ### `#[output]` and `-> ReturnValue`/`-> Result<ReturnValue, ContractError>`
467///
468/// Each `#[output]` argument in `ExternalArgs` is represented by three fields, `output_ptr` and
469/// `output_size` can be written to, while `output_capacity` is read-only:
470/// ```ignore
471/// #[repr(C)]
472/// pub struct ExternalArgs {
473///     // ...
474///     pub output_ptr: NonNull<<OutputValue as IoType>::PointerType>,
475///     pub output_size: *mut u32,
476///     pub output_capacity: NonNull<u32>,
477///     // ...
478/// }
479/// ```
480///
481/// The arguments are skipped in `ExternalArgs` for the last `#[output]` or `ReturnValue` when
482/// method is `#[init]` or when `ReturnValue` is `()` in other cases. For `#[init]` method's return
483/// value is contract's initial state and is processed by execution environment itself. When
484/// `ReturnValue` is `()` then there is no point in having a pointer for it.
485///
486/// ## Extension trait
487///
488/// Extension trait is just a convenient wrapper, whose safe methods take strongly typed arguments,
489/// construct `ExternalArgs` while respecting Rust safety invariants and calls [`Env::call()`] with
490/// it. Extension trait usage is not mandatory, but it does make method calls much more convenient
491/// in most simple cases.
492///
493/// Generated methods reflect `ExternalArgs` fields with just context (except when calling `#[view]`
494/// method where context is not applicable) and the address of the contract being called added at
495/// the beginning:
496/// ```ignore
497/// // This
498/// impl Token {
499///     // ...
500///
501///     #[view]
502///     pub fn balance(#[slot] target: &MaybeData<Slot>) -> Balance {
503///         // ...
504///     }
505///
506///     #[update]
507///     pub fn transfer(
508///         #[env] env: &mut Env<'_>,
509///         #[slot] (from_address, from): (&Address, &mut MaybeData<Slot>),
510///         #[slot] to: &mut MaybeData<Slot>,
511///         #[input] &amount: &Balance,
512///     ) -> Result<(), ContractError> {
513///         // ...
514///     }
515/// }
516///
517/// // Will generate this
518/// pub trait TokenExt {
519///     fn balance(
520///         &self,
521///         contract: &Address,
522///         target: &Address,
523///     ) -> Result<Balance, ContractError>;
524///
525///     fn transfer(
526///         self: &&mut Self,
527///         method_context: &MethodContext,
528///         contract: &Address,
529///         from: &Address,
530///         to: &Address,
531///         amount: &Balance,
532///     ) -> Result<(), ContractError>;
533/// }
534///
535/// impl TokenExt for Env {
536///     fn balance(
537///         &self,
538///         contract: &Address,
539///         target: &Address,
540///     ) -> Result<Balance, ContractError> {
541///         // ...
542///     }
543///
544///     fn transfer(
545///         self: &&mut Self,
546///         method_context: &MethodContext,
547///         contract: &Address,
548///         from: &Address,
549///         to: &Address,
550///         amount: &Balance,
551///     ) -> Result<(), ContractError> {
552///         // ...
553///     }
554/// }
555/// ```
556///
557/// The name of the extension trait is created as struct or trait name followed by `Ext` suffix.
558///
559/// ## Metadata
560///
561/// There are several places where metadata is being generated, see [`ContractMetadataKind`] for
562/// details.
563///
564/// First, `#[contract]` macro generates a public `METADATA` constant for each method individually.
565///
566/// Second, for each trait that contract can implement `#[contract]` macro generates an associated
567/// constant `METADATA` that essentially aggregates metadata of all annotated methods.
568///
569/// Third, [`Contract`] trait implementation generated by `#[contract]` macro contains
570/// `MAIN_CONTRACT_METADATA` associated constant, which is similar in nature to `METADATA` constant
571/// for traits described above.
572///
573/// Lastly, for the whole contract as a project, both trait and contract metadata is concatenated
574/// and stored in `CONTRACT_METADATA` link section that can later be inspected externally to
575/// understand everything about contract's interfaces, auto-generate UI, etc.
576///
577/// [`Contract`]: ab_contracts_common::Contract
578/// [`TrivialType`]: ab_contracts_io_type::trivial_type::TrivialType
579/// [`IoType`]: ab_contracts_io_type::IoType
580/// [`ExternalArgs`]: ab_contracts_common::method::ExternalArgs
581/// [`Env`]: ab_contracts_common::env::Env
582/// [`Env::call()`]: ab_contracts_common::env::Env::call()
583/// [`ContractMetadataKind`]: ab_contracts_common::metadata::ContractMetadataKind
584pub use ab_contracts_macros_impl::contract;