bity_ic_icrc3_macros/
lib.rs1extern crate proc_macro;
39
40use proc_macro::TokenStream;
41use quote::quote;
42
43#[proc_macro]
44pub fn icrc3_state(_input: TokenStream) -> TokenStream {
45 let expanded = quote! {
46 use lazy_static::lazy_static;
47 use std::sync::{Arc, RwLock};
48 use icrc_ledger_types::icrc3::blocks::{GetBlocksResult, GetBlocksRequest, ICRC3DataCertificate, SupportedBlockType};
49 use icrc_ledger_types::icrc3::archive::ICRC3ArchiveInfo;
50 use bity_ic_icrc3::{config::{ICRC3Config, ICRC3Properties}, icrc3::ICRC3, interface::ICRC3Interface, types::Icrc3Error};
51 use bity_ic_canister_time::{run_interval, MINUTE_IN_MS, HOUR_IN_MS};
52 use std::time::Duration;
53
54 lazy_static! {
55 pub static ref ICRC3_INSTANCE: Arc<RwLock<Option<ICRC3>>> = Arc::new(RwLock::new(None));
56 }
57
58 const __ICRC3_NOT_INITIALIZED: &str = "ICRC3 state has not been initialized";
59
60 pub fn init_icrc3(config: ICRC3Config) {
61 let mut lock = ICRC3_INSTANCE.write().unwrap();
62 *lock = Some(ICRC3::new(config));
63 }
64
65 pub fn is_initialized() -> bool {
66 let lock = ICRC3_INSTANCE.read().unwrap();
67 lock.is_some()
68 }
69
70 pub fn take_icrc3() -> Option<ICRC3> {
71 let mut lock = ICRC3_INSTANCE.write().unwrap();
72 lock.take()
73 }
74
75 pub fn replace_icrc3(icrc3: ICRC3) {
76 let mut lock = ICRC3_INSTANCE.write().unwrap();
77 *lock = Some(icrc3);
78 }
79
80 pub fn icrc3_add_transaction<T: TransactionType>(
81 transaction: T,
82 ) -> Result<u64, Icrc3Error> {
83 let mut lock = ICRC3_INSTANCE.write().unwrap();
84 let icrc3 = lock.as_mut().expect(__ICRC3_NOT_INITIALIZED);
85 <ICRC3 as ICRC3Interface>::add_transaction(icrc3, transaction)
86 }
87
88 pub fn icrc3_prepare_transaction<T: TransactionType>(
89 transaction: T,
90 ) -> Result<bity_ic_icrc3::types::prepare_transaction::PreparedTransaction, Icrc3Error> {
91 let mut lock = ICRC3_INSTANCE.write().unwrap();
92 let icrc3 = lock.as_mut().expect(__ICRC3_NOT_INITIALIZED);
93 <ICRC3 as ICRC3Interface>::prepare_transaction(icrc3, transaction)
94 }
95
96 pub fn icrc3_commit_prepared_transaction<T: TransactionType>(
97 transaction: T,
98 timestamp: u128,
99 ) -> Result<u64, Icrc3Error> {
100 let mut lock = ICRC3_INSTANCE.write().unwrap();
101 let icrc3 = lock.as_mut().expect(__ICRC3_NOT_INITIALIZED);
102 <ICRC3 as ICRC3Interface>::commit_prepared_transaction(icrc3, transaction, timestamp)
103 }
104
105 pub fn icrc3_get_archives() -> Vec<ICRC3ArchiveInfo> {
106 let lock = ICRC3_INSTANCE.read().unwrap();
107 let icrc3 = lock.as_ref().expect(__ICRC3_NOT_INITIALIZED);
108 <ICRC3 as ICRC3Interface>::icrc3_get_archives(icrc3)
109 }
110
111 pub fn icrc3_get_blocks(
112 args: Vec<GetBlocksRequest>,
113 ) -> GetBlocksResult {
114 let lock = ICRC3_INSTANCE.read().unwrap();
115 let icrc3 = lock.as_ref().expect(__ICRC3_NOT_INITIALIZED);
116 <ICRC3 as ICRC3Interface>::icrc3_get_blocks(icrc3, args)
117 }
118
119 pub fn icrc3_get_properties() -> ICRC3Properties {
120 let lock = ICRC3_INSTANCE.read().unwrap();
121 let icrc3 = lock.as_ref().expect(__ICRC3_NOT_INITIALIZED);
122 <ICRC3 as ICRC3Interface>::icrc3_get_properties(icrc3)
123 }
124
125 pub fn icrc3_get_tip_certificate() -> ICRC3DataCertificate {
126 let lock = ICRC3_INSTANCE.read().unwrap();
127 let icrc3 = lock.as_ref().expect(__ICRC3_NOT_INITIALIZED);
128 <ICRC3 as ICRC3Interface>::icrc3_get_tip_certificate(icrc3)
129 }
130
131 pub fn icrc3_supported_block_types() -> Vec<SupportedBlockType> {
132 let lock = ICRC3_INSTANCE.read().unwrap();
133 let icrc3 = lock.as_ref().expect(__ICRC3_NOT_INITIALIZED);
134 <ICRC3 as ICRC3Interface>::icrc3_supported_block_types(icrc3)
135 }
136
137 pub fn start_archive_job(interval_ms: u64) {
138 run_interval(Duration::from_millis(interval_ms), || {
139 ic_cdk::futures::spawn(async {
140 match ICRC3_INSTANCE.write() {
141 Ok(mut lock) => {
142 if let Some(icrc3) = lock.as_mut() {
143 if let Err(e) = icrc3.archive_job().await {
144 bity_ic_icrc3::utils::trace(format!("Archive job failed: {}", e));
145 } else {
146 bity_ic_icrc3::utils::trace(format!("Archive job completed successfully"));
147 }
148 } else {
149 bity_ic_icrc3::utils::trace("ICRC3 instance not initialized");
150 }
151 },
152 Err(e) => {
153 bity_ic_icrc3::utils::trace(format!("Failed to acquire ICRC3 lock: {}", e));
154 }
155 }
156 });
157 });
158 }
159
160 pub fn start_cleanup_job(interval_ms: u64) {
161 run_interval(Duration::from_millis(interval_ms), || {
162 ic_cdk::futures::spawn(async {
163 match ICRC3_INSTANCE.write() {
164 Ok(mut lock) => {
165 if let Some(icrc3) = lock.as_mut() {
166 if let Err(e) = icrc3.cleanup_job() {
167 bity_ic_icrc3::utils::trace(format!("Cleanup job failed: {}", e));
168 } else {
169 bity_ic_icrc3::utils::trace(format!("Cleanup job completed successfully"));
170 }
171 } else {
172 bity_ic_icrc3::utils::trace("ICRC3 instance not initialized");
173 }
174 },
175 Err(e) => {
176 bity_ic_icrc3::utils::trace(format!("Failed to acquire ICRC3 lock: {}", e));
177 }
178 }
179 });
180 });
181 }
182
183 pub fn start_default_archive_job() {
185 start_archive_job(10 * MINUTE_IN_MS);
186 start_cleanup_job(1 * HOUR_IN_MS);
187 }
188 };
189
190 expanded.into()
191}