fedimint_mint_client/
api.rs1use fedimint_api_client::api::{FederationApiExt, FederationResult, IModuleFederationApi};
2use fedimint_core::bitcoin::hashes::sha256;
3use fedimint_core::module::registry::ModuleRegistry;
4use fedimint_core::module::{ApiRequestErased, SerdeModuleEncodingBase64};
5use fedimint_core::task::{MaybeSend, MaybeSync};
6use fedimint_core::{OutPoint, PeerId, apply, async_trait_maybe_send};
7use fedimint_mint_common::endpoint_constants::{
8 BLIND_NONCE_USED_ENDPOINT, NOTE_SPENT_ENDPOINT, RECOVERY_BLIND_NONCE_OUTPOINTS_ENDPOINT,
9 RECOVERY_COUNT_ENDPOINT, RECOVERY_SLICE_ENDPOINT, RECOVERY_SLICE_HASH_ENDPOINT,
10};
11use fedimint_mint_common::{BlindNonce, Nonce, RecoveryItem};
12
13#[apply(async_trait_maybe_send!)]
14pub trait MintFederationApi {
15 async fn check_blind_nonce_used(&self, blind_nonce: BlindNonce) -> FederationResult<bool>;
16
17 async fn check_note_spent(&self, nonce: Nonce) -> FederationResult<bool>;
18
19 async fn check_blind_nonce_used_single_peer(
25 &self,
26 peer: PeerId,
27 blind_nonce: BlindNonce,
28 ) -> anyhow::Result<bool>;
29
30 async fn check_note_spent_single_peer(
36 &self,
37 peer: PeerId,
38 nonce: Nonce,
39 ) -> anyhow::Result<bool>;
40
41 async fn fetch_recovery_count(&self) -> anyhow::Result<u64>;
43
44 async fn fetch_recovery_slice_hash(&self, start: u64, end: u64) -> sha256::Hash;
47
48 async fn fetch_recovery_slice(
50 &self,
51 peer: PeerId,
52 start: u64,
53 end: u64,
54 ) -> anyhow::Result<Vec<RecoveryItem>>;
55
56 async fn fetch_blind_nonce_outpoints(
58 &self,
59 blind_nonces: Vec<BlindNonce>,
60 ) -> anyhow::Result<Vec<OutPoint>>;
61}
62
63#[apply(async_trait_maybe_send!)]
64impl<T: ?Sized> MintFederationApi for T
65where
66 T: IModuleFederationApi + MaybeSend + MaybeSync + 'static,
67{
68 async fn check_blind_nonce_used(&self, blind_nonce: BlindNonce) -> FederationResult<bool> {
69 self.request_current_consensus(
70 BLIND_NONCE_USED_ENDPOINT.to_string(),
71 ApiRequestErased::new(blind_nonce),
72 )
73 .await
74 }
75
76 async fn check_note_spent(&self, nonce: Nonce) -> FederationResult<bool> {
77 self.request_current_consensus(
78 NOTE_SPENT_ENDPOINT.to_string(),
79 ApiRequestErased::new(nonce),
80 )
81 .await
82 }
83
84 async fn check_blind_nonce_used_single_peer(
85 &self,
86 peer: PeerId,
87 blind_nonce: BlindNonce,
88 ) -> anyhow::Result<bool> {
89 Ok(self
90 .request_single_peer::<bool>(
91 BLIND_NONCE_USED_ENDPOINT.to_string(),
92 ApiRequestErased::new(blind_nonce),
93 peer,
94 )
95 .await?)
96 }
97
98 async fn check_note_spent_single_peer(
99 &self,
100 peer: PeerId,
101 nonce: Nonce,
102 ) -> anyhow::Result<bool> {
103 Ok(self
104 .request_single_peer::<bool>(
105 NOTE_SPENT_ENDPOINT.to_string(),
106 ApiRequestErased::new(nonce),
107 peer,
108 )
109 .await?)
110 }
111
112 async fn fetch_recovery_count(&self) -> anyhow::Result<u64> {
113 self.request_current_consensus::<u64>(
114 RECOVERY_COUNT_ENDPOINT.to_string(),
115 ApiRequestErased::default(),
116 )
117 .await
118 .map_err(|e| anyhow::anyhow!("{e}"))
119 }
120
121 async fn fetch_recovery_slice_hash(&self, start: u64, end: u64) -> sha256::Hash {
122 self.request_current_consensus_retry(
123 RECOVERY_SLICE_HASH_ENDPOINT.to_owned(),
124 ApiRequestErased::new((start, end)),
125 )
126 .await
127 }
128
129 async fn fetch_recovery_slice(
130 &self,
131 peer: PeerId,
132 start: u64,
133 end: u64,
134 ) -> anyhow::Result<Vec<RecoveryItem>> {
135 let result = self
136 .request_single_peer::<SerdeModuleEncodingBase64<Vec<RecoveryItem>>>(
137 RECOVERY_SLICE_ENDPOINT.to_owned(),
138 ApiRequestErased::new((start, end)),
139 peer,
140 )
141 .await?;
142
143 Ok(result.try_into_inner(&ModuleRegistry::default())?)
144 }
145
146 async fn fetch_blind_nonce_outpoints(
147 &self,
148 blind_nonces: Vec<BlindNonce>,
149 ) -> anyhow::Result<Vec<OutPoint>> {
150 self.request_current_consensus::<Vec<OutPoint>>(
151 RECOVERY_BLIND_NONCE_OUTPOINTS_ENDPOINT.to_string(),
152 ApiRequestErased::new(blind_nonces),
153 )
154 .await
155 .map_err(|e| anyhow::anyhow!("{e}"))
156 }
157}