Skip to main content

ic_query/icrc/model/contracts/requests/
account_history.rs

1//! Module: icrc::model::contracts::requests::account_history
2//!
3//! Responsibility: ICRC account-history page, cache, refresh, and list requests.
4//! Does not own: ledger-wide history, live transport, cache mechanics, or reports.
5//! Boundary: separates stable collection identity from pagination and local view options.
6
7use std::path::PathBuf;
8
9///
10/// IcrcAccountTransactionPageRequest
11///
12/// Request accepted by the live ICRC index account-transaction page builder.
13///
14
15#[derive(Clone, Debug, Eq, PartialEq)]
16pub struct IcrcAccountTransactionPageRequest {
17    /// IC API endpoint used for ledger and index queries.
18    pub source_endpoint: String,
19    /// Collection time as Unix seconds.
20    pub now_unix_secs: u64,
21    /// Ledger canister whose account history is requested.
22    pub ledger_canister_id: String,
23    /// Optional explicit index canister; otherwise ICRC-106 discovery is used.
24    pub index_canister_id: Option<String>,
25    /// Account owner principal.
26    pub account_owner: String,
27    /// Optional normalized 32-byte subaccount hex.
28    pub subaccount_hex: Option<String>,
29    /// Optional exclusive block-index cursor for backward pagination.
30    pub start: Option<String>,
31    /// Maximum number of account transactions to request.
32    pub limit: u32,
33}
34
35impl IcrcAccountTransactionPageRequest {
36    /// Constructs an account-history request that discovers the index through the ledger.
37    #[must_use]
38    pub fn new(
39        source_endpoint: impl Into<String>,
40        now_unix_secs: u64,
41        ledger_canister_id: impl Into<String>,
42        account_owner: impl Into<String>,
43        limit: u32,
44    ) -> Self {
45        Self {
46            source_endpoint: source_endpoint.into(),
47            now_unix_secs,
48            ledger_canister_id: ledger_canister_id.into(),
49            index_canister_id: None,
50            account_owner: account_owner.into(),
51            subaccount_hex: None,
52            start: None,
53            limit,
54        }
55    }
56
57    /// Uses an explicit index canister instead of ICRC-106 discovery.
58    #[must_use]
59    pub fn with_index_canister_id(mut self, index_canister_id: impl Into<String>) -> Self {
60        self.index_canister_id = Some(index_canister_id.into());
61        self
62    }
63
64    /// Selects a 32-byte ICRC subaccount encoded as hex.
65    #[must_use]
66    pub fn with_subaccount_hex(mut self, subaccount_hex: impl Into<String>) -> Self {
67        self.subaccount_hex = Some(subaccount_hex.into());
68        self
69    }
70
71    /// Starts after the given transaction block index when paginating backward.
72    #[must_use]
73    pub fn with_start(mut self, start: impl Into<String>) -> Self {
74        self.start = Some(start.into());
75        self
76    }
77}
78
79///
80/// IcrcAccountTransactionCacheRequest
81///
82/// Stable account-history cache identity independent of page and view options.
83///
84
85#[derive(Clone, Debug, Eq, PartialEq)]
86pub struct IcrcAccountTransactionCacheRequest {
87    /// Root directory containing the shared cache.
88    pub cache_root: PathBuf,
89    /// IC API endpoint whose indexed history is cached.
90    pub source_endpoint: String,
91    /// Ledger canister whose account history is cached.
92    pub ledger_canister_id: String,
93    /// Account owner principal.
94    pub account_owner: String,
95    /// Optional normalized 32-byte subaccount hex.
96    pub subaccount_hex: Option<String>,
97}
98
99impl IcrcAccountTransactionCacheRequest {
100    /// Constructs a cache identity for the default subaccount.
101    #[must_use]
102    pub fn new(
103        cache_root: impl Into<PathBuf>,
104        source_endpoint: impl Into<String>,
105        ledger_canister_id: impl Into<String>,
106        account_owner: impl Into<String>,
107    ) -> Self {
108        Self {
109            cache_root: cache_root.into(),
110            source_endpoint: source_endpoint.into(),
111            ledger_canister_id: ledger_canister_id.into(),
112            account_owner: account_owner.into(),
113            subaccount_hex: None,
114        }
115    }
116
117    /// Selects a 32-byte ICRC subaccount encoded as hex.
118    #[must_use]
119    pub fn with_subaccount_hex(mut self, subaccount_hex: impl Into<String>) -> Self {
120        self.subaccount_hex = Some(subaccount_hex.into());
121        self
122    }
123}
124
125///
126/// IcrcAccountTransactionRefreshRequest
127///
128/// Request for a forced complete account-history refresh.
129///
130
131#[derive(Clone, Debug, Eq, PartialEq)]
132pub struct IcrcAccountTransactionRefreshRequest {
133    /// Stable cache identity.
134    pub cache: IcrcAccountTransactionCacheRequest,
135    /// Collection start time as Unix seconds.
136    pub now_unix_secs: u64,
137    /// Optional explicit index canister; otherwise ICRC-106 discovery is used.
138    pub index_canister_id: Option<String>,
139    /// Maximum transactions requested per index page.
140    pub page_size: u32,
141    /// Optional diagnostic bound that fails rather than publishing a partial cache.
142    pub max_pages: Option<u32>,
143    /// Age after which an abandoned refresh lock is reported as stale.
144    pub lock_stale_after_seconds: u64,
145}
146
147impl IcrcAccountTransactionRefreshRequest {
148    /// Constructs a complete refresh request.
149    #[must_use]
150    pub const fn new(
151        cache: IcrcAccountTransactionCacheRequest,
152        now_unix_secs: u64,
153        page_size: u32,
154        lock_stale_after_seconds: u64,
155    ) -> Self {
156        Self {
157            cache,
158            now_unix_secs,
159            index_canister_id: None,
160            page_size,
161            max_pages: None,
162            lock_stale_after_seconds,
163        }
164    }
165
166    /// Uses an explicit index canister instead of ICRC-106 discovery.
167    #[must_use]
168    pub fn with_index_canister_id(mut self, index_canister_id: impl Into<String>) -> Self {
169        self.index_canister_id = Some(index_canister_id.into());
170        self
171    }
172
173    /// Bounds pages for diagnostics; reaching the bound never publishes a cache.
174    #[must_use]
175    pub const fn with_max_pages(mut self, max_pages: Option<u32>) -> Self {
176        self.max_pages = max_pages;
177        self
178    }
179}
180
181///
182/// IcrcAccountTransactionSort
183///
184/// Supported cached account-history ordering.
185///
186
187#[derive(Clone, Copy, Debug, Eq, PartialEq)]
188pub enum IcrcAccountTransactionSort {
189    /// Highest transaction id first.
190    Newest,
191    /// Lowest transaction id first.
192    Oldest,
193}
194
195impl IcrcAccountTransactionSort {
196    /// Stable JSON/text name for this ordering.
197    #[must_use]
198    pub const fn as_str(self) -> &'static str {
199        match self {
200            Self::Newest => "newest",
201            Self::Oldest => "oldest",
202        }
203    }
204}
205
206///
207/// IcrcAccountTransactionListRequest
208///
209/// Cache-only account-history list view.
210///
211
212#[derive(Clone, Debug, Eq, PartialEq)]
213pub struct IcrcAccountTransactionListRequest {
214    /// Stable cache identity.
215    pub cache: IcrcAccountTransactionCacheRequest,
216    /// Maximum cached rows returned by this view.
217    pub limit: u32,
218    /// Requested cached-row ordering.
219    pub sort: IcrcAccountTransactionSort,
220}
221
222impl IcrcAccountTransactionListRequest {
223    /// Constructs a newest-first cached list view.
224    #[must_use]
225    pub const fn new(cache: IcrcAccountTransactionCacheRequest, limit: u32) -> Self {
226        Self {
227            cache,
228            limit,
229            sort: IcrcAccountTransactionSort::Newest,
230        }
231    }
232
233    /// Selects cached-row ordering.
234    #[must_use]
235    pub const fn with_sort(mut self, sort: IcrcAccountTransactionSort) -> Self {
236        self.sort = sort;
237        self
238    }
239}