|  | @@ -955,6 +955,166 @@ async fn test_fake_mint_swap_inflated() -> Result<()> {
 | 
	
		
			
				|  |  |      Ok(())
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/// Test swap after failure
 | 
	
		
			
				|  |  | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
 | 
	
		
			
				|  |  | +async fn test_fake_mint_swap_spend_after_fail() -> Result<()> {
 | 
	
		
			
				|  |  | +    let wallet = Wallet::new(
 | 
	
		
			
				|  |  | +        MINT_URL,
 | 
	
		
			
				|  |  | +        CurrencyUnit::Sat,
 | 
	
		
			
				|  |  | +        Arc::new(WalletMemoryDatabase::default()),
 | 
	
		
			
				|  |  | +        &Mnemonic::generate(12)?.to_seed_normalized(""),
 | 
	
		
			
				|  |  | +        None,
 | 
	
		
			
				|  |  | +    )?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let mint_quote = wallet.mint_quote(100.into(), None).await?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    wait_for_mint_to_be_paid(&wallet, &mint_quote.id, 60).await?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let proofs = wallet.mint(&mint_quote.id, SplitTarget::None, None).await?;
 | 
	
		
			
				|  |  | +    let active_keyset_id = wallet.get_active_mint_keyset().await?.id;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let pre_mint = PreMintSecrets::random(active_keyset_id, 100.into(), &SplitTarget::None)?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let swap_request = SwapRequest {
 | 
	
		
			
				|  |  | +        inputs: proofs.clone(),
 | 
	
		
			
				|  |  | +        outputs: pre_mint.blinded_messages(),
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let http_client = HttpClient::new(MINT_URL.parse()?);
 | 
	
		
			
				|  |  | +    let response = http_client.post_swap(swap_request.clone()).await;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    assert!(response.is_ok());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let pre_mint = PreMintSecrets::random(active_keyset_id, 101.into(), &SplitTarget::None)?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let swap_request = SwapRequest {
 | 
	
		
			
				|  |  | +        inputs: proofs.clone(),
 | 
	
		
			
				|  |  | +        outputs: pre_mint.blinded_messages(),
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let http_client = HttpClient::new(MINT_URL.parse()?);
 | 
	
		
			
				|  |  | +    let response = http_client.post_swap(swap_request.clone()).await;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    match response {
 | 
	
		
			
				|  |  | +        Err(err) => match err {
 | 
	
		
			
				|  |  | +            cdk::Error::TokenAlreadySpent => (),
 | 
	
		
			
				|  |  | +            err => {
 | 
	
		
			
				|  |  | +                bail!(
 | 
	
		
			
				|  |  | +                    "Wrong mint error returned expected already spent: {}",
 | 
	
		
			
				|  |  | +                    err.to_string()
 | 
	
		
			
				|  |  | +                );
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        },
 | 
	
		
			
				|  |  | +        Ok(_) => {
 | 
	
		
			
				|  |  | +            bail!("Should not have allowed swap with unbalanced");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let pre_mint = PreMintSecrets::random(active_keyset_id, 100.into(), &SplitTarget::None)?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let swap_request = SwapRequest {
 | 
	
		
			
				|  |  | +        inputs: proofs,
 | 
	
		
			
				|  |  | +        outputs: pre_mint.blinded_messages(),
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let http_client = HttpClient::new(MINT_URL.parse()?);
 | 
	
		
			
				|  |  | +    let response = http_client.post_swap(swap_request.clone()).await;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    match response {
 | 
	
		
			
				|  |  | +        Err(err) => match err {
 | 
	
		
			
				|  |  | +            cdk::Error::TokenAlreadySpent => (),
 | 
	
		
			
				|  |  | +            err => {
 | 
	
		
			
				|  |  | +                bail!("Wrong mint error returned: {}", err.to_string());
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        },
 | 
	
		
			
				|  |  | +        Ok(_) => {
 | 
	
		
			
				|  |  | +            bail!("Should not have allowed to mint with multiple units");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Ok(())
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/// Test swap after failure
 | 
	
		
			
				|  |  | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
 | 
	
		
			
				|  |  | +async fn test_fake_mint_melt_spend_after_fail() -> Result<()> {
 | 
	
		
			
				|  |  | +    let wallet = Wallet::new(
 | 
	
		
			
				|  |  | +        MINT_URL,
 | 
	
		
			
				|  |  | +        CurrencyUnit::Sat,
 | 
	
		
			
				|  |  | +        Arc::new(WalletMemoryDatabase::default()),
 | 
	
		
			
				|  |  | +        &Mnemonic::generate(12)?.to_seed_normalized(""),
 | 
	
		
			
				|  |  | +        None,
 | 
	
		
			
				|  |  | +    )?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let mint_quote = wallet.mint_quote(100.into(), None).await?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    wait_for_mint_to_be_paid(&wallet, &mint_quote.id, 60).await?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let proofs = wallet.mint(&mint_quote.id, SplitTarget::None, None).await?;
 | 
	
		
			
				|  |  | +    let active_keyset_id = wallet.get_active_mint_keyset().await?.id;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let pre_mint = PreMintSecrets::random(active_keyset_id, 100.into(), &SplitTarget::None)?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let swap_request = SwapRequest {
 | 
	
		
			
				|  |  | +        inputs: proofs.clone(),
 | 
	
		
			
				|  |  | +        outputs: pre_mint.blinded_messages(),
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let http_client = HttpClient::new(MINT_URL.parse()?);
 | 
	
		
			
				|  |  | +    let response = http_client.post_swap(swap_request.clone()).await;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    assert!(response.is_ok());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let pre_mint = PreMintSecrets::random(active_keyset_id, 101.into(), &SplitTarget::None)?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let swap_request = SwapRequest {
 | 
	
		
			
				|  |  | +        inputs: proofs.clone(),
 | 
	
		
			
				|  |  | +        outputs: pre_mint.blinded_messages(),
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let http_client = HttpClient::new(MINT_URL.parse()?);
 | 
	
		
			
				|  |  | +    let response = http_client.post_swap(swap_request.clone()).await;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    match response {
 | 
	
		
			
				|  |  | +        Err(err) => match err {
 | 
	
		
			
				|  |  | +            cdk::Error::TokenAlreadySpent => (),
 | 
	
		
			
				|  |  | +            err => {
 | 
	
		
			
				|  |  | +                bail!("Wrong mint error returned: {}", err.to_string());
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        },
 | 
	
		
			
				|  |  | +        Ok(_) => {
 | 
	
		
			
				|  |  | +            bail!("Should not have allowed to mint with multiple units");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let input_amount: u64 = proofs.total_amount()?.into();
 | 
	
		
			
				|  |  | +    let invoice = create_fake_invoice((input_amount - 1) * 1000, "".to_string());
 | 
	
		
			
				|  |  | +    let melt_quote = wallet.melt_quote(invoice.to_string(), None).await?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let melt_request = MeltBolt11Request {
 | 
	
		
			
				|  |  | +        quote: melt_quote.id,
 | 
	
		
			
				|  |  | +        inputs: proofs,
 | 
	
		
			
				|  |  | +        outputs: None,
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let http_client = HttpClient::new(MINT_URL.parse()?);
 | 
	
		
			
				|  |  | +    let response = http_client.post_melt(melt_request.clone()).await;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    match response {
 | 
	
		
			
				|  |  | +        Err(err) => match err {
 | 
	
		
			
				|  |  | +            cdk::Error::TokenAlreadySpent => (),
 | 
	
		
			
				|  |  | +            err => {
 | 
	
		
			
				|  |  | +                bail!("Wrong mint error returned: {}", err.to_string());
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        },
 | 
	
		
			
				|  |  | +        Ok(_) => {
 | 
	
		
			
				|  |  | +            bail!("Should not have allowed to melt with multiple units");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Ok(())
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /// Test swap where input unit != output unit
 | 
	
		
			
				|  |  |  #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
 | 
	
		
			
				|  |  |  async fn test_fake_mint_duplicate_proofs_swap() -> Result<()> {
 |