mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-29 10:35:14 +01:00
mint tests
This commit is contained in:
@@ -9,6 +9,7 @@ bitcoin_hashes = "0.12.0"
|
||||
hex = "0.4.3"
|
||||
lightning-invoice = { version = "0.22.0", features=["serde"] }
|
||||
minreq = { version = "2.7.0", features = ["json-using-serde", "https"] }
|
||||
rand = "0.8.5"
|
||||
secp256k1 = { version = "0.27.0", features = ["rand-std", "bitcoin-hashes-std"] }
|
||||
serde = { version = "1.0.160", features = ["derive"]}
|
||||
thiserror = "1.0.40"
|
||||
|
||||
@@ -5,9 +5,10 @@ use url::Url;
|
||||
use crate::{
|
||||
error::Error,
|
||||
types::{
|
||||
BlindedMessage, CheckFeesRequest, CheckFeesResponse, CheckSpendableRequest,
|
||||
CheckSpendableResponse, MeltRequest, MeltResposne, MintInfo, MintKeySets, MintKeys,
|
||||
MintRequest, PostMintResponse, Proof, RequestMintResponse, SplitRequest, SplitResponse,
|
||||
BlindedMessage, BlindedMessages, CheckFeesRequest, CheckFeesResponse,
|
||||
CheckSpendableRequest, CheckSpendableResponse, MeltRequest, MeltResposne, MintInfo,
|
||||
MintKeySets, MintKeys, MintRequest, PostMintResponse, Proof, RequestMintResponse,
|
||||
SplitRequest, SplitResponse,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -45,7 +46,7 @@ impl CashuMint {
|
||||
/// Mint Tokens [NUT-04]
|
||||
pub async fn mint(
|
||||
&self,
|
||||
blinded_messages: Vec<BlindedMessage>,
|
||||
blinded_messages: BlindedMessages,
|
||||
payment_hash: &str,
|
||||
) -> Result<PostMintResponse, Error> {
|
||||
let mut url = self.url.join("mint")?;
|
||||
@@ -53,7 +54,7 @@ impl CashuMint {
|
||||
.append_pair("payment_hash", payment_hash);
|
||||
|
||||
let request = MintRequest {
|
||||
outputs: blinded_messages,
|
||||
outputs: blinded_messages.blinded_messages,
|
||||
};
|
||||
|
||||
Ok(minreq::post(url)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
//! Diffie-Hellmann key exchange
|
||||
|
||||
use bitcoin_hashes::sha256;
|
||||
// use bitcoin_hashes::Hash;
|
||||
use bitcoin_hashes::Hash;
|
||||
use secp256k1::rand::rngs::OsRng;
|
||||
use secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey};
|
||||
|
||||
@@ -2,3 +2,4 @@ pub mod cashu_mint;
|
||||
pub mod dhke;
|
||||
pub mod error;
|
||||
pub mod types;
|
||||
pub mod utils;
|
||||
|
||||
40
src/types.rs
40
src/types.rs
@@ -4,8 +4,12 @@ use std::collections::HashMap;
|
||||
|
||||
use bitcoin::Amount;
|
||||
use lightning_invoice::Invoice;
|
||||
use rand::Rng;
|
||||
use secp256k1::{PublicKey, SecretKey};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::{dhke::blind_message, error::Error, utils::split_amount};
|
||||
|
||||
/// Blinded Message [NUT-00]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BlindedMessage {
|
||||
@@ -14,7 +18,41 @@ pub struct BlindedMessage {
|
||||
pub amount: Amount,
|
||||
/// encrypted secret message (B_)
|
||||
#[serde(rename = "B_")]
|
||||
pub b: String,
|
||||
pub b: PublicKey,
|
||||
}
|
||||
|
||||
/// Blinded Messages [NUT-00]
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct BlindedMessages {
|
||||
/// Blinded messages
|
||||
pub blinded_messages: Vec<BlindedMessage>,
|
||||
/// Secrets
|
||||
pub secrets: Vec<Vec<u8>>,
|
||||
/// Rs
|
||||
pub rs: Vec<SecretKey>,
|
||||
/// Amounts
|
||||
pub amounts: Vec<Amount>,
|
||||
}
|
||||
|
||||
impl BlindedMessages {
|
||||
pub fn random(amount: Amount) -> Result<Self, Error> {
|
||||
let mut blinded_messages = BlindedMessages::default();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
for amount in split_amount(amount) {
|
||||
let bytes: [u8; 32] = rng.gen();
|
||||
let (blinded, r) = blind_message(&bytes, None)?;
|
||||
|
||||
let blinded_message = BlindedMessage { amount, b: blinded };
|
||||
|
||||
blinded_messages.secrets.push(bytes.to_vec());
|
||||
blinded_messages.blinded_messages.push(blinded_message);
|
||||
blinded_messages.rs.push(r);
|
||||
blinded_messages.amounts.push(amount);
|
||||
}
|
||||
|
||||
Ok(blinded_messages)
|
||||
}
|
||||
}
|
||||
|
||||
/// Promise (BlindedSignature) [NIP-00]
|
||||
|
||||
36
src/utils.rs
Normal file
36
src/utils.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use bitcoin::Amount;
|
||||
|
||||
/// Split amount into cashu denominations (powers of 2)
|
||||
pub fn split_amount(amount: Amount) -> Vec<Amount> {
|
||||
let mut chunks = Vec::new();
|
||||
let value = amount.to_sat();
|
||||
for i in 0..64 {
|
||||
let mask = 1 << i;
|
||||
if (value & mask) != 0 {
|
||||
chunks.push(Amount::from_sat(2u64.pow(i as u32)));
|
||||
}
|
||||
}
|
||||
chunks
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_split_amount() {
|
||||
assert_eq!(split_amount(Amount::from_sat(1)), vec![Amount::from_sat(1)]);
|
||||
assert_eq!(split_amount(Amount::from_sat(2)), vec![Amount::from_sat(2)]);
|
||||
assert_eq!(
|
||||
split_amount(Amount::from_sat(3)),
|
||||
vec![Amount::from_sat(1), Amount::from_sat(2)]
|
||||
);
|
||||
let amounts: Vec<Amount> = vec![1, 2, 8].iter().map(|a| Amount::from_sat(*a)).collect();
|
||||
assert_eq!(split_amount(Amount::from_sat(11)), amounts);
|
||||
let amounts: Vec<Amount> = vec![1, 2, 4, 8, 16, 32, 64, 128]
|
||||
.iter()
|
||||
.map(|a| Amount::from_sat(*a))
|
||||
.collect();
|
||||
assert_eq!(split_amount(Amount::from_sat(255)), amounts);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
use std::str::FromStr;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use bitcoin::Amount;
|
||||
use lightning_invoice::Invoice;
|
||||
use url::Url;
|
||||
|
||||
use cashu_rs::cashu_mint::CashuMint;
|
||||
use cashu_rs::{cashu_mint::CashuMint, types::BlindedMessages};
|
||||
|
||||
const MINTURL: &str = "https://legend.lnbits.com/cashu/api/v1/SKvHRus9dmjWHhstHrsazW/";
|
||||
|
||||
@@ -36,6 +38,24 @@ async fn test_request_mint() {
|
||||
assert!(mint.pr.check_signature().is_ok())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mint() {
|
||||
let url = Url::from_str(MINTURL).unwrap();
|
||||
let mint = CashuMint::new(url);
|
||||
let mint_req = mint.request_mint(Amount::from_sat(21)).await.unwrap();
|
||||
println!("Mint Req: {:?}", mint_req.pr.to_string());
|
||||
|
||||
// Since before the mind happens the invoice in the int req has to be payed this wait is here
|
||||
// probally some way to simulate this in a better way
|
||||
// but for now pay it quick
|
||||
thread::sleep(Duration::from_secs(10));
|
||||
|
||||
let blinded_messages = BlindedMessages::random(Amount::from_sat(21)).unwrap();
|
||||
let mint_res = mint.mint(blinded_messages, &mint_req.hash).await.unwrap();
|
||||
|
||||
println!("Mint: {:?}", mint_res);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_check_fees() {
|
||||
let invoice = Invoice::from_str("lnbc10n1p3a6s0dsp5n55r506t2fv4r0mjcg30v569nk2u9s40ur4v3r3mgtscjvkvnrqqpp5lzfv8fmjzduelk74y9rsrxrayvhyzcdsh3zkdgv0g50napzalvqsdqhf9h8vmmfvdjn5gp58qengdqxq8p3aaymdcqpjrzjqwryaup9lh50kkranzgcdnn2fgvx390wgj5jd07rwr3vxeje0glc7z70cgqqg4sqqqqqqqlgqqqqrucqjq9qyysgqrjky5axsldzhqsjwsc38xa37k6t04le3ws4t26nqej62vst5xkz56qw85r6c4a3tr79588e0ceuuahwgfnkqc6n6269unlwqtvwr5vqqy0ncdq").unwrap();
|
||||
|
||||
Reference in New Issue
Block a user