Skip to content

Commit

Permalink
feat: nut19 signature on mint witness
Browse files Browse the repository at this point in the history
  • Loading branch information
thesimplekid committed Nov 8, 2024
1 parent 0523892 commit 9e662ba
Show file tree
Hide file tree
Showing 24 changed files with 315 additions and 60 deletions.
12 changes: 10 additions & 2 deletions bindings/cdk-js/src/nuts/nut04.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,18 @@ impl From<MintBolt11Request> for JsMintBolt11Request {
impl JsMintBolt11Request {
/// Try From Base 64 String
#[wasm_bindgen(constructor)]
pub fn new(quote: String, outputs: JsValue) -> Result<JsMintBolt11Request> {
pub fn new(
quote: String,
outputs: JsValue,
witness: Option<String>,
) -> Result<JsMintBolt11Request> {
let outputs = serde_wasm_bindgen::from_value(outputs).map_err(into_err)?;
Ok(JsMintBolt11Request {
inner: MintBolt11Request { quote, outputs },
inner: MintBolt11Request {
quote,
outputs,
witness,
},
})
}

Expand Down
6 changes: 4 additions & 2 deletions crates/cdk-cli/src/sub_commands/mint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub async fn mint(
};

let quote = wallet
.mint_quote(Amount::from(sub_command_args.amount), description)
.mint_quote(Amount::from(sub_command_args.amount), description, None)
.await?;

println!("Quote: {:#?}", quote);
Expand All @@ -69,7 +69,9 @@ pub async fn mint(
sleep(Duration::from_secs(2)).await;
}

let receive_amount = wallet.mint(&quote.id, SplitTarget::default(), None).await?;
let receive_amount = wallet
.mint(&quote.id, SplitTarget::default(), None, None)
.await?;

println!("Received {receive_amount} from mint {mint_url}");

Expand Down
6 changes: 4 additions & 2 deletions crates/cdk-integration-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ pub async fn wallet_mint(
split_target: SplitTarget,
description: Option<String>,
) -> Result<()> {
let quote = wallet.mint_quote(amount, description).await?;
let quote = wallet.mint_quote(amount, description, None).await?;

loop {
let status = wallet.mint_quote_state(&quote.id).await?;
Expand All @@ -138,7 +138,7 @@ pub async fn wallet_mint(
sleep(Duration::from_secs(2)).await;
}

let receive_amount = wallet.mint(&quote.id, split_target, None).await?;
let receive_amount = wallet.mint(&quote.id, split_target, None, None).await?;

println!("Minted: {}", receive_amount);

Expand All @@ -161,6 +161,7 @@ pub async fn mint_proofs(
amount,
unit: CurrencyUnit::Sat,
description,
pubkey: None,
};

let mint_quote = wallet_client
Expand All @@ -187,6 +188,7 @@ pub async fn mint_proofs(
let request = MintBolt11Request {
quote: mint_quote.quote,
outputs: premint_secrets.blinded_messages(),
witness: None,
};

let mint_response = wallet_client.post_mint(mint_url.parse()?, request).await?;
Expand Down
114 changes: 98 additions & 16 deletions crates/cdk-integration-tests/tests/fake_wallet.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use std::{sync::Arc, time::Duration};

use anyhow::Result;
use anyhow::{bail, Result};
use bip39::Mnemonic;
use cdk::{
amount::SplitTarget,
cdk_database::WalletMemoryDatabase,
nuts::{
CurrencyUnit, MeltBolt11Request, MeltQuoteState, MintQuoteState, PreMintSecrets, State,
CurrencyUnit, MeltBolt11Request, MeltQuoteState, MintQuoteState, PreMintSecrets, SecretKey,
State,
},
wallet::{
client::{HttpClient, HttpClientMethods},
Expand All @@ -30,12 +31,12 @@ async fn test_fake_tokens_pending() -> Result<()> {
None,
)?;

let mint_quote = wallet.mint_quote(100.into(), None).await?;
let mint_quote = wallet.mint_quote(100.into(), None, None).await?;

wait_for_mint_to_be_paid(&wallet, &mint_quote.id).await?;

let _mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await?;

let fake_description = FakeInvoiceDescription {
Expand Down Expand Up @@ -70,12 +71,12 @@ async fn test_fake_melt_payment_fail() -> Result<()> {
None,
)?;

let mint_quote = wallet.mint_quote(100.into(), None).await?;
let mint_quote = wallet.mint_quote(100.into(), None, None).await?;

wait_for_mint_to_be_paid(&wallet, &mint_quote.id).await?;

let _mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await?;

let fake_description = FakeInvoiceDescription {
Expand Down Expand Up @@ -133,12 +134,12 @@ async fn test_fake_melt_payment_fail_and_check() -> Result<()> {
None,
)?;

let mint_quote = wallet.mint_quote(100.into(), None).await?;
let mint_quote = wallet.mint_quote(100.into(), None, None).await?;

wait_for_mint_to_be_paid(&wallet, &mint_quote.id).await?;

let _mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await?;

let fake_description = FakeInvoiceDescription {
Expand Down Expand Up @@ -178,12 +179,12 @@ async fn test_fake_melt_payment_return_fail_status() -> Result<()> {
None,
)?;

let mint_quote = wallet.mint_quote(100.into(), None).await?;
let mint_quote = wallet.mint_quote(100.into(), None, None).await?;

wait_for_mint_to_be_paid(&wallet, &mint_quote.id).await?;

let _mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await?;

let fake_description = FakeInvoiceDescription {
Expand Down Expand Up @@ -238,12 +239,12 @@ async fn test_fake_melt_payment_error_unknown() -> Result<()> {
None,
)?;

let mint_quote = wallet.mint_quote(100.into(), None).await?;
let mint_quote = wallet.mint_quote(100.into(), None, None).await?;

wait_for_mint_to_be_paid(&wallet, &mint_quote.id).await?;

let _mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await?;

let fake_description = FakeInvoiceDescription {
Expand Down Expand Up @@ -299,12 +300,12 @@ async fn test_fake_melt_payment_err_paid() -> Result<()> {
None,
)?;

let mint_quote = wallet.mint_quote(100.into(), None).await?;
let mint_quote = wallet.mint_quote(100.into(), None, None).await?;

wait_for_mint_to_be_paid(&wallet, &mint_quote.id).await?;

let _mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await?;

let fake_description = FakeInvoiceDescription {
Expand Down Expand Up @@ -337,12 +338,12 @@ async fn test_fake_melt_change_in_quote() -> Result<()> {
None,
)?;

let mint_quote = wallet.mint_quote(100.into(), None).await?;
let mint_quote = wallet.mint_quote(100.into(), None, None).await?;

wait_for_mint_to_be_paid(&wallet, &mint_quote.id).await?;

let _mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await?;

let fake_description = FakeInvoiceDescription::default();
Expand Down Expand Up @@ -380,6 +381,87 @@ async fn test_fake_melt_change_in_quote() -> Result<()> {
Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn test_fake_mint_with_witness() -> Result<()> {
let wallet = Wallet::new(
MINT_URL,
CurrencyUnit::Sat,
Arc::new(WalletMemoryDatabase::default()),
&Mnemonic::generate(12)?.to_seed_normalized(""),
None,
)?;
let secret = SecretKey::generate();
let mint_quote = wallet
.mint_quote(100.into(), None, Some(secret.public_key()))
.await?;

wait_for_mint_to_be_paid(&wallet, &mint_quote.id).await?;

let mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None, Some(secret))
.await?;

assert!(mint_amount == 100.into());

Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn test_fake_mint_without_witness() -> Result<()> {
let wallet = Wallet::new(
MINT_URL,
CurrencyUnit::Sat,
Arc::new(WalletMemoryDatabase::default()),
&Mnemonic::generate(12)?.to_seed_normalized(""),
None,
)?;

let secret = SecretKey::generate();
let mint_quote = wallet
.mint_quote(100.into(), None, Some(secret.public_key()))
.await?;

wait_for_mint_to_be_paid(&wallet, &mint_quote.id).await?;

let mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await;

match mint_amount {
Err(cdk::error::Error::SecretKeyNotProvided) => Ok(()),
_ => bail!("Wrong mint response for minting without witness"),
}
}

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn test_fake_mint_with_wrong_witness() -> Result<()> {
let wallet = Wallet::new(
MINT_URL,
CurrencyUnit::Sat,
Arc::new(WalletMemoryDatabase::default()),
&Mnemonic::generate(12)?.to_seed_normalized(""),
None,
)?;
let secret = SecretKey::generate();
let mint_quote = wallet
.mint_quote(100.into(), None, Some(secret.public_key()))
.await?;

wait_for_mint_to_be_paid(&wallet, &mint_quote.id).await?;
let secret = SecretKey::generate();

let mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None, Some(secret))
.await;

match mint_amount {
Err(cdk::error::Error::IncorrectSecretKey) => Ok(()),
_ => {
bail!("Wrong mint response for minting without 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<()> {
loop {
Expand Down
27 changes: 14 additions & 13 deletions crates/cdk-integration-tests/tests/regtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ async fn test_regtest_mint_melt_round_trip() -> Result<()> {
.expect("Failed to connect");
let (mut write, mut reader) = ws_stream.split();

let mint_quote = wallet.mint_quote(100.into(), None).await?;
let mint_quote = wallet.mint_quote(100.into(), None, None).await?;

lnd_client.pay_invoice(mint_quote.request).await?;

let mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await?;

assert!(mint_amount == 100.into());
Expand Down Expand Up @@ -139,14 +139,14 @@ async fn test_regtest_mint_melt() -> Result<()> {

let mint_amount = Amount::from(100);

let mint_quote = wallet.mint_quote(mint_amount, None).await?;
let mint_quote = wallet.mint_quote(mint_amount, None, None).await?;

assert_eq!(mint_quote.amount, mint_amount);

lnd_client.pay_invoice(mint_quote.request).await?;

let mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await?;

assert!(mint_amount == 100.into());
Expand All @@ -167,12 +167,12 @@ async fn test_restore() -> Result<()> {
None,
)?;

let mint_quote = wallet.mint_quote(100.into(), None).await?;
let mint_quote = wallet.mint_quote(100.into(), None, None).await?;

lnd_client.pay_invoice(mint_quote.request).await?;

let _mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await?;

assert!(wallet.total_balance().await? == 100.into());
Expand Down Expand Up @@ -223,12 +223,12 @@ async fn test_pay_invoice_twice() -> Result<()> {
None,
)?;

let mint_quote = wallet.mint_quote(100.into(), None).await?;
let mint_quote = wallet.mint_quote(100.into(), None, None).await?;

lnd_client.pay_invoice(mint_quote.request).await?;

let mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await?;

assert_eq!(mint_amount, 100.into());
Expand Down Expand Up @@ -275,12 +275,12 @@ async fn test_internal_payment() -> Result<()> {
None,
)?;

let mint_quote = wallet.mint_quote(100.into(), None).await?;
let mint_quote = wallet.mint_quote(100.into(), None, None).await?;

lnd_client.pay_invoice(mint_quote.request).await?;

let _mint_amount = wallet
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await?;

assert!(wallet.total_balance().await? == 100.into());
Expand All @@ -295,7 +295,7 @@ async fn test_internal_payment() -> Result<()> {
None,
)?;

let mint_quote = wallet_2.mint_quote(10.into(), None).await?;
let mint_quote = wallet_2.mint_quote(10.into(), None, None).await?;

let melt = wallet.melt_quote(mint_quote.request.clone(), None).await?;

Expand All @@ -304,7 +304,7 @@ async fn test_internal_payment() -> Result<()> {
let _melted = wallet.melt(&melt.id).await.unwrap();

let _wallet_2_mint = wallet_2
.mint(&mint_quote.id, SplitTarget::default(), None)
.mint(&mint_quote.id, SplitTarget::default(), None, None)
.await
.unwrap();

Expand Down Expand Up @@ -346,7 +346,7 @@ async fn test_cached_mint() -> Result<()> {

let mint_amount = Amount::from(100);

let quote = wallet.mint_quote(mint_amount, None).await?;
let quote = wallet.mint_quote(mint_amount, None, None).await?;
lnd_client.pay_invoice(quote.request).await?;

loop {
Expand All @@ -369,6 +369,7 @@ async fn test_cached_mint() -> Result<()> {
let request = MintBolt11Request {
quote: quote.id,
outputs: premint_secrets.blinded_messages(),
witness: None,
};

let response = http_client
Expand Down
Loading

0 comments on commit 9e662ba

Please sign in to comment.