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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
//! Procedural macros for the `Sails` framework.
use TokenStream;
use proc_macro_error;
/// Generates code for turning a Rust impl block into a Sails service
/// based on a set of public methods of the block. See
/// [documentation](https://github.com/gear-tech/sails?tab=readme-ov-file#application)
/// for details.
///
/// The macro can be customized with the following arguments:
/// - `crate` - specifies path to the `sails-rs` crate allowing the latter
/// to be imported with a different name, for example, when the
/// `sails-rs` create is re-exported from another crate.
/// - `events` - specifies a Rust enum type denoting events that the service can emit.
/// See [documentation](https://github.com/gear-tech/sails?tab=readme-ov-file#events)
/// for details.
/// - `extends` - specifies a list of other services the service extends using the mixin pattern.
/// See [documentation](https://github.com/gear-tech/sails?tab=readme-ov-file#service-extending-mixins)
/// for details.
///
/// # Examples
///
/// ```rust
/// mod my_service {
/// use sails_rs::{export, service, prelude::*};
///
/// #[event]
/// #[derive(parity_scale_codec::Encode, type_info::TypeInfo, ReflectHash)]
/// #[reflect_hash(crate = sails_rs)]
/// pub enum MyServiceEvents {
/// SomethingDone,
/// }
///
/// pub struct MyService;
///
/// #[service(events = MyServiceEvents)]
/// impl MyService {
/// #[export]
/// pub fn do_something(&mut self) -> u32 {
/// self.emit_event(MyServiceEvents::SomethingDone).unwrap();
/// 0
/// }
///
/// #[export]
/// pub fn get_something(&self) -> u32 {
/// 0
/// }
/// }
/// }
/// ```
/// Generates code for turning a Rust impl block into a Sails program
/// based on a set of public methods of the block. See
/// [documentation](https://github.com/gear-tech/sails?tab=readme-ov-file#application)
/// for details.
///
/// The macro can be customized with the following arguments:
/// - `crate` - specifies path to the `sails-rs` crate allowing the latter
/// to be imported with a different name, for example, when the
/// `sails-rs` create is re-exported from another crate.
/// - `handle_signal` - specifies a path to a function that will be called
/// after standard signal handling provided by the `gstd` crate.
/// - `payable` - specifies that the program can accept transfers of value.
///
/// The macro also accepts a `handle_reply` attribute that can be used to specify a function
/// that will handle replies. This function should be defined within the program and accepts `&self`.
/// The function will be called automatically when a reply is received.
///
/// # Examples
///
/// ```rust
/// mod my_program {
/// use sails_rs::program;
///
/// pub struct MyProgram;
///
/// #[program(payable)]
/// impl MyProgram {
/// pub fn default() -> Self {
/// Self
/// }
///
/// pub fn from_seed(_seed: u32) -> Self {
/// Self
/// }
///
/// #[handle_reply]
/// fn inspect_reply(&self) {
/// // Handle reply here
/// }
/// }
/// }
/// ```
/// Customizes how a service/program method is exposed based on specified arguments.
///
/// The attribute accepts two optional arguments:
/// - `route` - Defines a custom route for the method.
/// By default, every exposed service method is accessible via a route derived from its name,
/// converted to PascalCase. This argument allows you to override the default route with a
/// string of your choice.
/// - `unwrap_result` - Indicates that the method's `Result<T, E>` return value should be unwrapped.
/// If specified, the method will panic if the result is an `Err`.
///
/// # Examples
///
/// The following example demonstrates the use of the `export` attribute applied to the `do_something` method.
/// - The `route` argument customizes the route to "Something" (convertered to PascalCase).
/// - The `unwrap_result` argument ensures that the method's result is unwrapped, causing it to panic
/// with the message "Something went wrong" if the result is an `Err`.
///
/// ```rust
/// mod my_service {
/// use sails_rs::{export, service};
///
/// struct MyService;
///
/// #[service]
/// impl MyService {
/// #[export(route = "something", unwrap_result)]
/// pub fn do_something(&mut self) -> Result<u32, String> {
/// Err("Something went wrong".to_string())
/// }
/// }
/// }
/// ```
/// Defines event for using within Gear and Ethereum ecosystem.
///
/// Trait `SailsEvent` provides a uniform interface to encode an event into a tuple
/// of variant name and data payload.
///
/// Trait `EthEvent` provides a uniform interface to convert an event into the topics and data payload
/// that are used to emit logs in the Ethereum Virtual Machine (EVM). The logs generated by the EVM
/// consist of:
///
/// - **Topics:** An array of 32-byte values. The first topic is always the keccak256 hash of the event
/// signature, while the remaining topics correspond to indexed fields. For dynamic types (as determined
/// by `<T as alloy_sol_types::SolType>::IS_DYNAMIC`), the ABI-encoded value is hashed before being stored.
/// For static types, the ABI-encoded value is left-padded with zeros to 32 bytes.
/// - **Data:** A byte array containing the ABI-encoded non-indexed fields of the event, encoded as a tuple.
///
/// This is intended to be used with the `#[sails_rs::event]` procedural macro, which automatically
/// implements the trait for your enum-based event definitions.
///
///
/// # Arguments
///
/// - `scale` — implement only `SailsEvent` (SCALE/Gear transport). The Rust client generator
/// and JS client generator will include this event; the Solidity generator will exclude it.
/// - `ethabi` — implement only `EthEvent` (Ethereum ABI transport, requires `ethexe` feature).
/// The Solidity generator will include this event; the Rust and JS client generators will exclude it.
/// - `scale, ethabi` — implement both traits explicitly (same as the default when both flags are omitted).
/// - `crate = <path>` — override the path to the `sails-rs` crate (defaults to `sails_rs`).
///
/// When only one transport flag is given, every variant in the IDL receives a `@codec: scale` or
/// `@codec: ethabi` annotation so downstream generators can filter accordingly.
///
/// ## Ethabi-only events and `#[sails_type]`
///
/// `#[sails_type]` always derives `Encode`, `Decode`, `TypeInfo`, and `ReflectHash`. If your
/// ethabi-only event enum contains fields that are ABI-compatible but not SCALE-compatible (e.g.
/// `alloy_primitives::Address`), do **not** combine it with `#[sails_type]`. Instead, derive
/// `TypeInfo` and `ReflectHash` manually:
///
/// ```rust,ignore
/// #[sails_rs::event(ethabi)]
/// #[derive(sails_rs::type_info::TypeInfo, sails_rs::ReflectHash)]
/// #[type_info(crate = sails_rs::type_info)]
/// #[reflect_hash(crate = sails_rs)]
/// pub enum Events {
/// Something(sails_rs::alloy_primitives::Address),
/// }
/// ```
///
/// # Examples
///
/// Given an event definition:
///
/// ```rust,ignore
/// #[sails_rs::event]
/// #[derive(sails_rs::Encode, sails_rs::TypeInfo)]
/// #[codec(crate = sails_rs::scale_codec)]
/// #[type_info(crate = sails_rs::type_info)]
/// pub enum Events {
/// MyEvent {
/// #[indexed]
/// sender: uint128,
/// amount: uint128,
/// note: String,
/// },
/// }
/// ```
///
/// Calling the methods:
///
/// ```rust,ignore
/// let event = Events::MyEvent {
/// sender: 123,
/// amount: 1000,
/// note: "Hello, Ethereum".to_owned(),
/// };
///
/// let topics = event.topics();
/// let data = event.data();
/// ```
///
/// The first topic will be the hash of the event signature (e.g. `"MyEvent(uint128,uint128,String)"`),
/// and additional topics and the data payload will be computed based on the field attributes.
///
/// # Methods
///
/// - `topics()`: Returns a vector of 32-byte topics (`alloy_primitives::B256`) for the event.
/// - `data()`: Returns the ABI-encoded data payload (a `Vec<u8>`) for the non-indexed fields.
/// Derives the canonical Sails type bundle: `Encode`, `Decode`, `TypeInfo`,
/// and `ReflectHash`, together with their `crate =` helper attributes routed
/// to the `sails_rs` re-exports.
///
/// # Arguments
///
/// - `crate = <path>` — override the path to the `sails-rs` crate (defaults to
/// `sails_rs`). Useful when `sails-rs` is re-exported from a parent crate.
/// - `no_reflect_hash` — omit `ReflectHash` from the derive list and drop the
/// `reflect_hash` helper attribute. Exists specifically for the IDL v1
/// client generator, which predates `ReflectHash`.
///
/// # Examples
///
/// ```rust,ignore
/// use sails_rs::sails_type;
///
/// #[sails_type]
/// #[derive(PartialEq, Clone, Debug)]
/// pub struct MyType {
/// pub a: u32,
/// pub b: String,
/// }
///
/// #[sails_type(crate = my_alias)]
/// pub enum MyEnum { A, B }
///
/// #[sails_type(no_reflect_hash)]
/// pub struct LegacyType { pub a: u32 }
/// ```
///
/// Composes with `#[event]` in any order — the two macros are orthogonal.