fedimint-mint-client 0.12.0-beta.2

fedimint-mint is a chaumian ecash mint module.
Documentation
use std::time::Duration;

use fedimint_client::OperationId;
use fedimint_core::util::ffi::UniffiError;
use fedimint_core::{Amount, runtime};
use futures::StreamExt;

use crate::{
    MintClientModule, OOBNotes, ReissueExternalNotesState, SelectNotesWithAtleastAmount,
    SelectNotesWithExactAmount, SpendOOBRefund, SpendOOBState,
};

type Result<T> = std::result::Result<T, UniffiError>;

#[derive(Debug, Clone)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct NoteDenominationCount {
    pub amount: Amount,
    pub count: u64,
}

#[derive(Debug, Clone, uniffi::Record)]
pub struct SpendNotesResponse {
    pub operation_id: OperationId,
    pub oob_notes: OOBNotes,
}

#[cfg_attr(feature = "uniffi", uniffi::export(async_runtime = "tokio"))]
impl MintClientModule {
    #[uniffi::method(name = "reissue_notes")]
    pub async fn reissue_notes_uniffi(
        &self,
        oob_notes: OOBNotes,
        extra_meta: String,
    ) -> Result<OperationId> {
        let extra_meta = if extra_meta.trim().is_empty() {
            serde_json::Value::Null
        } else {
            serde_json::from_str(&extra_meta)?
        };
        let operation_id = self.reissue_external_notes(oob_notes, extra_meta).await?;
        Ok(operation_id)
    }

    #[uniffi::method(name = "subscribe_reissue_external_notes")]
    pub async fn subscribe_reissue_external_notes_uniffi(
        &self,
        operation_id: OperationId,
        callback: Box<dyn ReissueNotesStateCallback>,
    ) -> Result<()> {
        let client_ctx = self.client_ctx.clone();
        let mint = client_ctx.self_ref();
        let updates = mint.subscribe_reissue_external_notes(operation_id).await?;
        runtime::spawn("uniffi-subscribe-reissue-external-notes", async move {
            let mut stream = updates.into_stream();
            while let Some(state) = stream.next().await {
                callback.on_state(operation_id, state);
            }
        });
        Ok(())
    }

    #[uniffi::method(name = "spend_notes")]
    pub async fn spend_notes_uniffi(
        &self,
        amount: Amount,
        try_cancel_after_secs: Option<u64>,
    ) -> Result<SpendNotesResponse> {
        let (operation_id, oob_notes) = self
            .spend_notes_with_selector(
                &SelectNotesWithExactAmount,
                amount,
                try_cancel_after_secs.map(Duration::from_secs),
                false,
                serde_json::Value::Null,
            )
            .await?;
        Ok(SpendNotesResponse {
            operation_id,
            oob_notes,
        })
    }

    pub async fn spend_notes_expert(
        &self,
        amount: Amount,
        try_cancel_after_secs: Option<u64>,
    ) -> Result<SpendNotesResponse> {
        let (operation_id, oob_notes) = self
            .spend_notes_with_selector(
                &SelectNotesWithAtleastAmount,
                amount,
                try_cancel_after_secs.map(Duration::from_secs),
                false,
                serde_json::Value::Null,
            )
            .await?;
        Ok(SpendNotesResponse {
            operation_id,
            oob_notes,
        })
    }

    #[uniffi::method(name = "validate_notes")]
    pub fn validate_notes_uniffi(&self, oob_notes: &OOBNotes) -> Result<Amount> {
        Ok(self.validate_notes(oob_notes)?)
    }

    #[uniffi::method(name = "try_cancel_spend_notes")]
    pub async fn try_cancel_spend_notes_uniffi(&self, operation_id: OperationId) {
        self.try_cancel_spend_notes(operation_id).await;
    }

    #[uniffi::method(name = "subscribe_spend_notes")]
    pub async fn subscribe_spend_notes_uniffi(
        &self,
        operation_id: OperationId,
        callback: Box<dyn SpendNotesStateCallback>,
    ) -> Result<()> {
        let client_ctx = self.client_ctx.clone();
        let mint = client_ctx.self_ref();
        let updates = mint.subscribe_spend_notes(operation_id).await?;
        runtime::spawn("uniffi-subscribe-spend-notes", async move {
            let mut stream = updates.into_stream();
            while let Some(state) = stream.next().await {
                callback.on_state(operation_id, state);
            }
        });
        Ok(())
    }

    #[uniffi::method(name = "await_spend_oob_refund")]
    pub async fn await_spend_oob_refund_uniffi(&self, operation_id: OperationId) -> SpendOOBRefund {
        self.await_spend_oob_refund(operation_id).await
    }

    #[uniffi::method(name = "get_note_counts_by_denomination")]
    pub async fn get_note_counts_by_denomination_uniffi(
        &self,
    ) -> Result<Vec<NoteDenominationCount>> {
        let mut dbtx = self.client_ctx.module_db().begin_transaction_nc().await;
        let note_counts = self.get_note_counts_by_denomination(&mut dbtx).await;
        Ok(note_counts
            .iter()
            .map(|(amount, count)| NoteDenominationCount {
                amount,
                count: count as u64,
            })
            .collect())
    }
}

#[cfg(feature = "uniffi")]
#[uniffi::export(callback_interface)]
pub trait ReissueNotesStateCallback: Send + Sync {
    fn on_state(&self, operation_id: OperationId, state: ReissueExternalNotesState);
}

#[cfg(feature = "uniffi")]
#[uniffi::export(callback_interface)]
pub trait SpendNotesStateCallback: Send + Sync {
    fn on_state(&self, operation_id: OperationId, state: SpendOOBState);
}