mirror of
https://github.com/aljazceru/cdk.git
synced 2026-02-09 07:06:12 +01:00
refactor: pure tests
This commit is contained in:
@@ -14,6 +14,7 @@ rust-version = "1.63.0"
|
||||
http_subscription = ["cdk/http_subscription"]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
axum = "0.6.20"
|
||||
rand = "0.8.5"
|
||||
bip39 = { version = "2.0", features = ["rand"] }
|
||||
@@ -57,8 +58,6 @@ getrandom = { version = "0.2", features = ["js"] }
|
||||
instant = { version = "0.1", features = ["wasm-bindgen", "inaccurate"] }
|
||||
|
||||
[dev-dependencies]
|
||||
async-trait = "0.1"
|
||||
rand = "0.8.5"
|
||||
bip39 = { version = "2.0", features = ["rand"] }
|
||||
anyhow = "1"
|
||||
cdk = { path = "../cdk", features = ["mint", "wallet"] }
|
||||
|
||||
223
crates/cdk-integration-tests/src/init_pure_tests.rs
Normal file
223
crates/cdk-integration-tests/src/init_pure_tests.rs
Normal file
@@ -0,0 +1,223 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bip39::Mnemonic;
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::cdk_database::mint_memory::MintMemoryDatabase;
|
||||
use cdk::cdk_database::WalletMemoryDatabase;
|
||||
use cdk::mint::{FeeReserve, MintBuilder, MintMeltLimits};
|
||||
use cdk::nuts::nut00::ProofsMethods;
|
||||
use cdk::nuts::{
|
||||
CheckStateRequest, CheckStateResponse, CurrencyUnit, Id, KeySet, KeysetResponse,
|
||||
MeltBolt11Request, MeltQuoteBolt11Request, MeltQuoteBolt11Response, MintBolt11Request,
|
||||
MintBolt11Response, MintInfo, MintQuoteBolt11Request, MintQuoteBolt11Response, PaymentMethod,
|
||||
RestoreRequest, RestoreResponse, SwapRequest, SwapResponse,
|
||||
};
|
||||
use cdk::util::unix_time;
|
||||
use cdk::wallet::client::MintConnector;
|
||||
use cdk::wallet::Wallet;
|
||||
use cdk::{Amount, Error, Mint};
|
||||
use cdk_fake_wallet::FakeWallet;
|
||||
use tokio::sync::Notify;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::wait_for_mint_to_be_paid;
|
||||
|
||||
pub struct DirectMintConnection {
|
||||
pub mint: Arc<Mint>,
|
||||
}
|
||||
|
||||
impl DirectMintConnection {
|
||||
pub fn new(mint: Arc<Mint>) -> Self {
|
||||
Self { mint }
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for DirectMintConnection {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"DirectMintConnection {{ mint_info: {:?} }}",
|
||||
self.mint.config.mint_info()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements the generic [MintConnector] (i.e. use the interface that expects to communicate
|
||||
/// to a generic mint, where we don't know that quote ID's are [Uuid]s) for [DirectMintConnection],
|
||||
/// where we know we're dealing with a mint that uses [Uuid]s for quotes.
|
||||
/// Convert the requests and responses between the [String] and [Uuid] variants as necessary.
|
||||
#[async_trait]
|
||||
impl MintConnector for DirectMintConnection {
|
||||
async fn get_mint_keys(&self) -> Result<Vec<KeySet>, Error> {
|
||||
self.mint.pubkeys().await.map(|pks| pks.keysets)
|
||||
}
|
||||
|
||||
async fn get_mint_keyset(&self, keyset_id: Id) -> Result<KeySet, Error> {
|
||||
self.mint
|
||||
.keyset(&keyset_id)
|
||||
.await
|
||||
.and_then(|res| res.ok_or(Error::UnknownKeySet))
|
||||
}
|
||||
|
||||
async fn get_mint_keysets(&self) -> Result<KeysetResponse, Error> {
|
||||
self.mint.keysets().await
|
||||
}
|
||||
|
||||
async fn post_mint_quote(
|
||||
&self,
|
||||
request: MintQuoteBolt11Request,
|
||||
) -> Result<MintQuoteBolt11Response<String>, Error> {
|
||||
self.mint
|
||||
.get_mint_bolt11_quote(request)
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
async fn get_mint_quote_status(
|
||||
&self,
|
||||
quote_id: &str,
|
||||
) -> Result<MintQuoteBolt11Response<String>, Error> {
|
||||
let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
|
||||
self.mint
|
||||
.check_mint_quote("e_id_uuid)
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
async fn post_mint(
|
||||
&self,
|
||||
request: MintBolt11Request<String>,
|
||||
) -> Result<MintBolt11Response, Error> {
|
||||
let request_uuid = request.try_into().unwrap();
|
||||
self.mint.process_mint_request(request_uuid).await
|
||||
}
|
||||
|
||||
async fn post_melt_quote(
|
||||
&self,
|
||||
request: MeltQuoteBolt11Request,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
self.mint
|
||||
.get_melt_bolt11_quote(&request)
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
async fn get_melt_quote_status(
|
||||
&self,
|
||||
quote_id: &str,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
|
||||
self.mint
|
||||
.check_melt_quote("e_id_uuid)
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
async fn post_melt(
|
||||
&self,
|
||||
request: MeltBolt11Request<String>,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
let request_uuid = request.try_into().unwrap();
|
||||
self.mint.melt_bolt11(&request_uuid).await.map(Into::into)
|
||||
}
|
||||
|
||||
async fn post_swap(&self, swap_request: SwapRequest) -> Result<SwapResponse, Error> {
|
||||
self.mint.process_swap_request(swap_request).await
|
||||
}
|
||||
|
||||
async fn get_mint_info(&self) -> Result<MintInfo, Error> {
|
||||
Ok(self.mint.mint_info().clone().time(unix_time()))
|
||||
}
|
||||
|
||||
async fn post_check_state(
|
||||
&self,
|
||||
request: CheckStateRequest,
|
||||
) -> Result<CheckStateResponse, Error> {
|
||||
self.mint.check_state(&request).await
|
||||
}
|
||||
|
||||
async fn post_restore(&self, request: RestoreRequest) -> Result<RestoreResponse, Error> {
|
||||
self.mint.restore(request).await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_and_start_test_mint() -> anyhow::Result<Arc<Mint>> {
|
||||
let mut mint_builder = MintBuilder::new();
|
||||
|
||||
let database = MintMemoryDatabase::default();
|
||||
|
||||
mint_builder = mint_builder.with_localstore(Arc::new(database));
|
||||
|
||||
let fee_reserve = FeeReserve {
|
||||
min_fee_reserve: 1.into(),
|
||||
percent_fee_reserve: 1.0,
|
||||
};
|
||||
|
||||
let ln_fake_backend = Arc::new(FakeWallet::new(
|
||||
fee_reserve.clone(),
|
||||
HashMap::default(),
|
||||
HashSet::default(),
|
||||
0,
|
||||
));
|
||||
|
||||
mint_builder = mint_builder.add_ln_backend(
|
||||
CurrencyUnit::Sat,
|
||||
PaymentMethod::Bolt11,
|
||||
MintMeltLimits::default(),
|
||||
ln_fake_backend,
|
||||
);
|
||||
|
||||
let mnemonic = Mnemonic::generate(12)?;
|
||||
|
||||
mint_builder = mint_builder
|
||||
.with_name("pure test mint".to_string())
|
||||
.with_mint_url("http://aa".to_string())
|
||||
.with_description("pure test mint".to_string())
|
||||
.with_quote_ttl(10000, 10000)
|
||||
.with_seed(mnemonic.to_seed_normalized("").to_vec());
|
||||
|
||||
let mint = mint_builder.build().await?;
|
||||
|
||||
let mint_arc = Arc::new(mint);
|
||||
|
||||
let mint_arc_clone = Arc::clone(&mint_arc);
|
||||
let shutdown = Arc::new(Notify::new());
|
||||
tokio::spawn({
|
||||
let shutdown = Arc::clone(&shutdown);
|
||||
async move { mint_arc_clone.wait_for_paid_invoices(shutdown).await }
|
||||
});
|
||||
|
||||
Ok(mint_arc)
|
||||
}
|
||||
|
||||
pub fn create_test_wallet_for_mint(mint: Arc<Mint>) -> anyhow::Result<Arc<Wallet>> {
|
||||
let connector = DirectMintConnection::new(mint);
|
||||
|
||||
let seed = Mnemonic::generate(12)?.to_seed_normalized("");
|
||||
let mint_url = connector.mint.config.mint_url().to_string();
|
||||
let unit = CurrencyUnit::Sat;
|
||||
let localstore = WalletMemoryDatabase::default();
|
||||
let mut wallet = Wallet::new(&mint_url, unit, Arc::new(localstore), &seed, None)?;
|
||||
|
||||
wallet.set_client(connector);
|
||||
|
||||
Ok(Arc::new(wallet))
|
||||
}
|
||||
|
||||
/// Creates a mint quote for the given amount and checks its state in a loop. Returns when
|
||||
/// amount is minted.
|
||||
pub async fn fund_wallet(wallet: Arc<Wallet>, amount: u64) -> anyhow::Result<Amount> {
|
||||
let desired_amount = Amount::from(amount);
|
||||
let quote = wallet.mint_quote(desired_amount, None).await?;
|
||||
|
||||
wait_for_mint_to_be_paid(&wallet, "e.id).await?;
|
||||
|
||||
Ok(wallet
|
||||
.mint("e.id, SplitTarget::default(), None)
|
||||
.await?
|
||||
.total_amount()?)
|
||||
}
|
||||
@@ -1,54 +1,26 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use cdk::amount::{Amount, SplitTarget};
|
||||
use cdk::cdk_lightning::MintLightning;
|
||||
use cdk::dhke::construct_proofs;
|
||||
use cdk::mint::FeeReserve;
|
||||
use cdk::mint_url::MintUrl;
|
||||
use cdk::nuts::nut00::ProofsMethods;
|
||||
use cdk::nuts::nut17::Params;
|
||||
use cdk::nuts::{
|
||||
CurrencyUnit, Id, KeySet, MintBolt11Request, MintQuoteBolt11Request, MintQuoteState,
|
||||
NotificationPayload, PaymentMethod, PreMintSecrets, Proofs, State,
|
||||
NotificationPayload, PreMintSecrets, Proofs, State,
|
||||
};
|
||||
use cdk::types::LnKey;
|
||||
use cdk::wallet::client::{HttpClient, MintConnector};
|
||||
use cdk::wallet::subscription::SubscriptionManager;
|
||||
use cdk::wallet::WalletSubscription;
|
||||
use cdk::Wallet;
|
||||
use cdk_fake_wallet::FakeWallet;
|
||||
|
||||
pub mod init_fake_wallet;
|
||||
pub mod init_mint;
|
||||
pub mod init_pure_tests;
|
||||
pub mod init_regtest;
|
||||
|
||||
pub fn create_backends_fake_wallet(
|
||||
) -> HashMap<LnKey, Arc<dyn MintLightning<Err = cdk::cdk_lightning::Error> + Sync + Send>> {
|
||||
let fee_reserve = FeeReserve {
|
||||
min_fee_reserve: 1.into(),
|
||||
percent_fee_reserve: 1.0,
|
||||
};
|
||||
let mut ln_backends: HashMap<
|
||||
LnKey,
|
||||
Arc<dyn MintLightning<Err = cdk::cdk_lightning::Error> + Sync + Send>,
|
||||
> = HashMap::new();
|
||||
let ln_key = LnKey::new(CurrencyUnit::Sat, PaymentMethod::Bolt11);
|
||||
|
||||
let wallet = Arc::new(FakeWallet::new(
|
||||
fee_reserve.clone(),
|
||||
HashMap::default(),
|
||||
HashSet::default(),
|
||||
0,
|
||||
));
|
||||
|
||||
ln_backends.insert(ln_key, wallet.clone());
|
||||
|
||||
ln_backends
|
||||
}
|
||||
|
||||
pub async fn wallet_mint(
|
||||
wallet: Arc<Wallet>,
|
||||
amount: Amount,
|
||||
@@ -180,3 +152,22 @@ pub async fn attempt_to_swap_pending(wallet: &Wallet) -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Keep polling the state of the mint quote id until it's paid
|
||||
pub async fn wait_for_mint_to_be_paid(wallet: &Wallet, mint_quote_id: &str) -> Result<()> {
|
||||
let mut subscription = wallet
|
||||
.subscribe(WalletSubscription::Bolt11MintQuoteState(vec![
|
||||
mint_quote_id.to_owned(),
|
||||
]))
|
||||
.await;
|
||||
|
||||
while let Some(msg) = subscription.recv().await {
|
||||
if let NotificationPayload::MintQuoteBolt11Response(response) = msg {
|
||||
if response.state == MintQuoteState::Paid {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ use cdk::amount::SplitTarget;
|
||||
use cdk::cdk_database::WalletMemoryDatabase;
|
||||
use cdk::nuts::nut00::ProofsMethods;
|
||||
use cdk::nuts::{
|
||||
CurrencyUnit, MeltBolt11Request, MeltQuoteState, MintBolt11Request, MintQuoteState,
|
||||
NotificationPayload, PreMintSecrets, SecretKey, State,
|
||||
CurrencyUnit, MeltBolt11Request, MeltQuoteState, MintBolt11Request, PreMintSecrets, SecretKey,
|
||||
State,
|
||||
};
|
||||
use cdk::wallet::client::{HttpClient, MintConnector};
|
||||
use cdk::wallet::{Wallet, WalletSubscription};
|
||||
use cdk::wallet::Wallet;
|
||||
use cdk_fake_wallet::{create_fake_invoice, FakeInvoiceDescription};
|
||||
use cdk_integration_tests::attempt_to_swap_pending;
|
||||
use cdk_integration_tests::{attempt_to_swap_pending, wait_for_mint_to_be_paid};
|
||||
|
||||
const MINT_URL: &str = "http://127.0.0.1:8086";
|
||||
|
||||
@@ -477,22 +477,3 @@ async fn test_fake_mint_with_wrong_witness() -> Result<()> {
|
||||
Ok(_) => bail!("Minting should not have succeed without a witness"),
|
||||
}
|
||||
}
|
||||
|
||||
// Keep polling the state of the mint quote id until it's paid
|
||||
async fn wait_for_mint_to_be_paid(wallet: &Wallet, mint_quote_id: &str) -> Result<()> {
|
||||
let mut subscription = wallet
|
||||
.subscribe(WalletSubscription::Bolt11MintQuoteState(vec![
|
||||
mint_quote_id.to_owned(),
|
||||
]))
|
||||
.await;
|
||||
|
||||
while let Some(msg) = subscription.recv().await {
|
||||
if let NotificationPayload::MintQuoteBolt11Response(response) = msg {
|
||||
if response.state == MintQuoteState::Paid {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,267 +1,45 @@
|
||||
#[cfg(test)]
|
||||
mod integration_tests_pure {
|
||||
use std::assert_eq;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::assert_eq;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::cdk_database::mint_memory::MintMemoryDatabase;
|
||||
use cdk::cdk_database::WalletMemoryDatabase;
|
||||
use cdk::nuts::nut00::ProofsMethods;
|
||||
use cdk::nuts::{
|
||||
CheckStateRequest, CheckStateResponse, CurrencyUnit, Id, KeySet, KeysetResponse,
|
||||
MeltBolt11Request, MeltQuoteBolt11Request, MeltQuoteBolt11Response, MintBolt11Request,
|
||||
MintBolt11Response, MintInfo, MintQuoteBolt11Request, MintQuoteBolt11Response,
|
||||
MintQuoteState, Nuts, RestoreRequest, RestoreResponse, SwapRequest, SwapResponse,
|
||||
};
|
||||
use cdk::types::QuoteTTL;
|
||||
use cdk::util::unix_time;
|
||||
use cdk::wallet::client::MintConnector;
|
||||
use cdk::{Amount, Error, Mint, Wallet};
|
||||
use cdk_integration_tests::create_backends_fake_wallet;
|
||||
use rand::random;
|
||||
use tokio::sync::Notify;
|
||||
use uuid::Uuid;
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::nuts::nut00::ProofsMethods;
|
||||
use cdk::wallet::SendKind;
|
||||
use cdk::Amount;
|
||||
use cdk_integration_tests::init_pure_tests::{
|
||||
create_and_start_test_mint, create_test_wallet_for_mint, fund_wallet,
|
||||
};
|
||||
|
||||
struct DirectMintConnection {
|
||||
mint: Arc<Mint>,
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn test_swap_to_send() -> anyhow::Result<()> {
|
||||
let mint_bob = create_and_start_test_mint().await?;
|
||||
let wallet_alice = create_test_wallet_for_mint(mint_bob.clone())?;
|
||||
|
||||
impl Debug for DirectMintConnection {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"DirectMintConnection {{ mint_info: {:?} }}",
|
||||
self.mint.config.mint_info()
|
||||
)
|
||||
}
|
||||
}
|
||||
// Alice gets 64 sats
|
||||
fund_wallet(wallet_alice.clone(), 64).await?;
|
||||
let balance_alice = wallet_alice.total_balance().await?;
|
||||
assert_eq!(Amount::from(64), balance_alice);
|
||||
|
||||
/// Implements the generic [MintConnector] (i.e. use the interface that expects to communicate
|
||||
/// to a generic mint, where we don't know that quote ID's are [Uuid]s) for [DirectMintConnection],
|
||||
/// where we know we're dealing with a mint that uses [Uuid]s for quotes.
|
||||
/// Convert the requests and responses between the [String] and [Uuid] variants as necessary.
|
||||
#[async_trait]
|
||||
impl MintConnector for DirectMintConnection {
|
||||
async fn get_mint_keys(&self) -> Result<Vec<KeySet>, Error> {
|
||||
self.mint.pubkeys().await.map(|pks| pks.keysets)
|
||||
}
|
||||
|
||||
async fn get_mint_keyset(&self, keyset_id: Id) -> Result<KeySet, Error> {
|
||||
self.mint
|
||||
.keyset(&keyset_id)
|
||||
.await
|
||||
.and_then(|res| res.ok_or(Error::UnknownKeySet))
|
||||
}
|
||||
|
||||
async fn get_mint_keysets(&self) -> Result<KeysetResponse, Error> {
|
||||
self.mint.keysets().await
|
||||
}
|
||||
|
||||
async fn post_mint_quote(
|
||||
&self,
|
||||
request: MintQuoteBolt11Request,
|
||||
) -> Result<MintQuoteBolt11Response<String>, Error> {
|
||||
self.mint
|
||||
.get_mint_bolt11_quote(request)
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
async fn get_mint_quote_status(
|
||||
&self,
|
||||
quote_id: &str,
|
||||
) -> Result<MintQuoteBolt11Response<String>, Error> {
|
||||
let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
|
||||
self.mint
|
||||
.check_mint_quote("e_id_uuid)
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
async fn post_mint(
|
||||
&self,
|
||||
request: MintBolt11Request<String>,
|
||||
) -> Result<MintBolt11Response, Error> {
|
||||
let request_uuid = request.try_into().unwrap();
|
||||
self.mint.process_mint_request(request_uuid).await
|
||||
}
|
||||
|
||||
async fn post_melt_quote(
|
||||
&self,
|
||||
request: MeltQuoteBolt11Request,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
self.mint
|
||||
.get_melt_bolt11_quote(&request)
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
async fn get_melt_quote_status(
|
||||
&self,
|
||||
quote_id: &str,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
let quote_id_uuid = Uuid::from_str(quote_id).unwrap();
|
||||
self.mint
|
||||
.check_melt_quote("e_id_uuid)
|
||||
.await
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
async fn post_melt(
|
||||
&self,
|
||||
request: MeltBolt11Request<String>,
|
||||
) -> Result<MeltQuoteBolt11Response<String>, Error> {
|
||||
let request_uuid = request.try_into().unwrap();
|
||||
self.mint.melt_bolt11(&request_uuid).await.map(Into::into)
|
||||
}
|
||||
|
||||
async fn post_swap(&self, swap_request: SwapRequest) -> Result<SwapResponse, Error> {
|
||||
self.mint.process_swap_request(swap_request).await
|
||||
}
|
||||
|
||||
async fn get_mint_info(&self) -> Result<MintInfo, Error> {
|
||||
Ok(self.mint.mint_info().clone().time(unix_time()))
|
||||
}
|
||||
|
||||
async fn post_check_state(
|
||||
&self,
|
||||
request: CheckStateRequest,
|
||||
) -> Result<CheckStateResponse, Error> {
|
||||
self.mint.check_state(&request).await
|
||||
}
|
||||
|
||||
async fn post_restore(&self, request: RestoreRequest) -> Result<RestoreResponse, Error> {
|
||||
self.mint.restore(request).await
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mint_connector(mint: Arc<Mint>) -> DirectMintConnection {
|
||||
DirectMintConnection { mint }
|
||||
}
|
||||
|
||||
async fn create_and_start_test_mint() -> anyhow::Result<Arc<Mint>> {
|
||||
let fee: u64 = 0;
|
||||
let mut supported_units = HashMap::new();
|
||||
supported_units.insert(CurrencyUnit::Sat, (fee, 32));
|
||||
|
||||
let nuts = Nuts::new()
|
||||
.nut07(true)
|
||||
.nut08(true)
|
||||
.nut09(true)
|
||||
.nut10(true)
|
||||
.nut11(true)
|
||||
.nut12(true)
|
||||
.nut14(true);
|
||||
|
||||
let mint_info = MintInfo::new().nuts(nuts);
|
||||
|
||||
let quote_ttl = QuoteTTL::new(10000, 10000);
|
||||
|
||||
let mint_url = "http://aaa";
|
||||
|
||||
let seed = random::<[u8; 32]>();
|
||||
let mint: Mint = Mint::new(
|
||||
mint_url,
|
||||
&seed,
|
||||
mint_info,
|
||||
quote_ttl,
|
||||
Arc::new(MintMemoryDatabase::default()),
|
||||
create_backends_fake_wallet(),
|
||||
supported_units,
|
||||
HashMap::new(),
|
||||
// Alice wants to send 40 sats, which internally swaps
|
||||
let token = wallet_alice
|
||||
.send(
|
||||
Amount::from(40),
|
||||
None,
|
||||
None,
|
||||
&SplitTarget::None,
|
||||
&SendKind::OnlineExact,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(Amount::from(40), token.proofs().total_amount()?);
|
||||
assert_eq!(Amount::from(24), wallet_alice.total_balance().await?);
|
||||
|
||||
let mint_arc = Arc::new(mint);
|
||||
// Alice sends cashu, Carol receives
|
||||
let wallet_carol = create_test_wallet_for_mint(mint_bob.clone())?;
|
||||
let received_amount = wallet_carol
|
||||
.receive_proofs(token.proofs(), SplitTarget::None, &[], &[])
|
||||
.await?;
|
||||
|
||||
let mint_arc_clone = Arc::clone(&mint_arc);
|
||||
let shutdown = Arc::new(Notify::new());
|
||||
tokio::spawn({
|
||||
let shutdown = Arc::clone(&shutdown);
|
||||
async move { mint_arc_clone.wait_for_paid_invoices(shutdown).await }
|
||||
});
|
||||
assert_eq!(Amount::from(40), received_amount);
|
||||
assert_eq!(Amount::from(40), wallet_carol.total_balance().await?);
|
||||
|
||||
Ok(mint_arc)
|
||||
}
|
||||
|
||||
fn create_test_wallet_for_mint(mint: Arc<Mint>) -> anyhow::Result<Arc<Wallet>> {
|
||||
let connector = get_mint_connector(mint);
|
||||
|
||||
let seed = random::<[u8; 32]>();
|
||||
let mint_url = connector.mint.config.mint_url().to_string();
|
||||
let unit = CurrencyUnit::Sat;
|
||||
|
||||
let localstore = WalletMemoryDatabase::default();
|
||||
let mut wallet = Wallet::new(&mint_url, unit, Arc::new(localstore), &seed, None)?;
|
||||
|
||||
wallet.set_client(connector);
|
||||
|
||||
Ok(Arc::new(wallet))
|
||||
}
|
||||
|
||||
/// Creates a mint quote for the given amount and checks its state in a loop. Returns when
|
||||
/// amount is minted.
|
||||
async fn receive(wallet: Arc<Wallet>, amount: u64) -> anyhow::Result<Amount> {
|
||||
let desired_amount = Amount::from(amount);
|
||||
let quote = wallet.mint_quote(desired_amount, None).await?;
|
||||
|
||||
loop {
|
||||
let status = wallet.mint_quote_state("e.id).await?;
|
||||
if status.state == MintQuoteState::Paid {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(wallet
|
||||
.mint("e.id, SplitTarget::default(), None)
|
||||
.await?
|
||||
.total_amount()?)
|
||||
}
|
||||
|
||||
mod nut03 {
|
||||
use cdk::nuts::nut00::ProofsMethods;
|
||||
use cdk::wallet::SendKind;
|
||||
|
||||
use crate::integration_tests_pure::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_swap_to_send() -> anyhow::Result<()> {
|
||||
let mint_bob = create_and_start_test_mint().await?;
|
||||
let wallet_alice = create_test_wallet_for_mint(mint_bob.clone())?;
|
||||
|
||||
// Alice gets 64 sats
|
||||
receive(wallet_alice.clone(), 64).await?;
|
||||
let balance_alice = wallet_alice.total_balance().await?;
|
||||
assert_eq!(Amount::from(64), balance_alice);
|
||||
|
||||
// Alice wants to send 40 sats, which internally swaps
|
||||
let token = wallet_alice
|
||||
.send(
|
||||
Amount::from(40),
|
||||
None,
|
||||
None,
|
||||
&SplitTarget::None,
|
||||
&SendKind::OnlineExact,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(Amount::from(40), token.proofs().total_amount()?);
|
||||
assert_eq!(Amount::from(24), wallet_alice.total_balance().await?);
|
||||
|
||||
// Alice sends cashu, Carol receives
|
||||
let wallet_carol = create_test_wallet_for_mint(mint_bob.clone())?;
|
||||
let received_amount = wallet_carol
|
||||
.receive_proofs(token.proofs(), SplitTarget::None, &[], &[])
|
||||
.await?;
|
||||
|
||||
assert_eq!(Amount::from(40), received_amount);
|
||||
assert_eq!(Amount::from(40), wallet_carol.total_balance().await?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user