Update FFI Database Objects to Records (#1149)

This commit is contained in:
David Caseria
2025-10-24 12:24:06 -05:00
committed by GitHub
parent 33c206a310
commit 344b81a694
12 changed files with 194 additions and 234 deletions

View File

@@ -450,7 +450,9 @@ impl CdkWalletDatabase for WalletDatabaseBridge {
.into_iter()
.map(|info| {
Ok(cdk::types::ProofInfo {
proof: info.proof.inner.clone(),
proof: info.proof.try_into().map_err(|e: FfiError| {
cdk::cdk_database::Error::Database(e.to_string().into())
})?,
y: info.y.try_into().map_err(|e: FfiError| {
cdk::cdk_database::Error::Database(e.to_string().into())
})?,

View File

@@ -175,10 +175,7 @@ impl MultiMintWallet {
let proofs = self.inner.list_proofs().await?;
let mut proofs_by_mint = HashMap::new();
for (mint_url, mint_proofs) in proofs {
let ffi_proofs: Vec<Arc<Proof>> = mint_proofs
.into_iter()
.map(|p| Arc::new(p.into()))
.collect();
let ffi_proofs: Vec<Proof> = mint_proofs.into_iter().map(|p| p.into()).collect();
proofs_by_mint.insert(mint_url.to_string(), ffi_proofs);
}
Ok(proofs_by_mint)
@@ -262,7 +259,7 @@ impl MultiMintWallet {
.inner
.mint(&cdk_mint_url, &quote_id, conditions)
.await?;
Ok(proofs.into_iter().map(|p| Arc::new(p.into())).collect())
Ok(proofs.into_iter().map(|p| p.into()).collect())
}
/// Wait for a mint quote to be paid and automatically mint the proofs
@@ -288,7 +285,7 @@ impl MultiMintWallet {
timeout_secs,
)
.await?;
Ok(proofs.into_iter().map(|p| Arc::new(p.into())).collect())
Ok(proofs.into_iter().map(|p| p.into()).collect())
}
/// Get a melt quote from a specific mint
@@ -346,7 +343,7 @@ impl MultiMintWallet {
let result = self.inner.swap(amount.map(Into::into), conditions).await?;
Ok(result.map(|proofs| proofs.into_iter().map(|p| Arc::new(p.into())).collect()))
Ok(result.map(|proofs| proofs.into_iter().map(|p| p.into()).collect()))
}
/// List transactions from all mints
@@ -437,7 +434,7 @@ impl MultiMintWallet {
.inner
.mint_blind_auth(&cdk_mint_url, amount.into())
.await?;
Ok(proofs.into_iter().map(|p| Arc::new(p.into())).collect())
Ok(proofs.into_iter().map(|p| p.into()).collect())
}
/// Get unspent auth proofs for a specific mint
@@ -556,4 +553,4 @@ impl From<MultiMintSendOptions> for CdkMultiMintSendOptions {
pub type BalanceMap = HashMap<String, Amount>;
/// Type alias for proofs by mint URL
pub type ProofsByMint = HashMap<String, Vec<Arc<Proof>>>;
pub type ProofsByMint = HashMap<String, Vec<Proof>>;

View File

@@ -237,7 +237,7 @@ impl WalletDatabase for WalletPostgresDatabase {
.into_iter()
.map(|info| {
Ok::<cdk::types::ProofInfo, FfiError>(cdk::types::ProofInfo {
proof: info.proof.inner.clone(),
proof: info.proof.try_into()?,
y: info.y.try_into()?,
mint_url: info.mint_url.try_into()?,
state: info.state.into(),

View File

@@ -272,7 +272,7 @@ impl WalletDatabase for WalletSqliteDatabase {
.into_iter()
.map(|info| {
Ok::<cdk::types::ProofInfo, FfiError>(cdk::types::ProofInfo {
proof: info.proof.inner.clone(),
proof: info.proof.try_into()?,
y: info.y.try_into()?,
mint_url: info.mint_url.try_into()?,
state: info.state.into(),

View File

@@ -75,10 +75,7 @@ impl Token {
// For now, return empty keysets to get all proofs
let empty_keysets = vec![];
let proofs = self.inner.proofs(&empty_keysets)?;
Ok(proofs
.into_iter()
.map(|p| std::sync::Arc::new(p.into()))
.collect())
Ok(proofs.into_iter().map(|p| p.into()).collect())
}
/// Convert token to raw bytes

View File

@@ -44,78 +44,126 @@ impl From<ProofState> for CdkState {
}
/// FFI-compatible Proof
#[derive(Debug, uniffi::Object)]
#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
pub struct Proof {
pub(crate) inner: cdk::nuts::Proof,
/// Proof amount
pub amount: Amount,
/// Secret (as string)
pub secret: String,
/// Unblinded signature C (as hex string)
pub c: String,
/// Keyset ID (as hex string)
pub keyset_id: String,
/// Optional witness
pub witness: Option<Witness>,
/// Optional DLEQ proof
pub dleq: Option<ProofDleq>,
}
impl From<cdk::nuts::Proof> for Proof {
fn from(proof: cdk::nuts::Proof) -> Self {
Self { inner: proof }
Self {
amount: proof.amount.into(),
secret: proof.secret.to_string(),
c: proof.c.to_string(),
keyset_id: proof.keyset_id.to_string(),
witness: proof.witness.map(|w| w.into()),
dleq: proof.dleq.map(|d| d.into()),
}
}
}
impl From<Proof> for cdk::nuts::Proof {
fn from(proof: Proof) -> Self {
proof.inner
}
}
impl TryFrom<Proof> for cdk::nuts::Proof {
type Error = FfiError;
#[uniffi::export]
impl Proof {
/// Get the amount
pub fn amount(&self) -> Amount {
self.inner.amount.into()
}
fn try_from(proof: Proof) -> Result<Self, Self::Error> {
use std::str::FromStr;
/// Get the secret as string
pub fn secret(&self) -> String {
self.inner.secret.to_string()
}
/// Get the unblinded signature (C) as string
pub fn c(&self) -> String {
self.inner.c.to_string()
}
/// Get the keyset ID as string
pub fn keyset_id(&self) -> String {
self.inner.keyset_id.to_string()
}
/// Get the witness
pub fn witness(&self) -> Option<Witness> {
self.inner.witness.as_ref().map(|w| w.clone().into())
}
/// Check if proof is active with given keyset IDs
pub fn is_active(&self, active_keyset_ids: Vec<String>) -> bool {
use cdk::nuts::Id;
let ids: Vec<Id> = active_keyset_ids
.into_iter()
.filter_map(|id| Id::from_str(&id).ok())
.collect();
self.inner.is_active(&ids)
}
/// Get the Y value (hash_to_curve of secret)
pub fn y(&self) -> Result<String, FfiError> {
Ok(self.inner.y()?.to_string())
Ok(Self {
amount: proof.amount.into(),
secret: cdk::secret::Secret::from_str(&proof.secret)
.map_err(|e| FfiError::Serialization { msg: e.to_string() })?,
c: cdk::nuts::PublicKey::from_str(&proof.c)
.map_err(|e| FfiError::InvalidCryptographicKey { msg: e.to_string() })?,
keyset_id: Id::from_str(&proof.keyset_id)
.map_err(|e| FfiError::Serialization { msg: e.to_string() })?,
witness: proof.witness.map(|w| w.into()),
dleq: proof.dleq.map(|d| d.into()),
})
}
}
/// Get the DLEQ proof if present
pub fn dleq(&self) -> Option<ProofDleq> {
self.inner.dleq.as_ref().map(|d| d.clone().into())
}
/// Get the Y value (hash_to_curve of secret) for a proof
#[uniffi::export]
pub fn proof_y(proof: &Proof) -> Result<String, FfiError> {
// Convert to CDK proof to calculate Y
let cdk_proof: cdk::nuts::Proof = proof.clone().try_into()?;
Ok(cdk_proof.y()?.to_string())
}
/// Check if proof has DLEQ proof
pub fn has_dleq(&self) -> bool {
self.inner.dleq.is_some()
/// Check if proof is active with given keyset IDs
#[uniffi::export]
pub fn proof_is_active(proof: &Proof, active_keyset_ids: Vec<String>) -> bool {
use cdk::nuts::Id;
let ids: Vec<Id> = active_keyset_ids
.into_iter()
.filter_map(|id| Id::from_str(&id).ok())
.collect();
// A proof is active if its keyset_id is in the active list
if let Ok(keyset_id) = Id::from_str(&proof.keyset_id) {
ids.contains(&keyset_id)
} else {
false
}
}
/// Check if proof has DLEQ proof
#[uniffi::export]
pub fn proof_has_dleq(proof: &Proof) -> bool {
proof.dleq.is_some()
}
/// Verify HTLC witness on a proof
#[uniffi::export]
pub fn proof_verify_htlc(proof: &Proof) -> Result<(), FfiError> {
let cdk_proof: cdk::nuts::Proof = proof.clone().try_into()?;
cdk_proof
.verify_htlc()
.map_err(|e| FfiError::Generic { msg: e.to_string() })
}
/// Verify DLEQ proof on a proof
#[uniffi::export]
pub fn proof_verify_dleq(
proof: &Proof,
mint_pubkey: super::keys::PublicKey,
) -> Result<(), FfiError> {
let cdk_proof: cdk::nuts::Proof = proof.clone().try_into()?;
let cdk_pubkey: cdk::nuts::PublicKey = mint_pubkey.try_into()?;
cdk_proof
.verify_dleq(cdk_pubkey)
.map_err(|e| FfiError::Generic { msg: e.to_string() })
}
/// Sign a P2PK proof with a secret key, returning a new signed proof
#[uniffi::export]
pub fn proof_sign_p2pk(proof: Proof, secret_key_hex: String) -> Result<Proof, FfiError> {
let mut cdk_proof: cdk::nuts::Proof = proof.try_into()?;
let secret_key = cdk::nuts::SecretKey::from_hex(&secret_key_hex)
.map_err(|e| FfiError::InvalidCryptographicKey { msg: e.to_string() })?;
cdk_proof
.sign_p2pk(secret_key)
.map_err(|e| FfiError::Generic { msg: e.to_string() })?;
Ok(cdk_proof.into())
}
/// FFI-compatible Proofs (vector of Proof)
pub type Proofs = Vec<std::sync::Arc<Proof>>;
pub type Proofs = Vec<Proof>;
/// FFI-compatible DLEQ proof for proofs
#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
@@ -175,9 +223,12 @@ impl From<BlindSignatureDleq> for cdk::nuts::BlindSignatureDleq {
}
}
/// Helper functions for Proofs
/// Helper function to calculate total amount of proofs
#[uniffi::export]
pub fn proofs_total_amount(proofs: &Proofs) -> Result<Amount, FfiError> {
let cdk_proofs: Vec<cdk::nuts::Proof> = proofs.iter().map(|p| p.inner.clone()).collect();
let cdk_proofs: Result<Vec<cdk::nuts::Proof>, _> =
proofs.iter().map(|p| p.clone().try_into()).collect();
let cdk_proofs = cdk_proofs?;
use cdk::nuts::ProofsMethods;
Ok(cdk_proofs.total_amount()?.into())
}
@@ -420,7 +471,7 @@ impl TryFrom<SpendingConditions> for cdk::nuts::SpendingConditions {
#[derive(Debug, Clone, uniffi::Record)]
pub struct ProofInfo {
/// Proof
pub proof: std::sync::Arc<Proof>,
pub proof: Proof,
/// Y value (hash_to_curve of secret)
pub y: super::keys::PublicKey,
/// Mint URL
@@ -436,7 +487,7 @@ pub struct ProofInfo {
impl From<cdk::types::ProofInfo> for ProofInfo {
fn from(info: cdk::types::ProofInfo) -> Self {
Self {
proof: std::sync::Arc::new(info.proof.into()),
proof: info.proof.into(),
y: info.y.into(),
mint_url: info.mint_url.into(),
state: info.state.into(),
@@ -458,7 +509,7 @@ pub fn decode_proof_info(json: String) -> Result<ProofInfo, FfiError> {
pub fn encode_proof_info(info: ProofInfo) -> Result<String, FfiError> {
// Convert to cdk::types::ProofInfo for serialization
let cdk_info = cdk::types::ProofInfo {
proof: info.proof.inner.clone(),
proof: info.proof.try_into()?,
y: info.y.try_into()?,
mint_url: info.mint_url.try_into()?,
state: info.state.into(),

View File

@@ -77,30 +77,25 @@ impl TryFrom<MintQuote> for cdk::wallet::MintQuote {
}
}
impl MintQuote {
/// Get total amount (amount + fees)
pub fn total_amount(&self) -> Amount {
if let Some(amount) = self.amount {
Amount::new(amount.value + self.amount_paid.value - self.amount_issued.value)
} else {
Amount::zero()
}
}
/// Get total amount for a mint quote (amount paid)
#[uniffi::export]
pub fn mint_quote_total_amount(quote: &MintQuote) -> Result<Amount, FfiError> {
let cdk_quote: cdk::wallet::MintQuote = quote.clone().try_into()?;
Ok(cdk_quote.total_amount().into())
}
/// Check if quote is expired
pub fn is_expired(&self, current_time: u64) -> bool {
current_time > self.expiry
}
/// Check if mint quote is expired
#[uniffi::export]
pub fn mint_quote_is_expired(quote: &MintQuote, current_time: u64) -> Result<bool, FfiError> {
let cdk_quote: cdk::wallet::MintQuote = quote.clone().try_into()?;
Ok(cdk_quote.is_expired(current_time))
}
/// Get amount that can be minted
pub fn amount_mintable(&self) -> Amount {
Amount::new(self.amount_paid.value - self.amount_issued.value)
}
/// Convert MintQuote to JSON string
pub fn to_json(&self) -> Result<String, FfiError> {
Ok(serde_json::to_string(self)?)
}
/// Get amount that can be minted from a mint quote
#[uniffi::export]
pub fn mint_quote_amount_mintable(quote: &MintQuote) -> Result<Amount, FfiError> {
let cdk_quote: cdk::wallet::MintQuote = quote.clone().try_into()?;
Ok(cdk_quote.amount_mintable().into())
}
/// Decode MintQuote from JSON string
@@ -117,7 +112,7 @@ pub fn encode_mint_quote(quote: MintQuote) -> Result<String, FfiError> {
}
/// FFI-compatible MintQuoteBolt11Response
#[derive(Debug, uniffi::Object)]
#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
pub struct MintQuoteBolt11Response {
/// Quote ID
pub quote: String,
@@ -149,46 +144,8 @@ impl From<cdk::nuts::MintQuoteBolt11Response<String>> for MintQuoteBolt11Respons
}
}
#[uniffi::export]
impl MintQuoteBolt11Response {
/// Get quote ID
pub fn quote(&self) -> String {
self.quote.clone()
}
/// Get request string
pub fn request(&self) -> String {
self.request.clone()
}
/// Get state
pub fn state(&self) -> QuoteState {
self.state.clone()
}
/// Get expiry
pub fn expiry(&self) -> Option<u64> {
self.expiry
}
/// Get amount
pub fn amount(&self) -> Option<Amount> {
self.amount
}
/// Get unit
pub fn unit(&self) -> Option<CurrencyUnit> {
self.unit.clone()
}
/// Get pubkey
pub fn pubkey(&self) -> Option<String> {
self.pubkey.clone()
}
}
/// FFI-compatible MeltQuoteBolt11Response
#[derive(Debug, uniffi::Object)]
#[derive(Debug, Clone, Serialize, Deserialize, uniffi::Record)]
pub struct MeltQuoteBolt11Response {
/// Quote ID
pub quote: String,
@@ -222,50 +179,6 @@ impl From<cdk::nuts::MeltQuoteBolt11Response<String>> for MeltQuoteBolt11Respons
}
}
}
#[uniffi::export]
impl MeltQuoteBolt11Response {
/// Get quote ID
pub fn quote(&self) -> String {
self.quote.clone()
}
/// Get amount
pub fn amount(&self) -> Amount {
self.amount
}
/// Get fee reserve
pub fn fee_reserve(&self) -> Amount {
self.fee_reserve
}
/// Get state
pub fn state(&self) -> QuoteState {
self.state.clone()
}
/// Get expiry
pub fn expiry(&self) -> u64 {
self.expiry
}
/// Get payment preimage
pub fn payment_preimage(&self) -> Option<String> {
self.payment_preimage.clone()
}
/// Get request
pub fn request(&self) -> Option<String> {
self.request.clone()
}
/// Get unit
pub fn unit(&self) -> Option<CurrencyUnit> {
self.unit.clone()
}
}
/// FFI-compatible PaymentMethod
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum)]
pub enum PaymentMethod {

View File

@@ -139,13 +139,9 @@ pub enum NotificationPayload {
/// Proof state update
ProofState { proof_states: Vec<ProofStateUpdate> },
/// Mint quote update
MintQuoteUpdate {
quote: std::sync::Arc<MintQuoteBolt11Response>,
},
MintQuoteUpdate { quote: MintQuoteBolt11Response },
/// Melt quote update
MeltQuoteUpdate {
quote: std::sync::Arc<MeltQuoteBolt11Response>,
},
MeltQuoteUpdate { quote: MeltQuoteBolt11Response },
}
impl From<MintEvent<String>> for NotificationPayload {
@@ -156,12 +152,12 @@ impl From<MintEvent<String>> for NotificationPayload {
},
cdk::nuts::NotificationPayload::MintQuoteBolt11Response(quote_resp) => {
NotificationPayload::MintQuoteUpdate {
quote: std::sync::Arc::new(quote_resp.into()),
quote: quote_resp.into(),
}
}
cdk::nuts::NotificationPayload::MeltQuoteBolt11Response(quote_resp) => {
NotificationPayload::MeltQuoteUpdate {
quote: std::sync::Arc::new(quote_resp.into()),
quote: quote_resp.into(),
}
}
_ => {

View File

@@ -106,6 +106,21 @@ pub fn encode_transaction(transaction: Transaction) -> Result<String, FfiError>
Ok(serde_json::to_string(&transaction)?)
}
/// Check if a transaction matches the given filter conditions
#[uniffi::export]
pub fn transaction_matches_conditions(
transaction: &Transaction,
mint_url: Option<MintUrl>,
direction: Option<TransactionDirection>,
unit: Option<CurrencyUnit>,
) -> Result<bool, FfiError> {
let cdk_transaction: cdk::wallet::types::Transaction = transaction.clone().try_into()?;
let cdk_mint_url = mint_url.map(|url| url.try_into()).transpose()?;
let cdk_direction = direction.map(Into::into);
let cdk_unit = unit.map(Into::into);
Ok(cdk_transaction.matches_conditions(&cdk_mint_url, &cdk_direction, &cdk_unit))
}
/// FFI-compatible TransactionDirection
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, uniffi::Enum)]
pub enum TransactionDirection {
@@ -163,7 +178,9 @@ impl TransactionId {
/// Create from proofs
pub fn from_proofs(proofs: &Proofs) -> Result<Self, FfiError> {
let cdk_proofs: Vec<cdk::nuts::Proof> = proofs.iter().map(|p| p.inner.clone()).collect();
let cdk_proofs: Result<Vec<cdk::nuts::Proof>, _> =
proofs.iter().map(|p| p.clone().try_into()).collect();
let cdk_proofs = cdk_proofs?;
let id = cdk::wallet::types::TransactionId::from_proofs(cdk_proofs)?;
Ok(Self {
hex: id.to_string(),

View File

@@ -314,7 +314,7 @@ impl From<cdk::wallet::PreparedSend> for PreparedSend {
.proofs()
.iter()
.cloned()
.map(|p| std::sync::Arc::new(p.into()))
.map(|p| p.into())
.collect();
Self {
inner: Mutex::new(Some(prepared)),
@@ -421,12 +421,9 @@ impl From<cdk::types::Melted> for Melted {
Self {
state: melted.state.into(),
preimage: melted.preimage,
change: melted.change.map(|proofs| {
proofs
.into_iter()
.map(|p| std::sync::Arc::new(p.into()))
.collect()
}),
change: melted
.change
.map(|proofs| proofs.into_iter().map(|p| p.into()).collect()),
amount: melted.amount.into(),
fee_paid: melted.fee_paid.into(),
}

View File

@@ -119,8 +119,9 @@ impl Wallet {
options: ReceiveOptions,
memo: Option<String>,
) -> Result<Amount, FfiError> {
let cdk_proofs: Vec<cdk::nuts::Proof> =
proofs.into_iter().map(|p| p.inner.clone()).collect();
let cdk_proofs: Result<Vec<cdk::nuts::Proof>, _> =
proofs.into_iter().map(|p| p.try_into()).collect();
let cdk_proofs = cdk_proofs?;
let amount = self
.inner
@@ -166,10 +167,7 @@ impl Wallet {
.inner
.mint(&quote_id, amount_split_target.into(), conditions)
.await?;
Ok(proofs
.into_iter()
.map(|p| std::sync::Arc::new(p.into()))
.collect())
Ok(proofs.into_iter().map(|p| p.into()).collect())
}
/// Get a melt quote
@@ -222,10 +220,7 @@ impl Wallet {
)
.await?;
Ok(proofs
.into_iter()
.map(|p| std::sync::Arc::new(p.into()))
.collect())
Ok(proofs.into_iter().map(|p| p.into()).collect())
}
/// Get a quote for a bolt12 melt
@@ -248,8 +243,9 @@ impl Wallet {
spending_conditions: Option<SpendingConditions>,
include_fees: bool,
) -> Result<Option<Proofs>, FfiError> {
let cdk_proofs: Vec<cdk::nuts::Proof> =
input_proofs.into_iter().map(|p| p.inner.clone()).collect();
let cdk_proofs: Result<Vec<cdk::nuts::Proof>, _> =
input_proofs.into_iter().map(|p| p.try_into()).collect();
let cdk_proofs = cdk_proofs?;
// Convert spending conditions if provided
let conditions = spending_conditions.map(|sc| sc.try_into()).transpose()?;
@@ -265,12 +261,7 @@ impl Wallet {
)
.await?;
Ok(result.map(|proofs| {
proofs
.into_iter()
.map(|p| std::sync::Arc::new(p.into()))
.collect()
}))
Ok(result.map(|proofs| proofs.into_iter().map(|p| p.into()).collect()))
}
/// Get proofs by states
@@ -291,7 +282,7 @@ impl Wallet {
};
for proof in proofs {
all_proofs.push(std::sync::Arc::new(proof.into()));
all_proofs.push(proof.into());
}
}
@@ -300,8 +291,9 @@ impl Wallet {
/// Check if proofs are spent
pub async fn check_proofs_spent(&self, proofs: Proofs) -> Result<Vec<bool>, FfiError> {
let cdk_proofs: Vec<cdk::nuts::Proof> =
proofs.into_iter().map(|p| p.inner.clone()).collect();
let cdk_proofs: Result<Vec<cdk::nuts::Proof>, _> =
proofs.into_iter().map(|p| p.try_into()).collect();
let cdk_proofs = cdk_proofs?;
let proof_states = self.inner.check_proofs_spent(cdk_proofs).await?;
// Convert ProofState to bool (spent = true, unspent = false)
@@ -382,7 +374,9 @@ impl Wallet {
/// Reclaim unspent proofs (mark them as unspent in the database)
pub async fn reclaim_unspent(&self, proofs: Proofs) -> Result<(), FfiError> {
let cdk_proofs: Vec<cdk::nuts::Proof> = proofs.iter().map(|p| p.inner.clone()).collect();
let cdk_proofs: Result<Vec<cdk::nuts::Proof>, _> =
proofs.iter().map(|p| p.clone().try_into()).collect();
let cdk_proofs = cdk_proofs?;
self.inner.reclaim_unspent(cdk_proofs).await?;
Ok(())
}
@@ -401,9 +395,11 @@ impl Wallet {
) -> Result<Amount, FfiError> {
let id = cdk::nuts::Id::from_str(&keyset_id)
.map_err(|e| FfiError::Generic { msg: e.to_string() })?;
let fee_and_amounts = self.inner.get_keyset_fees_and_amounts_by_id(id).await?;
let total_fee = (proof_count as u64 * fee_and_amounts.fee()) / 1000; // fee is per thousand
Ok(Amount::new(total_fee))
let fee = self
.inner
.get_keyset_count_fee(&id, proof_count as u64)
.await?;
Ok(fee.into())
}
}
@@ -453,10 +449,7 @@ impl Wallet {
/// Mint blind auth tokens
pub async fn mint_blind_auth(&self, amount: Amount) -> Result<Proofs, FfiError> {
let proofs = self.inner.mint_blind_auth(amount.into()).await?;
Ok(proofs
.into_iter()
.map(|p| std::sync::Arc::new(p.into()))
.collect())
Ok(proofs.into_iter().map(|p| p.into()).collect())
}
/// Get unspent auth proofs

View File

@@ -18,7 +18,7 @@ use std::time::Duration;
use bip39::Mnemonic;
use cdk_ffi::sqlite::WalletSqliteDatabase;
use cdk_ffi::types::{Amount, CurrencyUnit, QuoteState, SplitTarget};
use cdk_ffi::types::{encode_mint_quote, Amount, CurrencyUnit, QuoteState, SplitTarget};
use cdk_ffi::wallet::Wallet as FfiWallet;
use cdk_ffi::WalletConfig;
use cdk_integration_tests::{get_mint_url_from_env, pay_if_regtest};
@@ -157,7 +157,7 @@ async fn test_ffi_full_minting_flow() {
);
// Calculate total amount of minted proofs
let total_minted: u64 = mint_result.iter().map(|proof| proof.amount().value).sum();
let total_minted: u64 = mint_result.iter().map(|proof| proof.amount.value).sum();
assert_eq!(
total_minted, mint_amount.value,
"Total minted amount should equal requested amount"
@@ -166,14 +166,11 @@ async fn test_ffi_full_minting_flow() {
// Verify each proof has valid properties
for proof in &mint_result {
assert!(
proof.amount().value > 0,
proof.amount.value > 0,
"Each proof should have positive amount"
);
assert!(
!proof.secret().is_empty(),
"Each proof should have a secret"
);
assert!(!proof.c().is_empty(), "Each proof should have a C value");
assert!(!proof.secret.is_empty(), "Each proof should have a secret");
assert!(!proof.c.is_empty(), "Each proof should have a C value");
}
// Step 4: Verify wallet balance after minting
@@ -235,7 +232,7 @@ async fn test_ffi_mint_quote_creation() {
);
// Test quote JSON serialization (useful for bindings that need JSON)
let quote_json = quote.to_json().expect("Quote should serialize to JSON");
let quote_json = encode_mint_quote(quote.clone()).expect("Quote should serialize to JSON");
assert!(!quote_json.is_empty(), "Quote JSON should not be empty");
println!(