xrpl_wasm_stdlib/host/mod.rs
1//! Host bindings and utilities exposed to WASM smart contracts.
2//!
3//! This module exposes the low-level host ABI plus typed primitives (Result, Error, helpers).
4//! Most users should prefer the safe, high-level APIs in [`crate::core`], which wrap these bindings.
5//!
6//! ## Float Operations for Fungible Tokens (IOUs)
7//!
8//! The host provides float arithmetic functions for XRPL's fungible token amounts.
9//! These operations use rippled's Number class via FFI to ensure exact consensus compatibility:
10//!
11//! - `float_from_int` / `float_from_uint` - Convert integers to float format
12//! - `float_set` - Create float from exponent and mantissa
13//! - `float_add` / `float_subtract` / `float_multiply` / `float_divide` - Arithmetic
14//! - `float_pow` / `float_root` / `float_log` - Mathematical functions
15//! - `float_compare` - Comparison operations
16//!
17//! All operations support explicit rounding modes (0=ToNearest, 1=TowardsZero, 2=Downward, 3=Upward).
18//!
19//! See the host_bindings documentation for detailed function signatures.
20
21pub mod assert;
22pub mod error_codes;
23pub mod trace;
24
25//////////////////////////////////////
26// Host functions (defined by the host)
27//////////////////////////////////////
28
29#[cfg(not(target_arch = "wasm32"))]
30include!("host_bindings_for_testing.rs");
31
32// host functions defined by the host.
33#[cfg(target_arch = "wasm32")]
34include!("host_bindings.rs");
35
36/// `Result` is a type that represents either a success ([`Ok`]) or failure ([`Err`]) result from the host.
37#[must_use]
38pub enum Result<T> {
39 /// Contains the success value
40 Ok(T),
41 /// Contains the error value
42 Err(Error), // TODO: Test if the WASM size is expanded if we use an enum here instead of i32
43}
44
45impl<T> Result<T> {
46 /// Returns `true` if the result is [`Ok`].
47 #[inline]
48 pub fn is_ok(&self) -> bool {
49 matches!(*self, Result::Ok(_))
50 }
51
52 /// Returns `true` if the result is [`Err`].
53 #[inline]
54 pub fn is_err(&self) -> bool {
55 !self.is_ok()
56 }
57
58 /// Converts from `Result<T>` to `Option<T>`.
59 ///
60 /// Converts `self` into an `Option<T>`, consuming `self`,
61 /// and discarding the error, if any.
62 #[inline]
63 pub fn ok(self) -> Option<T> {
64 match self {
65 Result::Ok(x) => Some(x),
66 Result::Err(_) => None,
67 }
68 }
69
70 /// Converts from `Result<T>` to `Option<Error>`.
71 ///
72 /// Converts `self` into an `Option<Error>`, consuming `self`,
73 /// and discarding the success value, if any.
74 #[inline]
75 pub fn err(self) -> Option<Error> {
76 match self {
77 Result::Ok(_) => None,
78 Result::Err(x) => Some(x),
79 }
80 }
81
82 /// Returns the contained [`Ok`] value, consuming the `self` value.
83 ///
84 /// # Panics
85 ///
86 /// Panics if the value is an [`Err`], with a panic message provided by the
87 /// [`Err`]'s value.
88 #[inline]
89 pub fn unwrap(self) -> T {
90 match self {
91 Result::Ok(t) => t,
92 Result::Err(error) => {
93 let _ = trace::trace_num("error_code=", error.code() as i64);
94 panic!(
95 "called `Result::unwrap()` on an `Err` with code: {}",
96 error.code()
97 )
98 }
99 }
100 }
101
102 /// Returns the contained [`Ok`] value or a provided default.
103 #[inline]
104 pub fn unwrap_or(self, default: T) -> T {
105 match self {
106 Result::Ok(t) => t,
107 Result::Err(_) => default,
108 }
109 }
110
111 /// Returns the contained [`Ok`] value or computes it from a closure.
112 #[inline]
113 pub fn unwrap_or_else<F: FnOnce(Error) -> T>(self, op: F) -> T {
114 match self {
115 Result::Ok(t) => t,
116 Result::Err(e) => op(e),
117 }
118 }
119
120 #[inline]
121 pub fn unwrap_or_panic(self) -> T {
122 self.unwrap_or_else(|error| {
123 let _ = trace::trace_num("error_code=", error.code() as i64);
124 core::panic!(
125 "Failed in {}: error_code={}",
126 core::panic::Location::caller(),
127 error.code()
128 );
129 })
130 }
131}
132
133impl From<i64> for Result<u64> {
134 #[inline(always)] // <-- Inline because this function is very small
135 fn from(value: i64) -> Self {
136 match value {
137 res if res >= 0 => Result::Ok(value as _),
138 _ => Result::Err(Error::from_code(value as _)),
139 }
140 }
141}
142
143/// Possible errors returned by XRPL Programmability APIs.
144///
145/// Errors are global across all Programmability APIs.
146#[derive(Clone, Copy, Debug)]
147#[repr(i32)]
148pub enum Error {
149 /// Reserved for internal invariant trips, generally unrelated to inputs.
150 /// These should be reported with an issue.
151 InternalError = error_codes::INTERNAL_ERROR,
152
153 /// The requested serialized field could not be found in the specified object.
154 /// This error is returned when attempting to access a field that doesn't exist
155 /// in the current transaction or ledger object.
156 FieldNotFound = error_codes::FIELD_NOT_FOUND,
157
158 /// The provided buffer is too small to hold the requested data.
159 /// Increase the buffer size and retry the operation.
160 BufferTooSmall = error_codes::BUFFER_TOO_SMALL,
161
162 /// The API was asked to assume the object under analysis is an STArray but it was not.
163 /// This error occurs when trying to perform array operations on non-array objects.
164 NoArray = error_codes::NO_ARRAY,
165
166 /// The specified field is not a leaf field and cannot be accessed directly.
167 /// Leaf fields are primitive types that contain actual data values.
168 NotLeafField = error_codes::NOT_LEAF_FIELD,
169
170 /// The provided locator string is malformed or invalid.
171 /// Locators must follow the proper format for field identification.
172 LocatorMalformed = error_codes::LOCATOR_MALFORMED,
173
174 /// The specified slot number is outside the valid range.
175 /// Slot numbers must be within the allowed bounds for the current context.
176 SlotOutRange = error_codes::SLOT_OUT_RANGE,
177
178 /// No free slots are available for allocation.
179 /// All available slots are currently in use. Consider reusing existing slots.
180 SlotsFull = error_codes::SLOTS_FULL,
181
182 /// The specified slot did not contain any slotted data (i.e., is empty).
183 /// This error occurs when trying to access a slot that hasn't been allocated
184 /// or has been freed.
185 EmptySlot = error_codes::EMPTY_SLOT,
186
187 /// The requested ledger object could not be found.
188 /// This may occur if the object doesn't exist or the keylet is invalid.
189 LedgerObjNotFound = error_codes::LEDGER_OBJ_NOT_FOUND,
190
191 /// An error occurred while decoding serialized data.
192 /// This typically indicates corrupted or invalidly formatted data.
193 InvalidDecoding = error_codes::INVALID_DECODING,
194
195 /// The data field is too large to be processed.
196 /// Consider reducing the size of the data or splitting it into smaller chunks.
197 DataFieldTooLarge = error_codes::DATA_FIELD_TOO_LARGE,
198
199 /// A pointer or buffer length provided as a parameter described memory outside the allowed memory region.
200 /// This error indicates a memory access violation.
201 PointerOutOfBounds = error_codes::POINTER_OUT_OF_BOUNDS,
202
203 /// No memory has been exported by the WebAssembly module.
204 /// The module must export its memory for host functions to access it.
205 NoMemoryExported = error_codes::NO_MEM_EXPORTED,
206
207 /// One or more of the parameters provided to the API are invalid.
208 /// Check the API documentation for valid parameter ranges and formats.
209 InvalidParams = error_codes::INVALID_PARAMS,
210
211 /// The provided account identifier is invalid.
212 /// Account IDs must be valid 20-byte addresses in the proper format.
213 InvalidAccount = error_codes::INVALID_ACCOUNT,
214
215 /// The specified field identifier is invalid or not recognized.
216 /// Field IDs must correspond to valid XRPL serialization fields.
217 InvalidField = error_codes::INVALID_FIELD,
218
219 /// The specified index is outside the valid bounds of the array or collection.
220 /// Ensure the index is within the valid range for the target object.
221 IndexOutOfBounds = error_codes::INDEX_OUT_OF_BOUNDS,
222
223 /// The input provided for floating-point parsing is malformed.
224 /// Floating-point values must be in the correct format for XFL operations.
225 InvalidFloatInput = error_codes::INVALID_FLOAT_INPUT,
226
227 /// An error occurred during floating-point computation.
228 /// This may indicate overflow, underflow, or other arithmetic errors.
229 InvalidFloatComputation = error_codes::INVALID_FLOAT_COMPUTATION,
230}
231
232impl Error {
233 // TODO: Use Trait instead?
234 #[inline(always)] // <-- Inline because this function is very small
235 pub fn from_code(code: i32) -> Self {
236 unsafe { core::mem::transmute(code) }
237 }
238
239 /// Error code
240 #[inline(always)] // <-- Inline because this function is very small
241 pub fn code(self) -> i32 {
242 self as _
243 }
244}
245
246impl From<Error> for i64 {
247 fn from(val: Error) -> Self {
248 val as i64
249 }
250}