fedimint_mint_client/
api.rs

1use 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    /// Returns the total number of recovery items stored on the federation.
20    async fn fetch_recovery_count(&self) -> anyhow::Result<u64>;
21
22    /// Returns the consensus hash of recovery items in the range `[start,
23    /// end)`.
24    async fn fetch_recovery_slice_hash(&self, start: u64, end: u64) -> sha256::Hash;
25
26    /// Fetches recovery items in the range `[start, end)` from a specific peer.
27    async fn fetch_recovery_slice(
28        &self,
29        peer: PeerId,
30        start: u64,
31        end: u64,
32    ) -> anyhow::Result<Vec<RecoveryItem>>;
33
34    /// Returns the outpoints where the given blind nonces were used.
35    async fn fetch_blind_nonce_outpoints(
36        &self,
37        blind_nonces: Vec<BlindNonce>,
38    ) -> anyhow::Result<Vec<OutPoint>>;
39}
40
41#[apply(async_trait_maybe_send!)]
42impl<T: ?Sized> MintFederationApi for T
43where
44    T: IModuleFederationApi + MaybeSend + MaybeSync + 'static,
45{
46    async fn check_blind_nonce_used(&self, blind_nonce: BlindNonce) -> FederationResult<bool> {
47        self.request_current_consensus(
48            BLIND_NONCE_USED_ENDPOINT.to_string(),
49            ApiRequestErased::new(blind_nonce),
50        )
51        .await
52    }
53
54    async fn check_note_spent(&self, nonce: Nonce) -> FederationResult<bool> {
55        self.request_current_consensus(
56            NOTE_SPENT_ENDPOINT.to_string(),
57            ApiRequestErased::new(nonce),
58        )
59        .await
60    }
61
62    async fn fetch_recovery_count(&self) -> anyhow::Result<u64> {
63        self.request_current_consensus::<u64>(
64            RECOVERY_COUNT_ENDPOINT.to_string(),
65            ApiRequestErased::default(),
66        )
67        .await
68        .map_err(|e| anyhow::anyhow!("{e}"))
69    }
70
71    async fn fetch_recovery_slice_hash(&self, start: u64, end: u64) -> sha256::Hash {
72        self.request_current_consensus_retry(
73            RECOVERY_SLICE_HASH_ENDPOINT.to_owned(),
74            ApiRequestErased::new((start, end)),
75        )
76        .await
77    }
78
79    async fn fetch_recovery_slice(
80        &self,
81        peer: PeerId,
82        start: u64,
83        end: u64,
84    ) -> anyhow::Result<Vec<RecoveryItem>> {
85        let result = self
86            .request_single_peer::<SerdeModuleEncodingBase64<Vec<RecoveryItem>>>(
87                RECOVERY_SLICE_ENDPOINT.to_owned(),
88                ApiRequestErased::new((start, end)),
89                peer,
90            )
91            .await?;
92
93        Ok(result.try_into_inner(&ModuleRegistry::default())?)
94    }
95
96    async fn fetch_blind_nonce_outpoints(
97        &self,
98        blind_nonces: Vec<BlindNonce>,
99    ) -> anyhow::Result<Vec<OutPoint>> {
100        self.request_current_consensus::<Vec<OutPoint>>(
101            RECOVERY_BLIND_NONCE_OUTPOINTS_ENDPOINT.to_string(),
102            ApiRequestErased::new(blind_nonces),
103        )
104        .await
105        .map_err(|e| anyhow::anyhow!("{e}"))
106    }
107}