Skip to main content

ic_query/icrc/model/contracts/
requests.rs

1//! Module: icrc::model::contracts::requests
2//!
3//! Responsibility: public ICRC request contracts and their constructors.
4//! Does not own: reports, rows, source data, errors, live transport, or rendering.
5//! Boundary: keeps collection identity and view options explicit without affecting report schemas.
6
7use std::path::PathBuf;
8
9///
10/// IcrcLedgerRequest
11///
12/// Shared ledger identity and provenance for metadata and capability report builders.
13///
14
15#[derive(Clone, Debug, Eq, PartialEq)]
16pub struct IcrcLedgerRequest {
17    pub source_endpoint: String,
18    pub now_unix_secs: u64,
19    pub ledger_canister_id: String,
20}
21
22impl IcrcLedgerRequest {
23    #[must_use]
24    pub fn new(
25        source_endpoint: impl Into<String>,
26        now_unix_secs: u64,
27        ledger_canister_id: impl Into<String>,
28    ) -> Self {
29        Self {
30            source_endpoint: source_endpoint.into(),
31            now_unix_secs,
32            ledger_canister_id: ledger_canister_id.into(),
33        }
34    }
35}
36
37///
38/// IcrcBalanceRequest
39///
40/// Request accepted by the generic ICRC account balance report builder.
41///
42
43#[derive(Clone, Debug, Eq, PartialEq)]
44pub struct IcrcBalanceRequest {
45    pub source_endpoint: String,
46    pub now_unix_secs: u64,
47    pub ledger_canister_id: String,
48    pub account_owner: String,
49    pub subaccount_hex: Option<String>,
50}
51
52impl IcrcBalanceRequest {
53    #[must_use]
54    pub fn new(
55        source_endpoint: impl Into<String>,
56        now_unix_secs: u64,
57        ledger_canister_id: impl Into<String>,
58        account_owner: impl Into<String>,
59    ) -> Self {
60        Self {
61            source_endpoint: source_endpoint.into(),
62            now_unix_secs,
63            ledger_canister_id: ledger_canister_id.into(),
64            account_owner: account_owner.into(),
65            subaccount_hex: None,
66        }
67    }
68
69    #[must_use]
70    pub fn with_subaccount_hex(mut self, subaccount_hex: impl Into<String>) -> Self {
71        self.subaccount_hex = Some(subaccount_hex.into());
72        self
73    }
74}
75
76///
77/// IcrcAllowanceRequest
78///
79/// Request accepted by the generic ICRC allowance report builder.
80///
81
82#[derive(Clone, Debug, Eq, PartialEq)]
83pub struct IcrcAllowanceRequest {
84    pub source_endpoint: String,
85    pub now_unix_secs: u64,
86    pub ledger_canister_id: String,
87    pub account_owner: String,
88    pub account_subaccount_hex: Option<String>,
89    pub spender_owner: String,
90    pub spender_subaccount_hex: Option<String>,
91}
92
93impl IcrcAllowanceRequest {
94    #[must_use]
95    pub fn new(
96        source_endpoint: impl Into<String>,
97        now_unix_secs: u64,
98        ledger_canister_id: impl Into<String>,
99        account_owner: impl Into<String>,
100        spender_owner: impl Into<String>,
101    ) -> Self {
102        Self {
103            source_endpoint: source_endpoint.into(),
104            now_unix_secs,
105            ledger_canister_id: ledger_canister_id.into(),
106            account_owner: account_owner.into(),
107            account_subaccount_hex: None,
108            spender_owner: spender_owner.into(),
109            spender_subaccount_hex: None,
110        }
111    }
112
113    #[must_use]
114    pub fn with_account_subaccount_hex(
115        mut self,
116        account_subaccount_hex: impl Into<String>,
117    ) -> Self {
118        self.account_subaccount_hex = Some(account_subaccount_hex.into());
119        self
120    }
121
122    #[must_use]
123    pub fn with_spender_subaccount_hex(
124        mut self,
125        spender_subaccount_hex: impl Into<String>,
126    ) -> Self {
127        self.spender_subaccount_hex = Some(spender_subaccount_hex.into());
128        self
129    }
130}
131
132///
133/// IcrcAccountTransactionPageRequest
134///
135/// Request accepted by the live ICRC index account-transaction page builder.
136///
137
138#[derive(Clone, Debug, Eq, PartialEq)]
139pub struct IcrcAccountTransactionPageRequest {
140    /// IC API endpoint used for ledger and index queries.
141    pub source_endpoint: String,
142    /// Collection time as Unix seconds.
143    pub now_unix_secs: u64,
144    /// Ledger canister whose account history is requested.
145    pub ledger_canister_id: String,
146    /// Optional explicit index canister; otherwise ICRC-106 discovery is used.
147    pub index_canister_id: Option<String>,
148    /// Account owner principal.
149    pub account_owner: String,
150    /// Optional normalized 32-byte subaccount hex.
151    pub subaccount_hex: Option<String>,
152    /// Optional exclusive block-index cursor for backward pagination.
153    pub start: Option<String>,
154    /// Maximum number of account transactions to request.
155    pub limit: u32,
156}
157
158impl IcrcAccountTransactionPageRequest {
159    /// Constructs an account-history request that discovers the index through the ledger.
160    #[must_use]
161    pub fn new(
162        source_endpoint: impl Into<String>,
163        now_unix_secs: u64,
164        ledger_canister_id: impl Into<String>,
165        account_owner: impl Into<String>,
166        limit: u32,
167    ) -> Self {
168        Self {
169            source_endpoint: source_endpoint.into(),
170            now_unix_secs,
171            ledger_canister_id: ledger_canister_id.into(),
172            index_canister_id: None,
173            account_owner: account_owner.into(),
174            subaccount_hex: None,
175            start: None,
176            limit,
177        }
178    }
179
180    /// Uses an explicit index canister instead of ICRC-106 discovery.
181    #[must_use]
182    pub fn with_index_canister_id(mut self, index_canister_id: impl Into<String>) -> Self {
183        self.index_canister_id = Some(index_canister_id.into());
184        self
185    }
186
187    /// Selects a 32-byte ICRC subaccount encoded as hex.
188    #[must_use]
189    pub fn with_subaccount_hex(mut self, subaccount_hex: impl Into<String>) -> Self {
190        self.subaccount_hex = Some(subaccount_hex.into());
191        self
192    }
193
194    /// Starts after the given transaction block index when paginating backward.
195    #[must_use]
196    pub fn with_start(mut self, start: impl Into<String>) -> Self {
197        self.start = Some(start.into());
198        self
199    }
200}
201
202///
203/// IcrcAccountTransactionCacheRequest
204///
205/// Stable account-history cache identity independent of page and view options.
206///
207
208#[derive(Clone, Debug, Eq, PartialEq)]
209pub struct IcrcAccountTransactionCacheRequest {
210    /// Root directory containing the shared cache.
211    pub cache_root: PathBuf,
212    /// IC API endpoint whose indexed history is cached.
213    pub source_endpoint: String,
214    /// Ledger canister whose account history is cached.
215    pub ledger_canister_id: String,
216    /// Account owner principal.
217    pub account_owner: String,
218    /// Optional normalized 32-byte subaccount hex.
219    pub subaccount_hex: Option<String>,
220}
221
222impl IcrcAccountTransactionCacheRequest {
223    /// Constructs a cache identity for the default subaccount.
224    #[must_use]
225    pub fn new(
226        cache_root: impl Into<PathBuf>,
227        source_endpoint: impl Into<String>,
228        ledger_canister_id: impl Into<String>,
229        account_owner: impl Into<String>,
230    ) -> Self {
231        Self {
232            cache_root: cache_root.into(),
233            source_endpoint: source_endpoint.into(),
234            ledger_canister_id: ledger_canister_id.into(),
235            account_owner: account_owner.into(),
236            subaccount_hex: None,
237        }
238    }
239
240    /// Selects a 32-byte ICRC subaccount encoded as hex.
241    #[must_use]
242    pub fn with_subaccount_hex(mut self, subaccount_hex: impl Into<String>) -> Self {
243        self.subaccount_hex = Some(subaccount_hex.into());
244        self
245    }
246}
247
248///
249/// IcrcAccountTransactionRefreshRequest
250///
251/// Request for a forced complete account-history refresh.
252///
253
254#[derive(Clone, Debug, Eq, PartialEq)]
255pub struct IcrcAccountTransactionRefreshRequest {
256    /// Stable cache identity.
257    pub cache: IcrcAccountTransactionCacheRequest,
258    /// Collection start time as Unix seconds.
259    pub now_unix_secs: u64,
260    /// Optional explicit index canister; otherwise ICRC-106 discovery is used.
261    pub index_canister_id: Option<String>,
262    /// Maximum transactions requested per index page.
263    pub page_size: u32,
264    /// Optional diagnostic bound that fails rather than publishing a partial cache.
265    pub max_pages: Option<u32>,
266    /// Age after which an abandoned refresh lock is reported as stale.
267    pub lock_stale_after_seconds: u64,
268}
269
270impl IcrcAccountTransactionRefreshRequest {
271    /// Constructs a complete refresh request.
272    #[must_use]
273    pub const fn new(
274        cache: IcrcAccountTransactionCacheRequest,
275        now_unix_secs: u64,
276        page_size: u32,
277        lock_stale_after_seconds: u64,
278    ) -> Self {
279        Self {
280            cache,
281            now_unix_secs,
282            index_canister_id: None,
283            page_size,
284            max_pages: None,
285            lock_stale_after_seconds,
286        }
287    }
288
289    /// Uses an explicit index canister instead of ICRC-106 discovery.
290    #[must_use]
291    pub fn with_index_canister_id(mut self, index_canister_id: impl Into<String>) -> Self {
292        self.index_canister_id = Some(index_canister_id.into());
293        self
294    }
295
296    /// Bounds pages for diagnostics; reaching the bound never publishes a cache.
297    #[must_use]
298    pub const fn with_max_pages(mut self, max_pages: Option<u32>) -> Self {
299        self.max_pages = max_pages;
300        self
301    }
302}
303
304///
305/// IcrcAccountTransactionSort
306///
307/// Supported cached account-history ordering.
308///
309
310#[derive(Clone, Copy, Debug, Eq, PartialEq)]
311pub enum IcrcAccountTransactionSort {
312    /// Highest transaction id first.
313    Newest,
314    /// Lowest transaction id first.
315    Oldest,
316}
317
318impl IcrcAccountTransactionSort {
319    /// Stable JSON/text name for this ordering.
320    #[must_use]
321    pub const fn as_str(self) -> &'static str {
322        match self {
323            Self::Newest => "newest",
324            Self::Oldest => "oldest",
325        }
326    }
327}
328
329///
330/// IcrcAccountTransactionListRequest
331///
332/// Cache-only account-history list view.
333///
334
335#[derive(Clone, Debug, Eq, PartialEq)]
336pub struct IcrcAccountTransactionListRequest {
337    /// Stable cache identity.
338    pub cache: IcrcAccountTransactionCacheRequest,
339    /// Maximum cached rows returned by this view.
340    pub limit: u32,
341    /// Requested cached-row ordering.
342    pub sort: IcrcAccountTransactionSort,
343}
344
345impl IcrcAccountTransactionListRequest {
346    /// Constructs a newest-first cached list view.
347    #[must_use]
348    pub const fn new(cache: IcrcAccountTransactionCacheRequest, limit: u32) -> Self {
349        Self {
350            cache,
351            limit,
352            sort: IcrcAccountTransactionSort::Newest,
353        }
354    }
355
356    /// Selects cached-row ordering.
357    #[must_use]
358    pub const fn with_sort(mut self, sort: IcrcAccountTransactionSort) -> Self {
359        self.sort = sort;
360        self
361    }
362}
363
364///
365/// IcrcTransactionsRequest
366///
367/// Request accepted by the generic ICRC transaction history report builder.
368///
369
370#[derive(Clone, Debug, Eq, PartialEq)]
371pub struct IcrcTransactionsRequest {
372    pub source_endpoint: String,
373    pub now_unix_secs: u64,
374    pub ledger_canister_id: String,
375    pub start: u64,
376    pub limit: u32,
377    pub follow_archives: bool,
378}
379
380impl IcrcTransactionsRequest {
381    #[must_use]
382    pub fn new(
383        source_endpoint: impl Into<String>,
384        now_unix_secs: u64,
385        ledger_canister_id: impl Into<String>,
386        start: u64,
387        limit: u32,
388    ) -> Self {
389        Self {
390            source_endpoint: source_endpoint.into(),
391            now_unix_secs,
392            ledger_canister_id: ledger_canister_id.into(),
393            start,
394            limit,
395            follow_archives: false,
396        }
397    }
398
399    #[must_use]
400    pub const fn with_follow_archives(mut self, follow_archives: bool) -> Self {
401        self.follow_archives = follow_archives;
402        self
403    }
404}
405
406///
407/// IcrcArchivesRequest
408///
409/// Request accepted by the generic ICRC archives report builder.
410///
411
412#[derive(Clone, Debug, Eq, PartialEq)]
413pub struct IcrcArchivesRequest {
414    pub source_endpoint: String,
415    pub now_unix_secs: u64,
416    pub ledger_canister_id: String,
417    pub from_canister_id: Option<String>,
418}
419
420impl IcrcArchivesRequest {
421    #[must_use]
422    pub fn new(
423        source_endpoint: impl Into<String>,
424        now_unix_secs: u64,
425        ledger_canister_id: impl Into<String>,
426    ) -> Self {
427        Self {
428            source_endpoint: source_endpoint.into(),
429            now_unix_secs,
430            ledger_canister_id: ledger_canister_id.into(),
431            from_canister_id: None,
432        }
433    }
434
435    #[must_use]
436    pub fn with_from_canister_id(mut self, from_canister_id: impl Into<String>) -> Self {
437        self.from_canister_id = Some(from_canister_id.into());
438        self
439    }
440}