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