1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Copyright 2022. The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//! This crate provides ergonomic abstractions that allow WASM templates to interact with the Tari Ootle engine.
//! Almost all Ootle templates written in Rust should depend on this crate.
//!
//! Include the template `prelude` which provides all the necessary imports for writing templates. This includes common
//! types (e.g. `Component`, `Resource`, `Vault`, `AccessRule` etc.) and macros (e.g. the `template` macro).
//! ```
//! use tari_template_lib::prelude::*;
//! ```
//!
//! ## Getting started
//!
//! Include this crate in your `Cargo.toml`:
//! ```toml
//! [dependencies]
//! tari_template_lib = { version = "*" } # Or specify a specific version
//! ```
//!
//! Apply the `template` macro and define your template struct and its methods.
//! This macro generates the necessary ABI functions and boilerplate to make your template work with the Ootle engine.
//!
//! ```rust
//! use tari_template_lib::prelude::*;
//!
//! // The `template` macro generates and implements the necessary ABI functions, `TemplateDefinition` and other boilerplate that
//! // hooks up the functions and methods you define to the Ootle execution engine.
//! // The module name is not important (it is ignored). The `template` macro must be applied to the module that contains your template struct/enum.
//! #[template]
//! mod my_template {
//! // Bring prelude and anything else into scope.
//! use super::*;
//!
//! /// Defines the component state that is stored on-chain. This can be a struct or an enum.
//! /// The struct/enum name can be selected arbitrarily, and is exposed in the TemplateDefinition for the template.
//! pub struct MyCounter {
//! counter: u64,
//! /// Vaults contain resources. A vault is a separate substate created within a component, and belongs to that component.
//! vault: Vault,
//! }
//!
//! impl MyCounter {
//! /// A simple constructor.
//! /// NOTE: this is a convenience constructor that implicitly creates a component with some defaults. These defaults are restrictive for many use cases
//! /// for e.g. all component methods are only callable by the component owner (i.e. the same signer that created the component must sign the transaction
//! /// to call any method).
//! /// To see how to customise this, see the `custom` constructor below.
//! pub fn new() -> Self {
//! Self {
//! counter: 0,
//! // A empty vault that can only hold the native token (XTR). You can also create vaults that hold your own resources (see the `ResourceBuilder`).
//! vault: Vault::new_empty(XTR),
//! }
//! }
//!
//! /// This constructor provides more control over the component configuration.
//! ///
//! /// ## Arguments
//! /// - `address`: An component address allocation. This allows a single transaction to both create and call onto the created component without knowing the component address in advance.
//! /// - `access_rules`: Custom method access rules for the component. All methods referenced in the access rules must be defined on the component or the transaction will fail.
//! /// - `owner_rule`: Custom owner rule for the component. The owner of a component is able to change access rules and call all methods. Setting `OwnerRule::None` means the component has no owner and all access rules are immutable.
//! pub fn custom(address: ComponentAddressAllocation, access_rules: ComponentAccessRules, owner_rule: OwnerRule) -> Component<Self> {
//! // Call `new` which initialises the component state. NOTE that this is a completely normal function call. The component
//! // is not yet created on-chain.
//! let component = Self::new();
//!
//! Component::new(component)
//! .with_address_allocation(address)
//! .with_access_rules(access_rules)
//! .with_owner_rule(owner_rule)
//! // Create the component on-chain
//! .create()
//! }
//!
//! /// Increment the counter by 1. The `CallMethod` instruction is used to invoke this method.
//! /// This method is callable as per the access rules defined for the component.
//! pub fn increment(&mut self) {
//! self.counter += 1;
//! }
//!
//! /// A simple associated function that returns a string. The `CallFunction` instruction is used to invoke this function.
//! /// Apart from defining constructors, associated functions can provide any shared functionality callable by anyone.
//! pub fn some_function(name: String, number: u64) -> String {
//! format!("Hello {name}, the number is {number}")
//! }
//! }
//! ```
//!
//! ## Template Examples
//!
//! - <https://github.com/tari-project/wasm-examples>
//! - <https://github.com/tari-project/tari-ootle/tree/development/crates/engine/tests/templates>
//!
//! ## Re-exports
//!
//! This crate re-exports common types (`tari_template_lib_types`), low-level ABI functions in `tari_template_abi` and
//! the `tari_template_macros` proc macro.
//!
//! ## no_std
//!
//! This crate supports `no_std` environments. To use in `no_std`, disable the `std` feature (`default-features =
//! false`) and enable the `alloc` feature.
//!
//! ```toml
//! [dependencies]
//! tari_template_lib = { version = "*", default-features = false, features = ["alloc"] }
//! ```
//!
//! You will need to provide a global allocator (e.g. `talc`, `lol_alloc`). This crate provides a panic handler for
//! `no_std`.
// Support no_std environments
// This can be uncommented if you need to check for mistaken use of the std crate
// TODO: to always use this, we'd need to include the rust prelude where ever ts_rs is used.
// #![no_std]
// #[cfg(feature = "std")]
// extern crate std;
compile_error!;
compile_error!;
pub use Consensus;
pub use tari_template_lib_types as types;
// ---------------------------------------- WASM target exports ------------------------------------------------
pub use engine;
pub use template;
// Re-export for macro
pub use to_value;