Skip to main content

xrpl_common_stdlib/
ledger_entry_ids.rs

1use crate::host;
2use crate::host::Result;
3use crate::host::error_codes::match_result_code_with_expected_bytes;
4use crate::types::account_id::AccountID;
5use crate::types::currency::Currency;
6use crate::types::issue::Issue;
7use crate::types::mpt_id::MptId;
8
9pub const XRPL_LEDGER_ENTRY_ID_SIZE: usize = 32;
10// Type aliases for specific ledger entry IDs, all currently using the same underlying array type.
11pub type LedgerEntryIdBytes = [u8; XRPL_LEDGER_ENTRY_ID_SIZE];
12
13/// Generates an account ledger entry ID for a given XRP Ledger account.
14///
15/// Account ledger entry IDs are used to reference account entries in the XRP Ledger's state data.
16/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
17///
18/// # Arguments
19///
20/// * `account_id` - Reference to an `AccountID` representing the XRP Ledger account
21///
22/// # Returns
23///
24/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte account ledger entry ID.
25///   On failure, returns an `Error` with the corresponding error code.
26///
27/// # Safety
28///
29/// This function makes unsafe FFI calls to the host environment through
30/// the `host::accountroot_id` function, though the unsafe code is contained
31/// within the closure passed to `create_id_from_host_call`.
32///
33/// # Example
34///
35/// ```rust
36///
37/// use xrpl_common_stdlib::types::account_id::AccountID;
38/// use xrpl_common_stdlib::ledger_entry_ids::accountroot_id;
39/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
40/// fn main() -> Result<(), Box<dyn std::error::Error>> {
41///   let account:AccountID = AccountID::from(
42///     *b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3"
43///   );
44///   match accountroot_id(&account){
45///     xrpl_common_stdlib::host::Result::Ok(id) => {
46///       trace_hex("Generated ledger entry ID", &id);
47///     }
48///     xrpl_common_stdlib::host::Result::Err(e) => {
49///       trace_num("Error assembling ledger entry ID", e.code() as i64);
50///     }
51///   }
52///   Ok(())
53/// }
54/// ```
55pub fn accountroot_id(account_id: &AccountID) -> Result<LedgerEntryIdBytes> {
56    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
57        host::accountroot_id(
58            account_id.0.as_ptr(), // Assuming AccountID is a tuple struct like AccountID(bytes)
59            account_id.0.len(),
60            id_buffer_ptr,
61            id_buffer_len,
62        )
63    })
64}
65
66/// Generates an AMM ledger entry ID for a given pair of accounts and currency code.
67///
68/// An AMM ledger entry ID is used to reference AMM entries in the XRP Ledger.
69///
70/// # Arguments
71///
72/// * `issue1` - The first Issue in the AMM relationship
73/// * `issue2` - The second Issue in the AMM relationship
74///
75/// # Returns
76///
77/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte AMM ledger entry ID.
78///   On failure, returns an `Error` with the corresponding error code.
79///
80/// # Safety
81///
82/// This function makes unsafe FFI calls to the host environment through
83/// the `host::amm_id` function.
84///
85/// # Example
86///
87/// ```rust
88/// use xrpl_common_stdlib::types::account_id::AccountID;
89/// use xrpl_common_stdlib::types::issue::{Issue, XrpIssue, IouIssue};
90/// use xrpl_common_stdlib::types::currency::Currency;
91/// use xrpl_common_stdlib::ledger_entry_ids::amm_id;
92/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
93/// fn main() -> Result<(), Box<dyn std::error::Error>> {
94///  let issue1: Issue = Issue::XRP(XrpIssue {});
95///  let issuer: AccountID =
96///    AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
97///  let currency = b"RLUSD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; // RLUSD currency code
98///  let currency: Currency = Currency::from(*currency);
99///  let issue2 = Issue::IOU(IouIssue::new(issuer, currency));
100///  match amm_id(&issue1, &issue2) {
101///    xrpl_common_stdlib::host::Result::Ok(id) => {
102///      trace_hex("Generated ledger entry ID", &id);
103///    }
104///    xrpl_common_stdlib::host::Result::Err(e) => {
105///      trace_num("Error assembling ledger entry ID", e.code() as i64);
106///    }
107///  }
108///  Ok(())
109/// }
110/// ```
111pub fn amm_id(issue1: &Issue, issue2: &Issue) -> Result<LedgerEntryIdBytes> {
112    let issue1_bytes = issue1.as_bytes();
113    let issue2_bytes = issue2.as_bytes();
114    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
115        host::amm_id(
116            issue1_bytes.as_ptr(),
117            issue1_bytes.len(),
118            issue2_bytes.as_ptr(),
119            issue2_bytes.len(),
120            id_buffer_ptr,
121            id_buffer_len,
122        )
123    })
124}
125
126/// Generates an check ledger entry ID for a given owner and sequence in the XRP Ledger.
127///
128/// Check ledger entry IDs are used to reference check entries in the XRP Ledger's state data.
129/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
130///
131/// # Arguments
132///
133/// * `owner` - Reference to an `AccountID` representing the check owner's account
134/// * `seq` - The account sequence associated with the check entry
135///
136/// # Returns
137///
138/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte check ledger entry ID.
139///   On failure, returns an `Error` with the corresponding error code.
140///
141/// # Safety
142///
143/// This function makes unsafe FFI calls to the host environment through
144/// the `host::check_id` function, though the unsafe code is contained
145/// within the closure passed to `create_id_from_host_call`.
146///
147/// # Example
148///
149/// ```rust
150/// use xrpl_common_stdlib::types::account_id::AccountID;
151/// use xrpl_common_stdlib::ledger_entry_ids::check_id;
152/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
153///
154/// fn main() -> Result<(), Box<dyn std::error::Error>> {
155///   let owner: AccountID =
156///       AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
157///   let sequence = 12345;
158///   match check_id(&owner, sequence) {
159///     xrpl_common_stdlib::host::Result::Ok(id) => {
160///       trace_hex("Generated ledger entry ID", &id);
161///     }
162///     xrpl_common_stdlib::host::Result::Err(e) => {
163///       trace_num("Error assembling ledger entry ID", e.code() as i64);
164///     }
165///   }
166///   Ok(())
167///}
168/// ```
169pub fn check_id(owner: &AccountID, seq: u32) -> Result<LedgerEntryIdBytes> {
170    let seq_bytes = seq.to_le_bytes();
171    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
172        host::check_id(
173            owner.0.as_ptr(),
174            owner.0.len(),
175            seq_bytes.as_ptr(),
176            seq_bytes.len(),
177            id_buffer_ptr,
178            id_buffer_len,
179        )
180    })
181}
182
183/// Generates a credential ledger entry ID for a given subject, issuer, and credential type.
184///
185/// A credential ledger entry ID is used to reference credential entries in the XRP Ledger.
186///
187/// # Arguments
188///
189/// * `subject` - The AccountID of the subject for whom the credential is issued
190/// * `issuer` - The AccountID of the entity issuing the credential
191/// * `credential_type` - A byte slice representing the type of credential
192///
193/// # Returns
194///
195/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte credential ledger entry ID.
196///   On failure, returns an `Error` with the corresponding error code.
197///
198/// # Safety
199///
200/// This function makes unsafe FFI calls to the host environment through
201/// the `host::credential_id` function.
202///
203/// # Example
204///
205/// ```rust
206/// use xrpl_common_stdlib::types::account_id::AccountID;
207/// use xrpl_common_stdlib::ledger_entry_ids::credential_id;
208/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
209/// fn main() -> Result<(), Box<dyn std::error::Error>> {
210///     let subject: AccountID =
211///         AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
212///     let issuer: AccountID =
213///         AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
214///     let cred_type: &[u8] = b"termsandconditions";
215///     match credential_id(&subject, &issuer, cred_type) {
216///       xrpl_common_stdlib::host::Result::Ok(id) => {
217///         trace_hex("Generated ledger entry ID", &id);
218///       }
219///       xrpl_common_stdlib::host::Result::Err(e) => {
220///         trace_num("Error assembling ledger entry ID", e.code() as i64);
221///       }
222///     }
223///     Ok(())
224/// }
225/// ```
226pub fn credential_id(
227    subject: &AccountID,
228    issuer: &AccountID,
229    credential_type: &[u8],
230) -> Result<LedgerEntryIdBytes> {
231    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
232        host::credential_id(
233            subject.0.as_ptr(),
234            subject.0.len(),
235            issuer.0.as_ptr(),
236            issuer.0.len(),
237            credential_type.as_ptr(),
238            credential_type.len(),
239            id_buffer_ptr,
240            id_buffer_len,
241        )
242    })
243}
244
245/// Generates a delegate ledger entry ID for a given given account and authorized account.
246///
247/// A delegate ledger entry ID is used to reference delegate entries in the XRP Ledger.
248///
249/// # Arguments
250///
251/// * `account` - The AccountID of the account that is delegating permissions
252/// * `authorize` - The AccountID of the account that is delegated to
253///
254/// # Returns
255///
256/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte delegate ledger entry ID.
257///   On failure, returns an `Error` with the corresponding error code.
258///
259/// # Safety
260///
261/// This function makes unsafe FFI calls to the host environment through
262/// the `host::delegate_id` function.
263///
264/// # Example
265///
266/// ```rust
267/// use xrpl_common_stdlib::types::account_id::AccountID;
268/// use xrpl_common_stdlib::ledger_entry_ids::delegate_id;
269/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
270/// fn main() -> Result<(), Box<dyn std::error::Error>> {
271///     let account: AccountID =
272///         AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
273///     let authorize: AccountID =
274///         AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
275///     match delegate_id(&account, &authorize) {
276///       xrpl_common_stdlib::host::Result::Ok(id) => {
277///         trace_hex("Generated ledger entry ID", &id);
278///       }
279///       xrpl_common_stdlib::host::Result::Err(e) => {
280///         trace_num("Error assembling ledger entry ID", e.code() as i64);
281///       }
282///     }
283///     Ok(())
284/// }
285/// ```
286pub fn delegate_id(account: &AccountID, authorize: &AccountID) -> Result<LedgerEntryIdBytes> {
287    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
288        host::delegate_id(
289            account.0.as_ptr(),
290            account.0.len(),
291            authorize.0.as_ptr(),
292            authorize.0.len(),
293            id_buffer_ptr,
294            id_buffer_len,
295        )
296    })
297}
298
299/// Generates a deposit preauth ledger entry ID for a given account and authorized account.
300///
301/// A deposit preauth ledger entry ID is used to reference deposit preauth entries in the XRP Ledger.
302///
303/// # Arguments
304///
305/// * `account` - The AccountID of the account that is doing the pre-authorizing
306/// * `authorize` - The AccountID of the account that is pre-authorizing
307///
308/// # Returns
309///
310/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte deposit preauth ledger entry ID.
311///   On failure, returns an `Error` with the corresponding error code.
312///
313/// # Safety
314///
315/// This function makes unsafe FFI calls to the host environment through
316/// the `host::deposit_preauth_id` function.
317///
318/// # Example
319///
320/// ```rust
321/// use xrpl_common_stdlib::types::account_id::AccountID;
322/// use xrpl_common_stdlib::ledger_entry_ids::deposit_preauth_id;
323/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
324/// fn main() -> Result<(), Box<dyn std::error::Error>> {
325///     let account: AccountID =
326///         AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
327///     let authorize: AccountID =
328///         AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
329///     match deposit_preauth_id(&account, &authorize) {
330///       xrpl_common_stdlib::host::Result::Ok(id) => {
331///         trace_hex("Generated ledger entry ID", &id);
332///       }
333///       xrpl_common_stdlib::host::Result::Err(e) => {
334///         trace_num("Error assembling ledger entry ID", e.code() as i64);
335///       }
336///     }
337///     Ok(())
338/// }
339/// ```
340pub fn deposit_preauth_id(
341    account: &AccountID,
342    authorize: &AccountID,
343) -> Result<LedgerEntryIdBytes> {
344    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
345        host::deposit_preauth_id(
346            account.0.as_ptr(),
347            account.0.len(),
348            authorize.0.as_ptr(),
349            authorize.0.len(),
350            id_buffer_ptr,
351            id_buffer_len,
352        )
353    })
354}
355
356/// Generates a DID ledger entry ID for a given XRP Ledger account.
357///
358/// DID ledger entry IDs are used to reference DID entries in the XRP Ledger's state data.
359/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
360///
361/// # Arguments
362///
363/// * `account_id` - Reference to an `AccountID` representing the XRP Ledger account
364///
365/// # Returns
366///
367/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte DID ledger entry ID.
368///   On failure, returns an `Error` with the corresponding error code.
369///
370/// # Safety
371///
372/// This function makes unsafe FFI calls to the host environment through
373/// the `host::did_id` function, though the unsafe code is contained
374/// within the closure passed to `create_id_from_host_call`.
375///
376/// # Example
377///
378/// ```rust
379///
380/// use xrpl_common_stdlib::types::account_id::AccountID;
381/// use xrpl_common_stdlib::ledger_entry_ids::did_id;
382/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
383/// fn main() -> Result<(), Box<dyn std::error::Error>> {
384///   let account:AccountID = AccountID::from(
385///     *b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3"
386///   );
387///   match did_id(&account){
388///     xrpl_common_stdlib::host::Result::Ok(id) => {
389///       trace_hex("Generated ledger entry ID", &id);
390///     }
391///     xrpl_common_stdlib::host::Result::Err(e) => {
392///       trace_num("Error assembling ledger entry ID", e.code() as i64);
393///     }
394///   }
395///   Ok(())
396/// }
397/// ```
398pub fn did_id(account_id: &AccountID) -> Result<LedgerEntryIdBytes> {
399    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
400        host::did_id(
401            account_id.0.as_ptr(),
402            account_id.0.len(),
403            id_buffer_ptr,
404            id_buffer_len,
405        )
406    })
407}
408
409/// Generates an escrow ledger entry ID for a given owner and sequence in the XRP Ledger.
410///
411/// Escrow ledger entry IDs are used to reference escrow entries in the XRP Ledger's state data.
412/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
413///
414/// # Arguments
415///
416/// * `owner` - Reference to an `AccountID` representing the escrow owner's account
417/// * `seq` - The account sequence associated with the escrow entry
418///
419/// # Returns
420///
421/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte escrow ledger entry ID.
422///   On failure, returns an `Error` with the corresponding error code.
423///
424/// # Safety
425///
426/// This function makes unsafe FFI calls to the host environment through
427/// the `host::escrow_id` function, though the unsafe code is contained
428/// within the closure passed to `create_id_from_host_call`.
429///
430/// # Example
431///
432/// ```rust
433/// use xrpl_common_stdlib::types::account_id::AccountID;
434/// use xrpl_common_stdlib::ledger_entry_ids::escrow_id;
435/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
436///
437/// fn main() -> Result<(), Box<dyn std::error::Error>> {
438///   let owner: AccountID =
439///       AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
440///   let sequence = 12345;
441///   match escrow_id(&owner, sequence) {
442///     xrpl_common_stdlib::host::Result::Ok(id) => {
443///       trace_hex("Generated ledger entry ID", &id);
444///     }
445///     xrpl_common_stdlib::host::Result::Err(e) => {
446///       trace_num("Error assembling ledger entry ID", e.code() as i64);
447///     }
448///   }
449///   Ok(())
450///}
451/// ```
452pub fn escrow_id(owner: &AccountID, seq: u32) -> Result<LedgerEntryIdBytes> {
453    let seq_bytes = seq.to_le_bytes();
454    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
455        host::escrow_id(
456            owner.0.as_ptr(),
457            owner.0.len(),
458            seq_bytes.as_ptr(),
459            seq_bytes.len(),
460            id_buffer_ptr,
461            id_buffer_len,
462        )
463    })
464}
465
466/// Generates a trustline ledger entry ID for a given pair of accounts and currency code.
467///
468/// A trustline ledger entry ID is used to reference trustline entries in the XRP Ledger.
469///
470/// # Arguments
471///
472/// * `account` - The first AccountID in the trustline relationship
473/// * `account2` - The second AccountID in the trustline relationship
474/// * `currency` - The Currency for the trustline
475///
476/// # Returns
477///
478/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte trustline ledger entry ID.
479///   On failure, returns an `Error` with the corresponding error code.
480///
481/// # Safety
482///
483/// This function makes unsafe FFI calls to the host environment through
484/// the `host::trustline_id` function.
485///
486/// # Example
487///
488/// ```rust
489/// use xrpl_common_stdlib::types::account_id::AccountID;
490/// use xrpl_common_stdlib::types::currency::Currency;
491/// use xrpl_common_stdlib::ledger_entry_ids::trustline_id;
492/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
493/// fn main() -> Result<(), Box<dyn std::error::Error>> {
494///  let account1: AccountID =
495///    AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
496///  let account2: AccountID =
497///    AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
498///  let currency = b"RLUSD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; // RLUSD currency code
499///  let currency: Currency = Currency::from(*currency);
500///  match trustline_id(&account1, &account2, &currency) {
501///    xrpl_common_stdlib::host::Result::Ok(id) => {
502///      trace_hex("Generated ledger entry ID", &id);
503///    }
504///    xrpl_common_stdlib::host::Result::Err(e) => {
505///      trace_num("Error assembling ledger entry ID", e.code() as i64);
506///    }
507///  }
508///  Ok(())
509/// }
510/// ```
511pub fn trustline_id(
512    account1: &AccountID,
513    account2: &AccountID,
514    currency: &Currency,
515) -> Result<LedgerEntryIdBytes> {
516    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
517        host::trustline_id(
518            account1.0.as_ptr(),
519            account1.0.len(),
520            account2.0.as_ptr(),
521            account2.0.len(),
522            currency.0.as_ptr(),
523            currency.0.len(),
524            id_buffer_ptr,
525            id_buffer_len,
526        )
527    })
528}
529
530/// Generates an MPT issuance ledger entry ID for a given owner and sequence in the XRP Ledger.
531///
532/// MPT issuance ledger entry IDs are used to reference MPT issuance entries in the XRP Ledger's state data.
533/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
534///
535/// # Arguments
536///
537/// * `owner` - Reference to an `AccountID` representing the MPT issuer's account
538/// * `seq` - The account sequence associated with the MPT issuance entry
539///
540/// # Returns
541///
542/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte MPT issuance ledger entry ID.
543///   On failure, returns an `Error` with the corresponding error code.
544///
545/// # Safety
546///
547/// This function makes unsafe FFI calls to the host environment through
548/// the `host::mpt_issuance_id` function, though the unsafe code is contained
549/// within the closure passed to `create_id_from_host_call`.
550///
551/// # Example
552///
553/// ```rust
554/// use xrpl_common_stdlib::types::account_id::AccountID;
555/// use xrpl_common_stdlib::ledger_entry_ids::mpt_issuance_id;
556/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
557///
558/// fn main() -> Result<(), Box<dyn std::error::Error>> {
559///   let owner: AccountID =
560///       AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
561///   let sequence = 12345;
562///   match mpt_issuance_id(&owner, sequence) {
563///     xrpl_common_stdlib::host::Result::Ok(id) => {
564///       trace_hex("Generated ledger entry ID", &id);
565///     }
566///     xrpl_common_stdlib::host::Result::Err(e) => {
567///       trace_num("Error assembling ledger entry ID", e.code() as i64);
568///     }
569///   }
570///   Ok(())
571///}
572/// ```
573pub fn mpt_issuance_id(owner: &AccountID, seq: u32) -> Result<LedgerEntryIdBytes> {
574    let seq_bytes = seq.to_le_bytes();
575    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
576        host::mpt_issuance_id(
577            owner.0.as_ptr(),
578            owner.0.len(),
579            seq_bytes.as_ptr(),
580            seq_bytes.len(),
581            id_buffer_ptr,
582            id_buffer_len,
583        )
584    })
585}
586
587/// Generates an MPToken ledger entry ID for a given MPT ID and holder.
588///
589/// An MPToken ledger entry ID is used to reference MPToken entries in the XRP Ledger.
590///
591/// # Arguments
592///
593/// * `mptid` - The MPT ID that the MPToken is associated with
594/// * `holder` - The AccountID of the account that holds the MPToken
595///
596/// # Returns
597///
598/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte MPToken ledger entry ID.
599///   On failure, returns an `Error` with the corresponding error code.
600///
601/// # Safety
602///
603/// This function makes unsafe FFI calls to the host environment through
604/// the `host::mptoken_id` function.
605///
606/// # Example
607///
608/// ```rust
609/// use xrpl_common_stdlib::types::account_id::AccountID;
610/// use xrpl_common_stdlib::types::mpt_id::MptId;
611/// use xrpl_common_stdlib::ledger_entry_ids::mptoken_id;
612/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
613/// fn main() -> Result<(), Box<dyn std::error::Error>> {
614///     let issuer: AccountID =
615///         AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
616///     let mptid: MptId = MptId::new(1, issuer);
617///     let holder: AccountID =
618///         AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
619///     match mptoken_id(&mptid, &holder) {
620///       xrpl_common_stdlib::host::Result::Ok(id) => {
621///         trace_hex("Generated ledger entry ID", &id);
622///       }
623///       xrpl_common_stdlib::host::Result::Err(e) => {
624///         trace_num("Error assembling ledger entry ID", e.code() as i64);
625///       }
626///     }
627///     Ok(())
628/// }
629/// ```
630pub fn mptoken_id(mptid: &MptId, holder: &AccountID) -> Result<LedgerEntryIdBytes> {
631    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
632        host::mptoken_id(
633            mptid.as_bytes().as_ptr(),
634            mptid.as_bytes().len(),
635            holder.0.as_ptr(),
636            holder.0.len(),
637            id_buffer_ptr,
638            id_buffer_len,
639        )
640    })
641}
642
643/// Generates an NFT offer ledger entry ID for a given owner and sequence in the XRP Ledger.
644///
645/// NFT offer ledger entry IDs are used to reference NFT offer entries in the XRP Ledger's state data.
646/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
647///
648/// # Arguments
649///
650/// * `owner` - Reference to an `AccountID` representing the NFT offer owner's account
651/// * `seq` - The account sequence associated with the NFT offer entry
652///
653/// # Returns
654///
655/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte NFT offer ledger entry ID.
656///   On failure, returns an `Error` with the corresponding error code.
657///
658/// # Safety
659///
660/// This function makes unsafe FFI calls to the host environment through
661/// the `host::nft_offer_id` function, though the unsafe code is contained
662/// within the closure passed to `create_id_from_host_call`.
663///
664/// # Example
665///
666/// ```rust
667/// use xrpl_common_stdlib::types::account_id::AccountID;
668/// use xrpl_common_stdlib::ledger_entry_ids::nft_offer_id;
669/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
670///
671/// fn main() -> Result<(), Box<dyn std::error::Error>> {
672///   let owner: AccountID =
673///       AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
674///   let sequence = 12345;
675///   match nft_offer_id(&owner, sequence) {
676///     xrpl_common_stdlib::host::Result::Ok(id) => {
677///       trace_hex("Generated ledger entry ID", &id);
678///     }
679///     xrpl_common_stdlib::host::Result::Err(e) => {
680///       trace_num("Error assembling ledger entry ID", e.code() as i64);
681///     }
682///   }
683///   Ok(())
684///}
685/// ```
686pub fn nft_offer_id(owner: &AccountID, seq: u32) -> Result<LedgerEntryIdBytes> {
687    let seq_bytes = seq.to_le_bytes();
688    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
689        host::nft_offer_id(
690            owner.0.as_ptr(),
691            owner.0.len(),
692            seq_bytes.as_ptr(),
693            seq_bytes.len(),
694            id_buffer_ptr,
695            id_buffer_len,
696        )
697    })
698}
699
700/// Generates an offer ledger entry ID for a given owner and sequence in the XRP Ledger.
701///
702/// Offer ledger entry IDs are used to reference offer entries in the XRP Ledger's state data.
703/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
704///
705/// # Arguments
706///
707/// * `owner` - Reference to an `AccountID` representing the offer owner's account
708/// * `seq` - The account sequence associated with the offer entry
709///
710/// # Returns
711///
712/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte offer ledger entry ID.
713///   On failure, returns an `Error` with the corresponding error code.
714///
715/// # Safety
716///
717/// This function makes unsafe FFI calls to the host environment through
718/// the `host::offer_id` function, though the unsafe code is contained
719/// within the closure passed to `create_id_from_host_call`.
720///
721/// # Example
722///
723/// ```rust
724/// use xrpl_common_stdlib::types::account_id::AccountID;
725/// use xrpl_common_stdlib::ledger_entry_ids::offer_id;
726/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
727///
728/// fn main() -> Result<(), Box<dyn std::error::Error>> {
729///   let owner: AccountID =
730///       AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
731///   let sequence = 12345;
732///   match offer_id(&owner, sequence) {
733///     xrpl_common_stdlib::host::Result::Ok(id) => {
734///       trace_hex("Generated ledger entry ID", &id);
735///     }
736///     xrpl_common_stdlib::host::Result::Err(e) => {
737///       trace_num("Error assembling ledger entry ID", e.code() as i64);
738///     }
739///   }
740///   Ok(())
741///}
742/// ```
743pub fn offer_id(owner: &AccountID, seq: u32) -> Result<LedgerEntryIdBytes> {
744    let seq_bytes = seq.to_le_bytes();
745    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
746        host::offer_id(
747            owner.0.as_ptr(),
748            owner.0.len(),
749            seq_bytes.as_ptr(),
750            seq_bytes.len(),
751            id_buffer_ptr,
752            id_buffer_len,
753        )
754    })
755}
756
757/// Generates an oracle ledger entry ID for a given owner and document ID in the XRP Ledger.
758///
759/// Oracle ledger entry IDs are used to reference oracle entries in the XRP Ledger's state data.
760/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
761///
762/// # Arguments
763///
764/// * `owner` - Reference to an `AccountID` representing the oracle owner's account
765/// * `document_id` - An integer identifier for the oracle document
766///
767/// # Returns
768///
769/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte oracle ledger entry ID.
770///   On failure, returns an `Error` with the corresponding error code.
771///
772/// # Safety
773///
774/// This function makes unsafe FFI calls to the host environment through
775/// the `host::oracle_id` function, though the unsafe code is contained
776/// within the closure passed to `create_id_from_host_call`.
777///
778/// # Example
779///
780/// ```rust
781/// use xrpl_common_stdlib::types::account_id::AccountID;
782/// use xrpl_common_stdlib::ledger_entry_ids::oracle_id;
783/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
784///
785/// fn main() -> Result<(), Box<dyn std::error::Error>> {
786///   let owner: AccountID =
787///       AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
788///   let document_id = 12345;
789///   match oracle_id(&owner, document_id) {
790///     xrpl_common_stdlib::host::Result::Ok(id) => {
791///       trace_hex("Generated ledger entry ID", &id);
792///     }
793///     xrpl_common_stdlib::host::Result::Err(e) => {
794///       trace_num("Error assembling ledger entry ID", e.code() as i64);
795///     }
796///   }
797///   Ok(())
798///}
799/// ```
800pub fn oracle_id(owner: &AccountID, document_id: u32) -> Result<LedgerEntryIdBytes> {
801    let document_id_bytes = document_id.to_le_bytes();
802    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
803        host::oracle_id(
804            owner.0.as_ptr(),
805            owner.0.len(),
806            document_id_bytes.as_ptr(),
807            document_id_bytes.len(),
808            id_buffer_ptr,
809            id_buffer_len,
810        )
811    })
812}
813
814/// Generates a payment channel ledger entry ID for a given owner and sequence in the XRP Ledger.
815///
816/// Payment channel ledger entry IDs are used to reference payment channel entries in the XRP Ledger's state data.
817/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
818///
819/// # Arguments
820///
821/// * `account` - Reference to an `AccountID` representing the payment channel sender's account
822/// * `destination` - Reference to an `AccountID` representing the payment channel's destination
823/// * `seq` - The account sequence associated with the payment channel entry
824///
825/// # Returns
826///
827/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte payment channel ledger entry ID.
828///   On failure, returns an `Error` with the corresponding error code.
829///
830/// # Safety
831///
832/// This function makes unsafe FFI calls to the host environment through
833/// the `host::paychan_id` function, though the unsafe code is contained
834/// within the closure passed to `create_id_from_host_call`.
835///
836/// # Example
837///
838/// ```rust
839/// use xrpl_common_stdlib::types::account_id::AccountID;
840/// use xrpl_common_stdlib::ledger_entry_ids::paychan_id;
841/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
842///
843/// fn main() -> Result<(), Box<dyn std::error::Error>> {
844///   let account: AccountID =
845///       AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
846///   let destination: AccountID =
847///       AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
848///   let sequence = 12345;
849///   match paychan_id(&account, &destination, sequence) {
850///     xrpl_common_stdlib::host::Result::Ok(id) => {
851///       trace_hex("Generated ledger entry ID", &id);
852///     }
853///     xrpl_common_stdlib::host::Result::Err(e) => {
854///       trace_num("Error assembling ledger entry ID", e.code() as i64);
855///     }
856///   }
857///   Ok(())
858///}
859/// ```
860pub fn paychan_id(
861    account: &AccountID,
862    destination: &AccountID,
863    seq: u32,
864) -> Result<LedgerEntryIdBytes> {
865    let seq_bytes = seq.to_le_bytes();
866    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
867        host::paychan_id(
868            account.0.as_ptr(),
869            account.0.len(),
870            destination.0.as_ptr(),
871            destination.0.len(),
872            seq_bytes.as_ptr(),
873            seq_bytes.len(),
874            id_buffer_ptr,
875            id_buffer_len,
876        )
877    })
878}
879
880/// Generates a permissioned domain ledger entry ID for a given owner and sequence in the XRP Ledger.
881///
882/// Permissioned domain ledger entry IDs are used to reference permissioned domain entries in the XRP Ledger's state data.
883/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
884///
885/// # Arguments
886///
887/// * `account` - Reference to an `AccountID` representing the permissioned domain's owner
888/// * `seq` - The account sequence associated with the permissioned domain entry
889///
890/// # Returns
891///
892/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte permissioned domain ledger entry ID.
893///   On failure, returns an `Error` with the corresponding error code.
894///
895/// # Safety
896///
897/// This function makes unsafe FFI calls to the host environment through
898/// the `host::permissioned_domain_id` function, though the unsafe code is contained
899/// within the closure passed to `create_id_from_host_call`.
900///
901/// # Example
902///
903/// ```rust
904/// use xrpl_common_stdlib::types::account_id::AccountID;
905/// use xrpl_common_stdlib::ledger_entry_ids::permissioned_domain_id;
906/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
907///
908/// fn main() -> Result<(), Box<dyn std::error::Error>> {
909///   let account: AccountID =
910///       AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
911///   let sequence = 12345;
912///   match permissioned_domain_id(&account, sequence) {
913///     xrpl_common_stdlib::host::Result::Ok(id) => {
914///       trace_hex("Generated ledger entry ID", &id);
915///     }
916///     xrpl_common_stdlib::host::Result::Err(e) => {
917///       trace_num("Error assembling ledger entry ID", e.code() as i64);
918///     }
919///   }
920///   Ok(())
921///}
922/// ```
923pub fn permissioned_domain_id(account: &AccountID, seq: u32) -> Result<LedgerEntryIdBytes> {
924    let seq_bytes = seq.to_le_bytes();
925    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
926        host::permissioned_domain_id(
927            account.0.as_ptr(),
928            account.0.len(),
929            seq_bytes.as_ptr(),
930            seq_bytes.len(),
931            id_buffer_ptr,
932            id_buffer_len,
933        )
934    })
935}
936
937/// Generates a signer entry ledger entry ID for a given XRP Ledger account.
938///
939/// signer entry ledger entry IDs are used to reference signer entries in the XRP Ledger's state data.
940/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
941///
942/// # Arguments
943///
944/// * `account_id` - Reference to an `AccountID` representing the XRP Ledger account
945///
946/// # Returns
947///
948/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte signer entry ledger entry ID.
949///   On failure, returns an `Error` with the corresponding error code.
950///
951/// # Safety
952///
953/// This function makes unsafe FFI calls to the host environment through
954/// the `host::signers_id` function, though the unsafe code is contained
955/// within the closure passed to `create_id_from_host_call`.
956///
957/// # Example
958///
959/// ```rust
960///
961/// use xrpl_common_stdlib::types::account_id::AccountID;
962/// use xrpl_common_stdlib::ledger_entry_ids::signers_id;
963/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
964/// fn main() -> Result<(), Box<dyn std::error::Error>> {
965///   let account:AccountID = AccountID::from(
966///     *b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3"
967///   );
968///   match signers_id(&account){
969///     xrpl_common_stdlib::host::Result::Ok(id) => {
970///       trace_hex("Generated ledger entry ID", &id);
971///     }
972///     xrpl_common_stdlib::host::Result::Err(e) => {
973///       trace_num("Error assembling ledger entry ID", e.code() as i64);
974///     }
975///   }
976///   Ok(())
977/// }
978/// ```
979pub fn signers_id(account_id: &AccountID) -> Result<LedgerEntryIdBytes> {
980    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
981        host::signers_id(
982            account_id.0.as_ptr(),
983            account_id.0.len(),
984            id_buffer_ptr,
985            id_buffer_len,
986        )
987    })
988}
989
990/// Generates a ticket ledger entry ID for a given owner and sequence in the XRP Ledger.
991///
992/// Ticket ledger entry IDs are used to reference ticket entries in the XRP Ledger's state data.
993/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
994///
995/// # Arguments
996///
997/// * `owner` - Reference to an `AccountID` representing the ticket owner's account
998/// * `seq` - The account sequence associated with the ticket entry
999///
1000/// # Returns
1001///
1002/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte ticket ledger entry ID.
1003///   On failure, returns an `Error` with the corresponding error code.
1004///
1005/// # Safety
1006///
1007/// This function makes unsafe FFI calls to the host environment through
1008/// the `host::ticket_id` function, though the unsafe code is contained
1009/// within the closure passed to `create_id_from_host_call`.
1010///
1011/// # Example
1012///
1013/// ```rust
1014/// use xrpl_common_stdlib::types::account_id::AccountID;
1015/// use xrpl_common_stdlib::ledger_entry_ids::ticket_id;
1016/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
1017///
1018/// fn main() -> Result<(), Box<dyn std::error::Error>> {
1019///   let owner: AccountID =
1020///       AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
1021///   let sequence = 12345;
1022///   match ticket_id(&owner, sequence) {
1023///     xrpl_common_stdlib::host::Result::Ok(id) => {
1024///       trace_hex("Generated ledger entry ID", &id);
1025///     }
1026///     xrpl_common_stdlib::host::Result::Err(e) => {
1027///       trace_num("Error assembling ledger entry ID", e.code() as i64);
1028///     }
1029///   }
1030///   Ok(())
1031///}
1032/// ```
1033pub fn ticket_id(owner: &AccountID, seq: u32) -> Result<LedgerEntryIdBytes> {
1034    let seq_bytes = seq.to_le_bytes();
1035    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
1036        host::ticket_id(
1037            owner.0.as_ptr(),
1038            owner.0.len(),
1039            seq_bytes.as_ptr(),
1040            seq_bytes.len(),
1041            id_buffer_ptr,
1042            id_buffer_len,
1043        )
1044    })
1045}
1046
1047/// Generates a vault ledger entry ID for a given owner and sequence in the XRP Ledger.
1048///
1049/// Vault ledger entry IDs are used to reference vault entries in the XRP Ledger's state data.
1050/// This function uses the generic `create_id_from_host_call` helper to manage the FFI interaction.
1051///
1052/// # Arguments
1053///
1054/// * `account` - Reference to an `AccountID` representing the vault's owner
1055/// * `seq` - The account sequence associated with the vault entry
1056///
1057/// # Returns
1058///
1059/// * `Result<LedgerEntryIdBytes>` - On success, returns a 32-byte vault ledger entry ID.
1060///   On failure, returns an `Error` with the corresponding error code.
1061///
1062/// # Safety
1063///
1064/// This function makes unsafe FFI calls to the host environment through
1065/// the `host::vault_id` function, though the unsafe code is contained
1066/// within the closure passed to `create_id_from_host_call`.
1067///
1068/// # Example
1069///
1070/// ```rust
1071/// use xrpl_common_stdlib::types::account_id::AccountID;
1072/// use xrpl_common_stdlib::ledger_entry_ids::vault_id;
1073/// use xrpl_common_stdlib::host::trace::{ trace_hex, trace_num };
1074///
1075/// fn main() -> Result<(), Box<dyn std::error::Error>> {
1076///   let account: AccountID =
1077///       AccountID::from(*b"\xd5\xb9\x84VP\x9f \xb5'\x9d\x1eJ.\xe8\xb2\xaa\x82\xaec\xe3");
1078///   let sequence = 12345;
1079///   match vault_id(&account, sequence) {
1080///     xrpl_common_stdlib::host::Result::Ok(id) => {
1081///       trace_hex("Generated ledger entry ID", &id);
1082///     }
1083///     xrpl_common_stdlib::host::Result::Err(e) => {
1084///       trace_num("Error assembling ledger entry ID", e.code() as i64);
1085///     }
1086///   }
1087///   Ok(())
1088///}
1089/// ```
1090pub fn vault_id(account: &AccountID, seq: u32) -> Result<LedgerEntryIdBytes> {
1091    let seq_bytes = seq.to_le_bytes();
1092    create_id_from_host_call(|id_buffer_ptr, id_buffer_len| unsafe {
1093        host::vault_id(
1094            account.0.as_ptr(),
1095            account.0.len(),
1096            seq_bytes.as_ptr(),
1097            seq_bytes.len(),
1098            id_buffer_ptr,
1099            id_buffer_len,
1100        )
1101    })
1102}
1103
1104/// Generic helper function to create a ledger entry ID by calling a host function.
1105///
1106/// This function handles the common tasks of:
1107/// - Initializing the ledger entry ID output buffer.
1108/// - Invoking the provided `host_call` closure (which performs the unsafe host FFI call).
1109/// - Converting the host call's `i32` result code into a `Result<LedgerEntryIdBytes, Error>`.
1110///
1111/// # Arguments
1112///
1113/// * `host_call`: A closure that takes a mutable pointer to the output buffer (`*mut u8`)
1114///   and its length (`usize`), performs the specific host FFI call, and returns an `i32` status
1115///   code.
1116fn create_id_from_host_call<F>(host_call: F) -> Result<LedgerEntryIdBytes>
1117where
1118    F: FnOnce(*mut u8, usize) -> i32,
1119{
1120    let mut id_buffer: LedgerEntryIdBytes = [0; XRPL_LEDGER_ENTRY_ID_SIZE];
1121    let result_code: i32 = host_call(id_buffer.as_mut_ptr(), id_buffer.len());
1122
1123    match_result_code_with_expected_bytes(result_code, XRPL_LEDGER_ENTRY_ID_SIZE, || id_buffer)
1124}
1125
1126#[cfg(test)]
1127mod tests {
1128    use super::*;
1129    use crate::host::error_codes::SOME_ERROR;
1130    use crate::host::host_bindings_trait::MockHostBindings;
1131    use crate::host::setup_mock;
1132
1133    const EXPECTED_ID: LedgerEntryIdBytes = [0xCC; XRPL_LEDGER_ENTRY_ID_SIZE];
1134
1135    /// Writes `0xCC` into the output buffer and returns `XRPL_LEDGER_ENTRY_ID_SIZE` as success.
1136    fn write_id_to_buffer(out_buff_ptr: *mut u8, out_buff_len: usize) -> i32 {
1137        assert_eq!(out_buff_len, XRPL_LEDGER_ENTRY_ID_SIZE);
1138        unsafe {
1139            for i in 0..XRPL_LEDGER_ENTRY_ID_SIZE {
1140                *out_buff_ptr.add(i) = 0xCC;
1141            }
1142        }
1143        XRPL_LEDGER_ENTRY_ID_SIZE as i32
1144    }
1145
1146    /// Generates a mock `returning` closure that delegates to `write_id_to_buffer`.
1147    /// Pass the number of prefix parameters (before the out_buff_ptr/out_buff_len pair)
1148    /// to match the host function arity.
1149    macro_rules! write_id_returning {
1150        (2) => {
1151            |_, _, out_buff_ptr, out_buff_len| write_id_to_buffer(out_buff_ptr, out_buff_len)
1152        };
1153        (4) => {
1154            |_, _, _, _, out_buff_ptr, out_buff_len| write_id_to_buffer(out_buff_ptr, out_buff_len)
1155        };
1156        (6) => {
1157            |_, _, _, _, _, _, out_buff_ptr, out_buff_len| {
1158                write_id_to_buffer(out_buff_ptr, out_buff_len)
1159            }
1160        };
1161    }
1162
1163    /// Generates a mock `returning` closure that returns SOME_ERROR.
1164    /// Pass the total number of parameters of the host function.
1165    macro_rules! error_returning {
1166        (4) => {
1167            |_, _, _, _| SOME_ERROR
1168        };
1169        (6) => {
1170            |_, _, _, _, _, _| SOME_ERROR
1171        };
1172        (8) => {
1173            |_, _, _, _, _, _, _, _| SOME_ERROR
1174        };
1175    }
1176
1177    /// Generates a test module with success and error tests for a ledger entry ID function.
1178    ///
1179    /// Arguments:
1180    /// - `$mod_name`: name for the test module
1181    /// - `$expect_fn`: mock expectation method (e.g., `expect_accountroot_id`)
1182    /// - `$success_arity`: number of prefix params for write_id_returning (2, 4, or 6)
1183    /// - `$error_arity`: total number of params for error_returning (4, 6, or 8)
1184    /// - `$call_block`: block that sets up args and returns the ledger entry ID function call result
1185    macro_rules! id_test {
1186        ($mod_name:ident, $expect_fn:ident, $success_arity:tt, $error_arity:tt, $call_block:block) => {
1187            mod $mod_name {
1188                use super::*;
1189
1190                #[test]
1191                fn test_success() {
1192                    let mut mock = MockHostBindings::new();
1193                    mock.$expect_fn()
1194                        .times(1)
1195                        .returning(write_id_returning!($success_arity));
1196                    let _guard = setup_mock(mock);
1197
1198                    let result = $call_block;
1199                    assert!(result.is_ok());
1200                    assert_eq!(result.unwrap(), EXPECTED_ID);
1201                }
1202
1203                #[test]
1204                fn test_error() {
1205                    let mut mock = MockHostBindings::new();
1206                    mock.$expect_fn()
1207                        .times(1)
1208                        .returning(error_returning!($error_arity));
1209                    let _guard = setup_mock(mock);
1210
1211                    let result = $call_block;
1212                    assert!(result.is_err());
1213                    assert_eq!(result.err().unwrap().code(), SOME_ERROR);
1214                }
1215            }
1216        };
1217    }
1218
1219    id_test!(accountroot_id_tests, expect_accountroot_id, 2, 4, {
1220        let account_id = AccountID::from([0xBB; 20]);
1221        accountroot_id(&account_id)
1222    });
1223
1224    id_test!(check_id_tests, expect_check_id, 4, 6, {
1225        let owner = AccountID::from([0xBB; 20]);
1226        check_id(&owner, 12345)
1227    });
1228
1229    id_test!(delegate_id_tests, expect_delegate_id, 4, 6, {
1230        let account = AccountID::from([0xBB; 20]);
1231        let authorize = AccountID::from([0xBB; 20]);
1232        delegate_id(&account, &authorize)
1233    });
1234
1235    id_test!(credential_id_tests, expect_credential_id, 6, 8, {
1236        let subject = AccountID::from([0xBB; 20]);
1237        let issuer = AccountID::from([0xBB; 20]);
1238        let cred_type: &[u8] = b"termsandconditions";
1239        credential_id(&subject, &issuer, cred_type)
1240    });
1241
1242    id_test!(amm_id_tests, expect_amm_id, 4, 6, {
1243        use crate::types::issue::{Issue, XrpIssue};
1244        let issue1 = Issue::XRP(XrpIssue {});
1245        let issue2 = Issue::XRP(XrpIssue {});
1246        amm_id(&issue1, &issue2)
1247    });
1248
1249    id_test!(deposit_preauth_id_tests, expect_deposit_preauth_id, 4, 6, {
1250        let account = AccountID::from([0xBB; 20]);
1251        let authorize = AccountID::from([0xBB; 20]);
1252        deposit_preauth_id(&account, &authorize)
1253    });
1254
1255    id_test!(did_id_tests, expect_did_id, 2, 4, {
1256        let account_id = AccountID::from([0xBB; 20]);
1257        did_id(&account_id)
1258    });
1259
1260    id_test!(escrow_id_tests, expect_escrow_id, 4, 6, {
1261        let owner = AccountID::from([0xBB; 20]);
1262        escrow_id(&owner, 12345)
1263    });
1264
1265    id_test!(trustline_id_tests, expect_trustline_id, 6, 8, {
1266        use crate::types::currency::Currency;
1267        let account1 = AccountID::from([0xBB; 20]);
1268        let account2 = AccountID::from([0xBB; 20]);
1269        let currency = Currency::from([0xBB; 20]);
1270        trustline_id(&account1, &account2, &currency)
1271    });
1272
1273    id_test!(mpt_issuance_id_tests, expect_mpt_issuance_id, 4, 6, {
1274        let owner = AccountID::from([0xBB; 20]);
1275        mpt_issuance_id(&owner, 12345)
1276    });
1277
1278    id_test!(mptoken_id_tests, expect_mptoken_id, 4, 6, {
1279        use crate::types::mpt_id::MptId;
1280        let issuer = AccountID::from([0xBB; 20]);
1281        let mptid = MptId::new(1, issuer);
1282        let holder = AccountID::from([0xBB; 20]);
1283        mptoken_id(&mptid, &holder)
1284    });
1285
1286    id_test!(nft_offer_id_tests, expect_nft_offer_id, 4, 6, {
1287        let owner = AccountID::from([0xBB; 20]);
1288        nft_offer_id(&owner, 12345)
1289    });
1290
1291    id_test!(offer_id_tests, expect_offer_id, 4, 6, {
1292        let owner = AccountID::from([0xBB; 20]);
1293        offer_id(&owner, 12345)
1294    });
1295
1296    id_test!(oracle_id_tests, expect_oracle_id, 4, 6, {
1297        let owner = AccountID::from([0xBB; 20]);
1298        oracle_id(&owner, 12345)
1299    });
1300
1301    id_test!(paychan_id_tests, expect_paychan_id, 6, 8, {
1302        let account = AccountID::from([0xBB; 20]);
1303        let destination = AccountID::from([0xBB; 20]);
1304        paychan_id(&account, &destination, 12345)
1305    });
1306
1307    id_test!(
1308        permissioned_domain_id_tests,
1309        expect_permissioned_domain_id,
1310        4,
1311        6,
1312        {
1313            let account = AccountID::from([0xBB; 20]);
1314            permissioned_domain_id(&account, 12345)
1315        }
1316    );
1317
1318    id_test!(signers_id_tests, expect_signers_id, 2, 4, {
1319        let account_id = AccountID::from([0xBB; 20]);
1320        signers_id(&account_id)
1321    });
1322
1323    id_test!(ticket_id_tests, expect_ticket_id, 4, 6, {
1324        let owner = AccountID::from([0xBB; 20]);
1325        ticket_id(&owner, 12345)
1326    });
1327
1328    id_test!(vault_id_tests, expect_vault_id, 4, 6, {
1329        let account = AccountID::from([0xBB; 20]);
1330        vault_id(&account, 12345)
1331    });
1332
1333    #[test]
1334    #[should_panic]
1335    fn test_wrong_size_panics() {
1336        let mut mock = MockHostBindings::new();
1337
1338        // Return 16 instead of 32 — positive but wrong size
1339        mock.expect_accountroot_id()
1340            .times(1)
1341            .returning(|_, _, _, _| 16);
1342
1343        let _guard = setup_mock(mock);
1344
1345        let account_id = AccountID::from([0xBB; 20]);
1346        let _ = accountroot_id(&account_id);
1347    }
1348}