Skip to main content

icrc3_macros/
lib.rs

1//! Module for managing ICRC3 state in Internet Computer canisters.
2//!
3//! This module provides macros for creating thread-safe ICRC3 state management in canisters,
4//! with functions for initialization and direct access to ICRC3 interface methods.
5
6/// A macro that generates thread-safe ICRC3 state management functions.
7///
8/// This macro creates a set of functions for managing ICRC3 state in a thread-safe manner.
9/// It provides direct access to all ICRC3 interface methods.
10///
11/// # Generated Functions
12/// * `init_icrc3()` - Initializes the ICRC3 state
13/// * `add_transaction(transaction: T) -> Result<u64, Icrc3Error>` - Adds a new transaction
14/// * `icrc3_get_archives() -> Vec<ICRC3ArchiveInfo>` - Gets information about archives
15/// * `icrc3_get_blocks(args: Vec<GetBlocksRequest>) -> Response` - Gets blocks
16/// * `icrc3_get_properties() -> Response` - Gets blockchain properties
17/// * `icrc3_get_tip_certificate() -> ICRC3DataCertificate` - Gets the tip certificate
18/// * `icrc3_supported_block_types() -> Vec<SupportedBlockType>` - Gets supported block types
19/// * `upgrade_archive_wasm(wasm_module: Vec<u8>)` - Upgrades the archive canister WASM
20///
21/// # Example
22/// ```
23/// use icrc3_library::icrc3_macros::icrc3_state;
24///
25/// icrc3_state!();
26///
27/// async fn add_transaction(transaction: MyTransaction) -> Result<u64, Icrc3Error> {
28///     add_transaction(transaction).await
29/// }
30///
31/// fn get_archives() -> Vec<ICRC3ArchiveInfo> {
32///     icrc3_get_archives()
33/// }
34/// ```
35///
36///
37// icrc3_macros/src/lib.rs
38extern 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 icrc3::{config::{ICRC3Config, ICRC3Properties}, icrc3::ICRC3, interface::ICRC3Interface, types::Icrc3Error};
51
52        lazy_static! {
53            pub static ref ICRC3_INSTANCE: Arc<RwLock<Option<ICRC3>>> = Arc::new(RwLock::new(None));
54        }
55
56        const __ICRC3_NOT_INITIALIZED: &str = "ICRC3 state has not been initialized";
57
58        pub fn init_icrc3(config: ICRC3Config) {
59            let mut lock = ICRC3_INSTANCE.write().unwrap();
60            *lock = Some(ICRC3::new(config));
61        }
62
63        pub fn is_initialized() -> bool {
64            let lock = ICRC3_INSTANCE.read().unwrap();
65            lock.is_some()
66        }
67
68        pub fn take_icrc3() -> Option<ICRC3> {
69            let mut lock = ICRC3_INSTANCE.write().unwrap();
70            lock.take()
71        }
72
73        pub fn replace_icrc3(icrc3: ICRC3) {
74            let mut lock = ICRC3_INSTANCE.write().unwrap();
75            *lock = Some(icrc3);
76        }
77
78        pub async fn icrc3_add_transaction<T: TransactionType>(
79            transaction: T,
80        ) -> Result<u64, Icrc3Error> {
81            let mut lock = ICRC3_INSTANCE.write().unwrap();
82            let icrc3 = lock.as_mut().expect(__ICRC3_NOT_INITIALIZED);
83            <ICRC3 as ICRC3Interface<T>>::add_transaction(icrc3, transaction).await
84        }
85
86        pub fn icrc3_get_archives<T: TransactionType>() -> Vec<ICRC3ArchiveInfo> {
87            let lock = ICRC3_INSTANCE.read().unwrap();
88            let icrc3 = lock.as_ref().expect(__ICRC3_NOT_INITIALIZED);
89            <ICRC3 as ICRC3Interface<T>>::icrc3_get_archives(&icrc3)
90        }
91
92        pub async fn icrc3_get_blocks<T: TransactionType>(
93            args: Vec<GetBlocksRequest>,
94        ) -> GetBlocksResult {
95            let lock = ICRC3_INSTANCE.read().unwrap();
96            let icrc3 = lock.as_ref().expect(__ICRC3_NOT_INITIALIZED);
97            <ICRC3 as ICRC3Interface<T>>::icrc3_get_blocks(icrc3, args).await
98        }
99
100        pub fn icrc3_get_properties<T: TransactionType>() -> ICRC3Properties {
101            let lock = ICRC3_INSTANCE.read().unwrap();
102            let icrc3 = lock.as_ref().expect(__ICRC3_NOT_INITIALIZED);
103            <ICRC3 as ICRC3Interface<T>>::icrc3_get_properties(&icrc3)
104        }
105
106        pub fn icrc3_get_tip_certificate<T: TransactionType>() -> ICRC3DataCertificate {
107            let lock = ICRC3_INSTANCE.read().unwrap();
108            let icrc3 = lock.as_ref().expect(__ICRC3_NOT_INITIALIZED);
109            <ICRC3 as ICRC3Interface<T>>::icrc3_get_tip_certificate(icrc3)
110        }
111
112        pub fn icrc3_supported_block_types<T: TransactionType>() -> Vec<SupportedBlockType> {
113            let lock = ICRC3_INSTANCE.read().unwrap();
114            let icrc3 = lock.as_ref().expect(__ICRC3_NOT_INITIALIZED);
115            <ICRC3 as ICRC3Interface<T>>::icrc3_supported_block_types(icrc3)
116        }
117    };
118
119    expanded.into()
120}