diff --git a/examples/uma-demo/src/config.rs b/examples/uma-demo/src/config.rs index e5e37b4..61c5a99 100644 --- a/examples/uma-demo/src/config.rs +++ b/examples/uma-demo/src/config.rs @@ -1,2 +1,40 @@ #[derive(Debug, Clone)] -pub struct Config {} +pub struct Config { + pub api_client_id: String, + pub api_client_secret: String, + pub node_id: String, + pub username: String, + pub user_id: String, + pub uma_encryption_private_key_hex: String, + pub uma_signing_private_key_hex: String, + pub node_master_seed_hex: String, + pub client_base_url: String, +} + +impl Config { + pub fn new_from_env() -> Self { + let api_endpoint = std::env::var("LIGHTSPARK_API_ENDPOINT").ok(); + let api_client_id = std::env::var("LIGHTSPARK_API_CLIENT_ID").ok(); + let api_client_secret = std::env::var("LIGHTSPARK_API_CLIENT_SECRET").ok(); + let master_seed_hex = std::env::var("LIGHTSPARK_MASTER_SEED_HEX").ok(); + let node_id = std::env::var("LIGHTSPARK_NODE_ID").ok(); + let username = std::env::var("LIGHTSPARK_USERNAME").ok(); + let user_id = std::env::var("LIGHTSPARK_USER_ID").ok(); + let uma_encryption_private_key_hex = + std::env::var("LIGHTSPARK_UMA_ENCRYPTION_PRIVATE_KEY_HEX").ok(); + let uma_signing_private_key_hex = + std::env::var("LIGHTSPARK_UMA_SIGNING_PRIVATE_KEY_HEX").ok(); + + Config { + api_client_id: api_client_id.unwrap_or_default(), + api_client_secret: api_client_secret.unwrap_or_default(), + node_id: node_id.unwrap_or_default(), + username: username.unwrap_or_default(), + user_id: user_id.unwrap_or_default(), + uma_encryption_private_key_hex: uma_encryption_private_key_hex.unwrap_or_default(), + uma_signing_private_key_hex: uma_signing_private_key_hex.unwrap_or_default(), + node_master_seed_hex: master_seed_hex.unwrap_or_default(), + client_base_url: api_endpoint.unwrap_or_default(), + } + } +} diff --git a/examples/uma-demo/src/main.rs b/examples/uma-demo/src/main.rs index 22b0531..929a287 100644 --- a/examples/uma-demo/src/main.rs +++ b/examples/uma-demo/src/main.rs @@ -48,7 +48,7 @@ async fn main() -> std::io::Result<()> { HttpServer::new(move || { App::new() .app_data(web::Data::new(VASP { - config: config::Config {}, + config: config::Config::new_from_env(), })) .service(uma_lookup) .service(client_payreq) @@ -57,7 +57,7 @@ async fn main() -> std::io::Result<()> { .service(lnurl_payreq) .service(uma_payreq) }) - .bind(("127.0.0.1", port))? + .bind(("0.0.0.0", port))? .run() .await } diff --git a/lightspark-remote-signing/CHANGELOG.md b/lightspark-remote-signing/CHANGELOG.md index 2d10669..47ee6b0 100644 --- a/lightspark-remote-signing/CHANGELOG.md +++ b/lightspark-remote-signing/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## v0.2.1 +- Remove is_raw field for derive_key_and_sign. + ## v0.2.0 - Remove unnecessary lightspark dependencies. - Expose lightspark crates. diff --git a/lightspark-remote-signing/Cargo.toml b/lightspark-remote-signing/Cargo.toml index 04e4977..6d14071 100644 --- a/lightspark-remote-signing/Cargo.toml +++ b/lightspark-remote-signing/Cargo.toml @@ -2,7 +2,7 @@ name = "lightspark-remote-signing" description = "Lightspark Remote Signing SDK for Rust" authors = ["Lightspark Group, Inc. "] -version = "0.2.0" +version = "0.2.1" edition = "2021" documentation = "https://app.lightspark.com/docs/" homepage = "https://www.lightspark.com/" diff --git a/lightspark-remote-signing/src/handler.rs b/lightspark-remote-signing/src/handler.rs index 1f71834..7b5a462 100644 --- a/lightspark-remote-signing/src/handler.rs +++ b/lightspark-remote-signing/src/handler.rs @@ -224,7 +224,6 @@ impl Handler { .derive_key_and_sign( hex::decode(signing_job.message).map_err(|_| Error::HexEncodingError)?, signing_job.derivation_path, - signing_job.is_raw, signing_job .add_tweak .map(|tweak| hex::decode(tweak).map_err(|_| Error::HexEncodingError)) @@ -252,5 +251,4 @@ struct SigningJob { message: String, add_tweak: Option, mul_tweak: Option, - is_raw: bool, } diff --git a/lightspark-remote-signing/src/signer.rs b/lightspark-remote-signing/src/signer.rs index 8ace8cf..b94850b 100644 --- a/lightspark-remote-signing/src/signer.rs +++ b/lightspark-remote-signing/src/signer.rs @@ -6,7 +6,6 @@ use std::str::FromStr; use bitcoin::bip32::{DerivationPath, ExtendedPrivKey, ExtendedPubKey}; use bitcoin::hashes::{sha512, Hash, HashEngine, Hmac, HmacEngine}; use bitcoin::secp256k1::ecdh::SharedSecret; -use bitcoin::secp256k1::ecdsa::Signature; use bitcoin::secp256k1::hashes::sha256; use bitcoin::secp256k1::{Message, PublicKey, Scalar, Secp256k1, SecretKey}; use rand_core::{OsRng, RngCore}; @@ -161,23 +160,13 @@ impl LightsparkSigner { &self, message: Vec, derivation_path: String, - is_raw: bool, add_tweak: Option>, mul_tweak: Option>, ) -> Result, Error> { let secp = Secp256k1::new(); let signing_key = self.derive_and_tweak_key(derivation_path, add_tweak, mul_tweak)?; - let signature: Signature = match is_raw { - true => { - let msg = Message::from_slice(message.as_slice()).map_err(Error::Secp256k1Error)?; - secp.sign_ecdsa(&msg, &signing_key) - } - false => { - let msg = Message::from_hashed_data::(message.as_slice()); - secp.sign_ecdsa(&msg, &signing_key) - } - }; - + let msg = Message::from_slice(message.as_slice()).map_err(Error::Secp256k1Error)?; + let signature = secp.sign_ecdsa(&msg, &signing_key); Ok(signature.serialize_compact().to_vec()) } @@ -342,6 +331,7 @@ impl LightsparkSigner { #[cfg(test)] mod tests { use super::*; + use bitcoin::secp256k1::ecdsa::Signature; use hex; #[test] @@ -397,8 +387,9 @@ mod tests { .public_key; let message = b"Hello, world!"; + let hash = sha256::Hash::hash(message); let signature_bytes = signer - .derive_key_and_sign(message.to_vec(), "m".to_owned(), false, None, None) + .derive_key_and_sign(hash.to_byte_array().to_vec(), "m".to_owned(), None, None) .unwrap(); let signature = Signature::from_compact(signature_bytes.as_slice()).unwrap(); let msg = Message::from_hashed_data::(message); @@ -525,7 +516,7 @@ mod tests { let signer = LightsparkSigner::new(&seed, Network::Bitcoin).unwrap(); let signature_bytes = signer - .derive_key_and_sign(msg.clone(), "m/3/2106220917/0".to_owned(), true, None, None) + .derive_key_and_sign(msg.clone(), "m/3/2106220917/0".to_owned(), None, None) .unwrap(); let pubkey = signer .derive_public_key("m/3/2106220917/0".to_owned()) diff --git a/lightspark/CHANGELOG.md b/lightspark/CHANGELOG.md index f49b515..3538de8 100644 --- a/lightspark/CHANGELOG.md +++ b/lightspark/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +# v0.7.1 +- Add UMA related operations in LightsparkClient. + # v0.7.0 - Refine requester. - Separate crate into features. diff --git a/lightspark/Cargo.toml b/lightspark/Cargo.toml index bc976e9..dacdf59 100644 --- a/lightspark/Cargo.toml +++ b/lightspark/Cargo.toml @@ -2,7 +2,7 @@ name = "lightspark" description = "Lightspark Rust SDK" authors = ["Lightspark Group, Inc. "] -version = "0.7.0" +version = "0.7.1" edition = "2021" documentation = "https://app.lightspark.com/docs/sdk" homepage = "https://www.lightspark.com/" diff --git a/lightspark/README.md b/lightspark/README.md index 9a0d6be..3b6cb02 100644 --- a/lightspark/README.md +++ b/lightspark/README.md @@ -1,8 +1,8 @@ -# Lightspark Rust SDK - v0.7.0 +# Lightspark Rust SDK - v0.7.1 The Lightspark Rust SDK provides a convenient way to interact with the Lightspark services from applications written in the Rust language. -***WARNING: This SDK is in version 0.7.0 (active development). It means that its APIs may not be fully stable. Please expect that changes to the APIs may happen until we move to v1.0.0.*** +***WARNING: This SDK is in version 0.7.1 (active development). It means that its APIs may not be fully stable. Please expect that changes to the APIs may happen until we move to v1.0.0.*** ## Documentation diff --git a/lightspark/examples/rk_test.rs b/lightspark/examples/rk_test.rs index 7335f96..aea1b1c 100644 --- a/lightspark/examples/rk_test.rs +++ b/lightspark/examples/rk_test.rs @@ -66,7 +66,7 @@ async fn test_payment() { let invoice = client .create_test_mode_invoice(&node_id, 10000, Some("test"), None) .await; - let payment_request = invoice.unwrap().replace("\"", ""); + let payment_request = invoice.unwrap().replace('\"', ""); println!("Invoice created: {:?}", payment_request); let response = client diff --git a/lightspark/src/client.rs b/lightspark/src/client.rs index 07c7b4d..ab8c1b8 100644 --- a/lightspark/src/client.rs +++ b/lightspark/src/client.rs @@ -13,6 +13,7 @@ use crate::error::Error; use crate::key::OperationSigningKey; use crate::objects::account::Account; use crate::objects::api_token::ApiToken; +use crate::objects::compliance_provider::ComplianceProvider; use crate::objects::currency_amount::{self, CurrencyAmount}; use crate::objects::fee_estimate::FeeEstimate; use crate::objects::incoming_payment::IncomingPayment; @@ -23,6 +24,7 @@ use crate::objects::invoice_type::InvoiceType; use crate::objects::lightning_fee_estimate_output::LightningFeeEstimateOutput; use crate::objects::outgoing_payment::OutgoingPayment; use crate::objects::permission::Permission; +use crate::objects::risk_rating::RiskRating; use crate::objects::withdrawal_mode::WithdrawalMode; use crate::objects::withdrawal_request::WithdrawalRequest; use crate::objects::{account, invoice_data}; @@ -820,4 +822,147 @@ impl LightsparkClient { .map_err(Error::JsonError)?; Ok(result) } + + pub async fn create_uma_invoice( + &self, + node_id: &str, + amount_msats: i64, + metadata: &str, + expiry_secs: Option, + ) -> Result { + let mutation = format!( + "mutation CreateUmaInvoice( + $node_id: ID! + $amount_msats: Long! + $metadata_hash: String! + $expiry_secs: Int + ) {{ + create_uma_invoice(input: {{ + node_id: $node_id + amount_msats: $amount_msats + metadata_hash: $metadata_hash + expiry_secs: $expiry_secs + }}) {{ + invoice {{ + ...InvoiceFragment + }} + }} + }} + + {} + ", + invoice::FRAGMENT + ); + + let mut hasher = Sha256::new(); + hasher.update(metadata.as_bytes()); + + let metadata_hash = hex::encode(hasher.finalize()); + + let mut variables: HashMap<&str, Value> = HashMap::new(); + variables.insert("node_id", node_id.into()); + variables.insert("amount_msats", amount_msats.into()); + variables.insert("metadata_hash", metadata_hash.into()); + if let Some(expiry_secs) = expiry_secs { + variables.insert("expiry_secs", expiry_secs.into()); + } + + let value = serde_json::to_value(variables).map_err(Error::ConversionError)?; + let json = self + .requester + .execute_graphql(&mutation, Some(value)) + .await?; + + let result = serde_json::from_value(json["create_uma_invoice"]["invoice"].clone()) + .map_err(Error::JsonError)?; + Ok(result) + } + + pub async fn pay_uma_invoice( + &self, + node_id: &str, + encoded_invoice: &str, + timeout_secs: i32, + maximum_fees_msats: i64, + amount_msats: Option, + ) -> Result { + let operation = format!( + "mutation PayUmaInvoice( + $node_id: ID! + $encoded_invoice: String! + $timeout_secs: Int! + $maximum_fees_msats: Long! + $amount_msats: Long + ) {{ + pay_uma_invoice(input: {{ + node_id: $node_id + encoded_invoice: $encoded_invoice + timeout_secs: $timeout_secs + maximum_fees_msats: $maximum_fees_msats + amount_msats: $amount_msats + }}) {{ + payment {{ + ...OutgoingPaymentFragment + }} + }} + }} + + {} + ", + outgoing_payment::FRAGMENT + ); + + let mut variables: HashMap<&str, Value> = HashMap::new(); + variables.insert("node_id", node_id.into()); + variables.insert("encoded_invoice", encoded_invoice.into()); + if let Some(amount_msats) = amount_msats { + variables.insert("amount_msats", amount_msats.into()); + } + variables.insert("timeout_secs", timeout_secs.into()); + variables.insert("maximum_fees_msats", maximum_fees_msats.into()); + + let value = serde_json::to_value(variables).map_err(Error::ConversionError)?; + + let signing_key = self.get_node_signing_key(node_id)?; + let json = self + .requester + .execute_graphql_signing(&operation, Some(value), Some(signing_key)) + .await?; + + let result = serde_json::from_value(json["pay_uma_invoice"]["payment"].clone()) + .map_err(Error::JsonError)?; + Ok(result) + } + + pub async fn screen_node( + &self, + provider: ComplianceProvider, + destination_node_public_key: &str, + ) -> Result { + let operation = "mutation ScreenNode( + $provider: ComplianceProvider! + $node_pubkey: String! + ) { + screen_node(input: { + provider: $provider + node_pubkey: $node_pubkey + }) { + rating + } + }"; + + let mut variables: HashMap<&str, Value> = HashMap::new(); + variables.insert("provider", provider.into()); + variables.insert("node_pubkey", destination_node_public_key.into()); + + let value = serde_json::to_value(variables).map_err(Error::ConversionError)?; + let json = self + .requester + .execute_graphql(operation, Some(value)) + .await?; + + let result = serde_json::from_value(json["screen_node"]["rating"].clone()) + .map_err(Error::JsonError)?; + Ok(result) + } } diff --git a/lightspark/src/lib.rs b/lightspark/src/lib.rs index cd7924f..3509056 100644 --- a/lightspark/src/lib.rs +++ b/lightspark/src/lib.rs @@ -28,7 +28,7 @@ //! See more examples in examples/example.rs //! /// The version of this library. -pub const VERSION: &str = "0.7.0"; +pub const VERSION: &str = "0.7.1"; #[cfg(feature = "client")] pub mod client;