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;