ab_contracts_macros/
lib.rs

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