mirror of
https://github.com/aljazceru/cdk.git
synced 2026-02-06 05:36:28 +01:00
refactor: itest as lib
This commit is contained in:
@@ -23,6 +23,8 @@ cdk-axum = { path = "../cdk-axum"}
|
||||
cdk-fake-wallet = { path = "../cdk-fake-wallet" }
|
||||
tower-http = { version = "0.4.4", features = ["cors"] }
|
||||
futures = { version = "0.3.28", default-features = false }
|
||||
once_cell = "1.19.0"
|
||||
uuid = { version = "1", features = ["v4"] }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
tokio = { version = "1", features = [
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
//! Test calc fee
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use bip39::Mnemonic;
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::cdk_database::WalletMemoryDatabase;
|
||||
use cdk::mint_url::MintUrl;
|
||||
use cdk::nuts::CurrencyUnit;
|
||||
use cdk::Wallet;
|
||||
use cdk_integration_tests::{create_backends_fake_wallet, start_mint, wallet_mint, MINT_URL};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
pub async fn test_mint_fee() -> Result<()> {
|
||||
tokio::spawn(async move {
|
||||
let ln_backends = create_backends_fake_wallet();
|
||||
|
||||
let mut supported_units = HashMap::new();
|
||||
supported_units.insert(CurrencyUnit::Sat, (1, 32));
|
||||
|
||||
start_mint(ln_backends, supported_units)
|
||||
.await
|
||||
.expect("Could not start mint")
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
let mnemonic = Mnemonic::generate(12)?;
|
||||
|
||||
let wallet = Wallet::new(
|
||||
MINT_URL,
|
||||
CurrencyUnit::Sat,
|
||||
Arc::new(WalletMemoryDatabase::default()),
|
||||
&mnemonic.to_seed_normalized(""),
|
||||
None,
|
||||
)?;
|
||||
|
||||
let wallet = Arc::new(wallet);
|
||||
|
||||
wallet_mint(
|
||||
Arc::clone(&wallet),
|
||||
10000.into(),
|
||||
SplitTarget::Value(1.into()),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
println!("Minted");
|
||||
|
||||
let proofs = wallet
|
||||
.localstore
|
||||
.get_proofs(Some(MintUrl::from_str(MINT_URL)?), None, None, None)
|
||||
.await?;
|
||||
|
||||
let proofs: Vec<cdk::nuts::Proof> = proofs.into_iter().map(|p| p.proof).collect();
|
||||
|
||||
let five_proofs = proofs[..5].to_vec();
|
||||
|
||||
let fee = wallet.get_proofs_fee(&five_proofs).await?;
|
||||
|
||||
// Check wallet gets fee calc correct
|
||||
assert_eq!(fee, 1.into());
|
||||
|
||||
let _swap = wallet
|
||||
.swap(None, SplitTarget::Value(1.into()), five_proofs, None, false)
|
||||
.await?;
|
||||
|
||||
let wallet_bal = wallet.total_balance().await?;
|
||||
|
||||
// Check 1 sat was paid in fees for the swap
|
||||
assert_eq!(wallet_bal, 9999.into());
|
||||
|
||||
let proofs = wallet
|
||||
.localstore
|
||||
.get_proofs(Some(MintUrl::from_str(MINT_URL)?), None, None, None)
|
||||
.await?;
|
||||
|
||||
let proofs: Vec<cdk::nuts::Proof> = proofs.into_iter().map(|p| p.proof).collect();
|
||||
|
||||
let thousand_proofs = proofs[..1001].to_vec();
|
||||
|
||||
let fee = wallet.get_proofs_fee(&thousand_proofs).await?;
|
||||
|
||||
// Check wallet gets fee calc correct
|
||||
assert_eq!(fee, 2.into());
|
||||
|
||||
let _swap = wallet
|
||||
.swap(
|
||||
None,
|
||||
SplitTarget::Value(1.into()),
|
||||
thousand_proofs,
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let wallet_bal = wallet.total_balance().await?;
|
||||
|
||||
// Check 1 sat was paid in fees for the swap
|
||||
assert_eq!(wallet_bal, 9997.into());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,88 +1,370 @@
|
||||
//! Mint integration tests
|
||||
//! Mint tests
|
||||
|
||||
use cdk::amount::{Amount, SplitTarget};
|
||||
use cdk::dhke::construct_proofs;
|
||||
use cdk::util::unix_time;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::OnceCell;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use bip39::Mnemonic;
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::cdk_database::WalletMemoryDatabase;
|
||||
use cdk::nuts::CurrencyUnit;
|
||||
use cdk::wallet::SendKind;
|
||||
use cdk::Error;
|
||||
use cdk::Wallet;
|
||||
use cdk_integration_tests::{create_backends_fake_wallet, start_mint, wallet_mint, MINT_URL};
|
||||
use cdk::cdk_database::mint_memory::MintMemoryDatabase;
|
||||
use cdk::nuts::{
|
||||
CurrencyUnit, Id, MintBolt11Request, MintInfo, Nuts, PreMintSecrets, Proofs, SecretKey,
|
||||
SpendingConditions, SwapRequest,
|
||||
};
|
||||
use cdk::Mint;
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
pub async fn test_mint_double_receive() -> Result<()> {
|
||||
tokio::spawn(async move {
|
||||
let ln_backends = create_backends_fake_wallet();
|
||||
pub const MINT_URL: &str = "http://127.0.0.1:8088";
|
||||
|
||||
let mut supported_units = HashMap::new();
|
||||
supported_units.insert(CurrencyUnit::Sat, (0, 64));
|
||||
static INSTANCE: OnceCell<Mint> = OnceCell::const_new();
|
||||
|
||||
start_mint(ln_backends, supported_units)
|
||||
.await
|
||||
.expect("Could not start mint")
|
||||
});
|
||||
async fn new_mint(fee: u64) -> Mint {
|
||||
let mut supported_units = HashMap::new();
|
||||
supported_units.insert(CurrencyUnit::Sat, (fee, 32));
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
let nuts = Nuts::new()
|
||||
.nut07(true)
|
||||
.nut08(true)
|
||||
.nut09(true)
|
||||
.nut10(true)
|
||||
.nut11(true)
|
||||
.nut12(true)
|
||||
.nut14(true);
|
||||
|
||||
let mnemonic = Mnemonic::generate(12)?;
|
||||
let mint_info = MintInfo::new().nuts(nuts);
|
||||
|
||||
let wallet = Wallet::new(
|
||||
let mnemonic = Mnemonic::generate(12).unwrap();
|
||||
|
||||
let mint = Mint::new(
|
||||
MINT_URL,
|
||||
CurrencyUnit::Sat,
|
||||
Arc::new(WalletMemoryDatabase::default()),
|
||||
&mnemonic.to_seed_normalized(""),
|
||||
None,
|
||||
)?;
|
||||
mint_info,
|
||||
Arc::new(MintMemoryDatabase::default()),
|
||||
supported_units,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let wallet = Arc::new(wallet);
|
||||
mint
|
||||
}
|
||||
|
||||
wallet_mint(Arc::clone(&wallet), 100.into(), SplitTarget::default()).await?;
|
||||
println!("Minted");
|
||||
async fn initialize() -> &'static Mint {
|
||||
INSTANCE.get_or_init(|| new_mint(0)).await
|
||||
}
|
||||
|
||||
let token = wallet
|
||||
.send(
|
||||
10.into(),
|
||||
None,
|
||||
None,
|
||||
&SplitTarget::default(),
|
||||
&SendKind::default(),
|
||||
false,
|
||||
async fn mint_proofs(
|
||||
mint: &Mint,
|
||||
amount: Amount,
|
||||
split_target: &SplitTarget,
|
||||
keys: cdk::nuts::Keys,
|
||||
) -> Result<Proofs> {
|
||||
let request_lookup = uuid::Uuid::new_v4().to_string();
|
||||
|
||||
let mint_quote = mint
|
||||
.new_mint_quote(
|
||||
MINT_URL.parse()?,
|
||||
"".to_string(),
|
||||
CurrencyUnit::Sat,
|
||||
amount,
|
||||
unix_time() + 36000,
|
||||
request_lookup.to_string(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mnemonic = Mnemonic::generate(12)?;
|
||||
mint.pay_mint_quote_for_request_id(&request_lookup).await?;
|
||||
let keyset_id = Id::from(&keys);
|
||||
|
||||
let wallet_two = Wallet::new(
|
||||
MINT_URL,
|
||||
CurrencyUnit::Sat,
|
||||
Arc::new(WalletMemoryDatabase::default()),
|
||||
&mnemonic.to_seed_normalized(""),
|
||||
None,
|
||||
let premint = PreMintSecrets::random(keyset_id, amount, split_target)?;
|
||||
|
||||
let mint_request = MintBolt11Request {
|
||||
quote: mint_quote.id,
|
||||
outputs: premint.blinded_messages(),
|
||||
};
|
||||
|
||||
let after_mint = mint.process_mint_request(mint_request).await?;
|
||||
|
||||
let proofs = construct_proofs(
|
||||
after_mint.signatures,
|
||||
premint.rs(),
|
||||
premint.secrets(),
|
||||
&keys,
|
||||
)?;
|
||||
|
||||
let rec = wallet_two
|
||||
.receive(&token.to_string(), SplitTarget::default(), &[], &[])
|
||||
.await?;
|
||||
println!("Received: {}", rec);
|
||||
Ok(proofs)
|
||||
}
|
||||
|
||||
// Attempt to receive again
|
||||
if let Err(err) = wallet
|
||||
.receive(&token.to_string(), SplitTarget::default(), &[], &[])
|
||||
.await
|
||||
{
|
||||
match err {
|
||||
Error::TokenAlreadySpent => (),
|
||||
_ => {
|
||||
println!("{}", err);
|
||||
bail!("Expected an already spent error");
|
||||
}
|
||||
}
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_mint_double_spend() -> Result<()> {
|
||||
let mint = initialize().await;
|
||||
|
||||
let keys = mint.pubkeys().await?.keysets.first().unwrap().clone().keys;
|
||||
let keyset_id = Id::from(&keys);
|
||||
|
||||
let proofs = mint_proofs(mint, 100.into(), &SplitTarget::default(), keys).await?;
|
||||
|
||||
let preswap = PreMintSecrets::random(keyset_id, 100.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_request = SwapRequest::new(proofs.clone(), preswap.blinded_messages());
|
||||
|
||||
let swap = mint.process_swap_request(swap_request).await;
|
||||
|
||||
assert!(swap.is_ok());
|
||||
|
||||
let preswap_two = PreMintSecrets::random(keyset_id, 100.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_two_request = SwapRequest::new(proofs, preswap_two.blinded_messages());
|
||||
|
||||
match mint.process_swap_request(swap_two_request).await {
|
||||
Ok(_) => bail!("Proofs double spent"),
|
||||
Err(err) => match err {
|
||||
cdk::Error::TokenAlreadySpent => (),
|
||||
_ => bail!("Wrong error returned"),
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This attempts to swap for more outputs then inputs.
|
||||
/// This will work if the mint does not check for outputs amounts overflowing
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_attempt_to_swap_by_overflowing() -> Result<()> {
|
||||
let mint = initialize().await;
|
||||
|
||||
let keys = mint.pubkeys().await?.keysets.first().unwrap().clone().keys;
|
||||
let keyset_id = Id::from(&keys);
|
||||
|
||||
let proofs = mint_proofs(mint, 100.into(), &SplitTarget::default(), keys).await?;
|
||||
|
||||
let amount = 2_u64.pow(63);
|
||||
|
||||
let pre_mint_amount =
|
||||
PreMintSecrets::random(keyset_id, amount.into(), &SplitTarget::default())?;
|
||||
let pre_mint_amount_two =
|
||||
PreMintSecrets::random(keyset_id, amount.into(), &SplitTarget::default())?;
|
||||
|
||||
let mut pre_mint = PreMintSecrets::random(keyset_id, 1.into(), &SplitTarget::default())?;
|
||||
|
||||
pre_mint.combine(pre_mint_amount);
|
||||
pre_mint.combine(pre_mint_amount_two);
|
||||
|
||||
let swap_request = SwapRequest::new(proofs.clone(), pre_mint.blinded_messages());
|
||||
|
||||
match mint.process_swap_request(swap_request).await {
|
||||
Ok(_) => bail!("Swap occurred with overflow"),
|
||||
Err(err) => match err {
|
||||
cdk::Error::NUT03(cdk::nuts::nut03::Error::Amount(_)) => (),
|
||||
_ => {
|
||||
println!("{:?}", err);
|
||||
bail!("Wrong error returned in swap overflow")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
pub async fn test_p2pk_swap() -> Result<()> {
|
||||
let mint = initialize().await;
|
||||
|
||||
let keys = mint.pubkeys().await?.keysets.first().unwrap().clone().keys;
|
||||
let keyset_id = Id::from(&keys);
|
||||
|
||||
let proofs = mint_proofs(mint, 100.into(), &SplitTarget::default(), keys).await?;
|
||||
|
||||
let secret = SecretKey::generate();
|
||||
|
||||
let spending_conditions = SpendingConditions::new_p2pk(secret.public_key(), None);
|
||||
|
||||
let pre_swap = PreMintSecrets::with_conditions(
|
||||
keyset_id,
|
||||
100.into(),
|
||||
&SplitTarget::default(),
|
||||
&spending_conditions,
|
||||
)?;
|
||||
|
||||
let swap_request = SwapRequest::new(proofs.clone(), pre_swap.blinded_messages());
|
||||
|
||||
let keys = mint.pubkeys().await?.keysets.first().cloned().unwrap().keys;
|
||||
|
||||
let post_swap = mint.process_swap_request(swap_request).await?;
|
||||
|
||||
let mut proofs = construct_proofs(
|
||||
post_swap.signatures,
|
||||
pre_swap.rs(),
|
||||
pre_swap.secrets(),
|
||||
&keys,
|
||||
)?;
|
||||
|
||||
let pre_swap = PreMintSecrets::random(keyset_id, 100.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_request = SwapRequest::new(proofs.clone(), pre_swap.blinded_messages());
|
||||
|
||||
match mint.process_swap_request(swap_request).await {
|
||||
Ok(_) => bail!("Proofs spent without sig"),
|
||||
Err(err) => match err {
|
||||
cdk::Error::NUT11(cdk::nuts::nut11::Error::SignaturesNotProvided) => (),
|
||||
_ => {
|
||||
println!("{:?}", err);
|
||||
bail!("Wrong error returned")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
for proof in &mut proofs {
|
||||
proof.sign_p2pk(secret.clone())?;
|
||||
}
|
||||
|
||||
let swap_request = SwapRequest::new(proofs.clone(), pre_swap.blinded_messages());
|
||||
|
||||
let attempt_swap = mint.process_swap_request(swap_request).await;
|
||||
|
||||
assert!(attempt_swap.is_ok());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_swap_unbalanced() -> Result<()> {
|
||||
let mint = initialize().await;
|
||||
|
||||
let keys = mint.pubkeys().await?.keysets.first().unwrap().clone().keys;
|
||||
let keyset_id = Id::from(&keys);
|
||||
|
||||
let proofs = mint_proofs(mint, 100.into(), &SplitTarget::default(), keys).await?;
|
||||
|
||||
let preswap = PreMintSecrets::random(keyset_id, 95.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_request = SwapRequest::new(proofs.clone(), preswap.blinded_messages());
|
||||
|
||||
match mint.process_swap_request(swap_request).await {
|
||||
Ok(_) => bail!("Swap was allowed unbalanced"),
|
||||
Err(err) => match err {
|
||||
cdk::Error::TransactionUnbalanced(_, _, _) => (),
|
||||
_ => bail!("Wrong error returned"),
|
||||
},
|
||||
}
|
||||
|
||||
let preswap = PreMintSecrets::random(keyset_id, 101.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_request = SwapRequest::new(proofs.clone(), preswap.blinded_messages());
|
||||
|
||||
match mint.process_swap_request(swap_request).await {
|
||||
Ok(_) => bail!("Swap was allowed unbalanced"),
|
||||
Err(err) => match err {
|
||||
cdk::Error::TransactionUnbalanced(_, _, _) => (),
|
||||
_ => bail!("Wrong error returned"),
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_swap_overpay_underpay_fee() -> Result<()> {
|
||||
let mint = new_mint(1).await;
|
||||
|
||||
mint.rotate_keyset(CurrencyUnit::Sat, 1, 32, 1).await?;
|
||||
|
||||
let keys = mint.pubkeys().await?.keysets.first().unwrap().clone().keys;
|
||||
let keyset_id = Id::from(&keys);
|
||||
|
||||
let proofs = mint_proofs(&mint, 1000.into(), &SplitTarget::default(), keys).await?;
|
||||
|
||||
let preswap = PreMintSecrets::random(keyset_id, 9998.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_request = SwapRequest::new(proofs.clone(), preswap.blinded_messages());
|
||||
|
||||
// Attempt to swap overpaying fee
|
||||
match mint.process_swap_request(swap_request).await {
|
||||
Ok(_) => bail!("Swap was allowed unbalanced"),
|
||||
Err(err) => match err {
|
||||
cdk::Error::TransactionUnbalanced(_, _, _) => (),
|
||||
_ => {
|
||||
println!("{:?}", err);
|
||||
bail!("Wrong error returned")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
let preswap = PreMintSecrets::random(keyset_id, 1000.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_request = SwapRequest::new(proofs.clone(), preswap.blinded_messages());
|
||||
|
||||
// Attempt to swap underpaying fee
|
||||
match mint.process_swap_request(swap_request).await {
|
||||
Ok(_) => bail!("Swap was allowed unbalanced"),
|
||||
Err(err) => match err {
|
||||
cdk::Error::TransactionUnbalanced(_, _, _) => (),
|
||||
_ => {
|
||||
println!("{:?}", err);
|
||||
bail!("Wrong error returned")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
async fn test_mint_enforce_fee() -> Result<()> {
|
||||
let mint = new_mint(1).await;
|
||||
|
||||
let keys = mint.pubkeys().await?.keysets.first().unwrap().clone().keys;
|
||||
let keyset_id = Id::from(&keys);
|
||||
|
||||
let mut proofs = mint_proofs(&mint, 1010.into(), &SplitTarget::Value(1.into()), keys).await?;
|
||||
|
||||
let five_proofs: Vec<_> = proofs.drain(..5).collect();
|
||||
|
||||
let preswap = PreMintSecrets::random(keyset_id, 5.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_request = SwapRequest::new(five_proofs.clone(), preswap.blinded_messages());
|
||||
|
||||
// Attempt to swap underpaying fee
|
||||
match mint.process_swap_request(swap_request).await {
|
||||
Ok(_) => bail!("Swap was allowed unbalanced"),
|
||||
Err(err) => match err {
|
||||
cdk::Error::TransactionUnbalanced(_, _, _) => (),
|
||||
_ => {
|
||||
println!("{:?}", err);
|
||||
bail!("Wrong error returned")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
let preswap = PreMintSecrets::random(keyset_id, 4.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_request = SwapRequest::new(five_proofs.clone(), preswap.blinded_messages());
|
||||
|
||||
let _ = mint.process_swap_request(swap_request).await?;
|
||||
|
||||
let thousnad_proofs: Vec<_> = proofs.drain(..1001).collect();
|
||||
|
||||
let preswap = PreMintSecrets::random(keyset_id, 1000.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_request = SwapRequest::new(thousnad_proofs.clone(), preswap.blinded_messages());
|
||||
|
||||
// Attempt to swap underpaying fee
|
||||
match mint.process_swap_request(swap_request).await {
|
||||
Ok(_) => bail!("Swap was allowed unbalanced"),
|
||||
Err(err) => match err {
|
||||
cdk::Error::TransactionUnbalanced(_, _, _) => (),
|
||||
_ => {
|
||||
println!("{:?}", err);
|
||||
bail!("Wrong error returned")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
let preswap = PreMintSecrets::random(keyset_id, 999.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_request = SwapRequest::new(thousnad_proofs.clone(), preswap.blinded_messages());
|
||||
|
||||
let _ = mint.process_swap_request(swap_request).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::dhke::construct_proofs;
|
||||
use cdk::nuts::{CurrencyUnit, PreMintSecrets, SwapRequest};
|
||||
use cdk::Amount;
|
||||
use cdk::HttpClient;
|
||||
use cdk_integration_tests::{create_backends_fake_wallet, mint_proofs, start_mint, MINT_URL};
|
||||
|
||||
/// This attempts to swap for more outputs then inputs.
|
||||
/// This will work if the mint does not check for outputs amounts overflowing
|
||||
async fn attempt_to_swap_by_overflowing() -> Result<()> {
|
||||
let wallet_client = HttpClient::new();
|
||||
let mint_keys = wallet_client.get_mint_keys(MINT_URL.parse()?).await?;
|
||||
|
||||
let mint_keys = mint_keys.first().unwrap();
|
||||
|
||||
let keyset_id = mint_keys.id;
|
||||
|
||||
let pre_swap_proofs = mint_proofs(MINT_URL, 1.into(), keyset_id, mint_keys).await?;
|
||||
|
||||
println!(
|
||||
"Pre swap amount: {:?}",
|
||||
Amount::try_sum(pre_swap_proofs.iter().map(|p| p.amount))?
|
||||
);
|
||||
|
||||
println!(
|
||||
"Pre swap amounts: {:?}",
|
||||
pre_swap_proofs
|
||||
.iter()
|
||||
.map(|p| p.amount)
|
||||
.collect::<Vec<Amount>>()
|
||||
);
|
||||
|
||||
// Construct messages that will overflow
|
||||
|
||||
let amount = 2_u64.pow(63);
|
||||
|
||||
let pre_mint_amount =
|
||||
PreMintSecrets::random(keyset_id, amount.into(), &SplitTarget::default())?;
|
||||
let pre_mint_amount_two =
|
||||
PreMintSecrets::random(keyset_id, amount.into(), &SplitTarget::default())?;
|
||||
|
||||
let mut pre_mint = PreMintSecrets::random(keyset_id, 1.into(), &SplitTarget::default())?;
|
||||
|
||||
pre_mint.combine(pre_mint_amount);
|
||||
pre_mint.combine(pre_mint_amount_two);
|
||||
|
||||
let swap_request = SwapRequest::new(pre_swap_proofs.clone(), pre_mint.blinded_messages());
|
||||
|
||||
let swap_response = match wallet_client
|
||||
.post_swap(MINT_URL.parse()?, swap_request)
|
||||
.await
|
||||
{
|
||||
Ok(res) => res,
|
||||
// In the context of this test an error response here is good.
|
||||
// It means the mint does not allow us to swap for more then we should by overflowing
|
||||
Err(_err) => return Ok(()),
|
||||
};
|
||||
|
||||
let post_swap_proofs = construct_proofs(
|
||||
swap_response.signatures,
|
||||
pre_mint.rs(),
|
||||
pre_mint.secrets(),
|
||||
&mint_keys.clone().keys,
|
||||
)?;
|
||||
|
||||
println!(
|
||||
"Pre swap amount: {:?}",
|
||||
Amount::try_sum(pre_swap_proofs.iter().map(|p| p.amount)).expect("Amount overflowed")
|
||||
);
|
||||
println!(
|
||||
"Post swap amount: {:?}",
|
||||
Amount::try_sum(post_swap_proofs.iter().map(|p| p.amount)).expect("Amount Overflowed")
|
||||
);
|
||||
|
||||
println!(
|
||||
"Pre swap amounts: {:?}",
|
||||
pre_swap_proofs
|
||||
.iter()
|
||||
.map(|p| p.amount)
|
||||
.collect::<Vec<Amount>>()
|
||||
);
|
||||
println!(
|
||||
"Post swap amounts: {:?}",
|
||||
post_swap_proofs
|
||||
.iter()
|
||||
.map(|p| p.amount)
|
||||
.collect::<Vec<Amount>>()
|
||||
);
|
||||
|
||||
bail!("Should not have been able to swap")
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
pub async fn test_overflow() -> Result<()> {
|
||||
tokio::spawn(async move {
|
||||
let ln_backends = create_backends_fake_wallet();
|
||||
|
||||
let mut supported_units = HashMap::new();
|
||||
supported_units.insert(CurrencyUnit::Sat, (0, 32));
|
||||
|
||||
start_mint(ln_backends, supported_units)
|
||||
.await
|
||||
.expect("Could not start mint")
|
||||
});
|
||||
|
||||
// Wait for mint server to start
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
let result = attempt_to_swap_by_overflowing().await;
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use bip39::Mnemonic;
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::cdk_database::WalletMemoryDatabase;
|
||||
use cdk::nuts::{CurrencyUnit, SecretKey, SpendingConditions};
|
||||
use cdk::wallet::SendKind;
|
||||
use cdk::{Amount, Wallet};
|
||||
use cdk_integration_tests::{create_backends_fake_wallet, start_mint, wallet_mint, MINT_URL};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
pub async fn test_p2pk_swap() -> Result<()> {
|
||||
tokio::spawn(async move {
|
||||
let ln_backends = create_backends_fake_wallet();
|
||||
|
||||
let mut supported_units = HashMap::new();
|
||||
supported_units.insert(CurrencyUnit::Sat, (0, 32));
|
||||
|
||||
start_mint(ln_backends, supported_units)
|
||||
.await
|
||||
.expect("Could not start mint")
|
||||
});
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
let mnemonic = Mnemonic::generate(12)?;
|
||||
|
||||
let wallet = Wallet::new(
|
||||
MINT_URL,
|
||||
CurrencyUnit::Sat,
|
||||
Arc::new(WalletMemoryDatabase::default()),
|
||||
&mnemonic.to_seed_normalized(""),
|
||||
None,
|
||||
)?;
|
||||
|
||||
let wallet = Arc::new(wallet);
|
||||
|
||||
// Mint 100 sats for the wallet
|
||||
wallet_mint(Arc::clone(&wallet), 100.into(), SplitTarget::default()).await?;
|
||||
|
||||
let secret = SecretKey::generate();
|
||||
|
||||
let spending_conditions = SpendingConditions::new_p2pk(secret.public_key(), None);
|
||||
|
||||
let amount = Amount::from(10);
|
||||
|
||||
let token = wallet
|
||||
.send(
|
||||
amount,
|
||||
None,
|
||||
Some(spending_conditions),
|
||||
&SplitTarget::None,
|
||||
&SendKind::default(),
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let attempt_amount = wallet
|
||||
.receive(&token.to_string(), SplitTarget::default(), &[], &[])
|
||||
.await;
|
||||
|
||||
// This should fail since the token is not signed
|
||||
assert!(attempt_amount.is_err());
|
||||
|
||||
let wrong_secret = SecretKey::generate();
|
||||
|
||||
let received_amount = wallet
|
||||
.receive(
|
||||
&token.to_string(),
|
||||
SplitTarget::default(),
|
||||
&[wrong_secret],
|
||||
&[],
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(received_amount.is_err());
|
||||
|
||||
let received_amount = wallet
|
||||
.receive(&token.to_string(), SplitTarget::default(), &[secret], &[])
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(received_amount, amount);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
//! Test that if a wallet attempts to swap for less outputs then inputs correct error is returned
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use cdk::amount::SplitTarget;
|
||||
use cdk::nuts::{CurrencyUnit, PreMintSecrets, SwapRequest};
|
||||
use cdk::Error;
|
||||
use cdk::HttpClient;
|
||||
use cdk_integration_tests::{create_backends_fake_wallet, mint_proofs, start_mint, MINT_URL};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
pub async fn test_unbalanced_swap() -> Result<()> {
|
||||
tokio::spawn(async move {
|
||||
let ln_backends = create_backends_fake_wallet();
|
||||
|
||||
let mut supported_units = HashMap::new();
|
||||
supported_units.insert(CurrencyUnit::Sat, (0, 32));
|
||||
|
||||
start_mint(ln_backends, supported_units)
|
||||
.await
|
||||
.expect("Could not start mint")
|
||||
});
|
||||
|
||||
// Wait for mint server to start
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
let wallet_client = HttpClient::new();
|
||||
let mint_keys = wallet_client.get_mint_keys(MINT_URL.parse()?).await?;
|
||||
|
||||
let mint_keys = mint_keys.first().unwrap();
|
||||
|
||||
let keyset_id = mint_keys.id;
|
||||
|
||||
let pre_swap_proofs = mint_proofs(MINT_URL, 10.into(), keyset_id, mint_keys).await?;
|
||||
|
||||
let pre_mint = PreMintSecrets::random(keyset_id, 9.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_request = SwapRequest::new(pre_swap_proofs.clone(), pre_mint.blinded_messages());
|
||||
|
||||
let _swap_response = match wallet_client
|
||||
.post_swap(MINT_URL.parse()?, swap_request)
|
||||
.await
|
||||
{
|
||||
Ok(res) => res,
|
||||
// In the context of this test an error response here is good.
|
||||
// It means the mint does not allow us to swap for more then we should by overflowing
|
||||
Err(err) => match err {
|
||||
Error::TransactionUnbalanced(_, _, _) => {
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
println!("{}", err);
|
||||
bail!("Wrong error code returned");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
bail!("Transaction should not have succeeded")
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
//! Fee tests for over and underpaying
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use bip39::Mnemonic;
|
||||
use cdk::cdk_database::WalletMemoryDatabase;
|
||||
use cdk::mint_url::MintUrl;
|
||||
use cdk::nuts::{CurrencyUnit, SwapRequest};
|
||||
use cdk::wallet::client::HttpClient;
|
||||
use cdk::Wallet;
|
||||
use cdk::{amount::SplitTarget, nuts::PreMintSecrets};
|
||||
use cdk_integration_tests::{create_backends_fake_wallet, start_mint, wallet_mint, MINT_URL};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||
pub async fn test_swap_overpay_underpay() -> Result<()> {
|
||||
tokio::spawn(async move {
|
||||
let ln_backends = create_backends_fake_wallet();
|
||||
|
||||
let mut supported_units = HashMap::new();
|
||||
supported_units.insert(CurrencyUnit::Sat, (1, 32));
|
||||
|
||||
start_mint(ln_backends, supported_units)
|
||||
.await
|
||||
.expect("Could not start mint")
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
let mnemonic = Mnemonic::generate(12)?;
|
||||
|
||||
let wallet = Wallet::new(
|
||||
MINT_URL,
|
||||
CurrencyUnit::Sat,
|
||||
Arc::new(WalletMemoryDatabase::default()),
|
||||
&mnemonic.to_seed_normalized(""),
|
||||
None,
|
||||
)?;
|
||||
|
||||
let wallet = Arc::new(wallet);
|
||||
|
||||
wallet_mint(
|
||||
Arc::clone(&wallet),
|
||||
10000.into(),
|
||||
SplitTarget::Value(1.into()),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
println!("Minted");
|
||||
|
||||
let proofs = wallet
|
||||
.localstore
|
||||
.get_proofs(Some(MintUrl::from_str(MINT_URL)?), None, None, None)
|
||||
.await?;
|
||||
|
||||
let proofs: Vec<cdk::nuts::Proof> = proofs.into_iter().map(|p| p.proof).collect();
|
||||
|
||||
let keyset_id = proofs.first().unwrap().keyset_id;
|
||||
|
||||
let pre_swap_proofs = proofs[..1000].to_vec();
|
||||
|
||||
// Attempt to swap while overpaying fee
|
||||
|
||||
let pre_swap_secret = PreMintSecrets::random(keyset_id, 450.into(), &SplitTarget::default())?;
|
||||
|
||||
let swap_request =
|
||||
SwapRequest::new(pre_swap_proofs.clone(), pre_swap_secret.blinded_messages());
|
||||
|
||||
let wallet_client = HttpClient::new();
|
||||
|
||||
match wallet_client
|
||||
.post_swap(MINT_URL.parse()?, swap_request)
|
||||
.await
|
||||
{
|
||||
Ok(_res) => {
|
||||
bail!("Swap should not have succeeded");
|
||||
}
|
||||
Err(err) => match err {
|
||||
cdk::error::Error::TransactionUnbalanced(_, _, _) => (),
|
||||
_ => {
|
||||
println!("{:?}", err);
|
||||
bail!("Swap returned the wrong error when overpaying fee");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Attempt to swap while underpaying fee
|
||||
|
||||
let pre_swap_secret = PreMintSecrets::random(keyset_id, 1000.into(), &SplitTarget::default())?;
|
||||
let swap_request =
|
||||
SwapRequest::new(pre_swap_proofs.clone(), pre_swap_secret.blinded_messages());
|
||||
match wallet_client
|
||||
.post_swap(MINT_URL.parse()?, swap_request)
|
||||
.await
|
||||
{
|
||||
Ok(_res) => {
|
||||
bail!("Swap should not have succeeded");
|
||||
}
|
||||
// In the context of this test an error response here is good.
|
||||
// It means the mint does not allow us to swap for more then we should by overflowing
|
||||
Err(err) => match err {
|
||||
cdk::error::Error::TransactionUnbalanced(_, _, _) => (),
|
||||
_ => {
|
||||
println!("{:?}", err);
|
||||
bail!("Swap returned the wrong error when underpaying fee");
|
||||
}
|
||||
},
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
@@ -511,8 +511,10 @@ impl Mint {
|
||||
Ok(KeysResponse {
|
||||
keysets: keysets
|
||||
.values()
|
||||
.filter(|k| active_keysets.contains(&k.id))
|
||||
.map(|k| k.clone().into())
|
||||
.filter_map(|k| match active_keysets.contains(&k.id) {
|
||||
true => Some(k.clone().into()),
|
||||
false => None,
|
||||
})
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
@@ -1648,4 +1650,9 @@ mod tests {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_over_pay_fee() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user