]> Untitled Git - bdk-cli/commitdiff
bip322: update proof handling for new bdk-bip322 API
authoraagbotemi <aabiodunawoyemi@gmail.com>
Sat, 26 Apr 2025 12:07:37 +0000 (13:07 +0100)
committerAbiodun Awoyemi <aabiodunawoyemi@gmail.com>
Fri, 17 Apr 2026 13:14:52 +0000 (14:14 +0100)
.github/workflows/audit.yml
Cargo.lock
Cargo.toml
src/commands.rs
src/handlers.rs
src/utils.rs

index 93806d533f8b09f03866c95979cd6fbb389276f1..d5f42ddafa9cdf26d98307e79a960df79189e016 100644 (file)
@@ -3,10 +3,17 @@ name: Audit
 on:
   push:
     paths:
+      # Run if workflow changes
+      - '.github/workflows/audit.yml'
+      # Run on changed dependencies
       - '**/Cargo.toml'
       - '**/Cargo.lock'
+      # Run if the configuration file changes
+      - '**/audit.toml'
   schedule:
     - cron: '0 0 * * 0' # Once per week
+  # Run manually
+  workflow_dispatch:
 
 jobs:
 
index b491c2e6af447c32adcf4124b3c66111d3ffed01..3e6dbe4ef7e9d994ddf636df0e4d86e479f0a25a 100644 (file)
@@ -192,10 +192,20 @@ version = "0.22.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
 
+[[package]]
+name = "bdk-bip322"
+version = "0.1.0"
+source = "git+https://github.com/aagbotemi/bdk-bip322.git?branch=master#aabe67ee68c14992b0d529192641d25ce376b6b1"
+dependencies = [
+ "bdk_wallet",
+ "bitcoin",
+]
+
 [[package]]
 name = "bdk-cli"
 version = "3.0.0"
 dependencies = [
+ "bdk-bip322",
  "bdk_bitcoind_rpc",
  "bdk_electrum",
  "bdk_esplora",
@@ -209,7 +219,7 @@ dependencies = [
  "env_logger",
  "log",
  "payjoin",
- "reqwest 0.13.2",
+ "reqwest",
  "serde",
  "serde_json",
  "shlex",
@@ -1002,7 +1012,7 @@ dependencies = [
  "hex-conservative 0.2.2",
  "log",
  "minreq",
- "reqwest 0.12.28",
+ "reqwest",
  "serde",
  "tokio",
 ]
@@ -1866,7 +1876,7 @@ dependencies = [
  "bitcoin-ohttp",
  "bitcoin_uri",
  "http",
- "reqwest 0.12.28",
+ "reqwest",
  "serde",
  "serde_json",
  "tracing",
@@ -2207,35 +2217,6 @@ dependencies = [
  "webpki-roots 1.0.5",
 ]
 
-[[package]]
-name = "reqwest"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801"
-dependencies = [
- "base64 0.22.1",
- "bytes",
- "futures-core",
- "http",
- "http-body",
- "http-body-util",
- "hyper",
- "hyper-util",
- "js-sys",
- "log",
- "percent-encoding",
- "pin-project-lite",
- "sync_wrapper",
- "tokio",
- "tower",
- "tower-http",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
-]
-
 [[package]]
 name = "ring"
 version = "0.17.14"
index 7a1a31b46f7bc8527a13a33ae2982d4e6cc05775..fb2e54d0bc77634e949291abdf1e72754a1a65d9 100644 (file)
@@ -34,9 +34,10 @@ bdk_esplora = { version = "0.22.1", features = ["async-https", "tokio"], optiona
 bdk_kyoto = { version = "0.15.4", optional = true }
 bdk_redb = { version = "0.1.1", optional = true }
 shlex = {  version = "1.3.0", optional = true }
-payjoin = { version = "=1.0.0-rc.1", features = ["v1", "v2", "io", "_test-utils"], optional = true}
-reqwest = { version = "0.13.2", default-features = false, optional = true }
-url = { version = "2.5.8", optional = true }
+payjoin = { version = "1.0.0-rc.1", features = ["v1", "v2", "io", "_test-utils"], optional = true}
+reqwest = { version = "0.12.23", default-features = false, optional = true }
+url = { version = "2.5.4", optional = true }
+bdk-bip322 = { git = "https://github.com/aagbotemi/bdk-bip322.git", branch = "master", optional = true }
 
 [features]
 default = ["repl", "sqlite"]
@@ -56,6 +57,7 @@ rpc = ["bdk_bitcoind_rpc", "_payjoin-dependencies"]
 
 # Internal features
 _payjoin-dependencies = ["payjoin", "reqwest", "url"]
+bip322 = ["bdk-bip322"]
 
 # Use this to consensus verify transactions at sync time
 verify = []
index 44b13f270b7b8a73a654507c83591c29c93133dc..14932e4a5f7d9a601244eeeceb6df14ec3121554 100644 (file)
@@ -461,6 +461,37 @@ pub enum OfflineWalletSubCommand {
         #[arg(env = "BASE64_PSBT", required = true)]
         psbt: Vec<String>,
     },
+    /// Sign a message using BIP322
+    #[cfg(feature = "bip322")]
+    SignBip322 {
+        /// The message to sign
+        #[arg(long)]
+        message: String,
+        /// The signature format (e.g., Legacy, Simple, Full)
+        #[arg(long, default_value = "simple")]
+        signature_type: String,
+        /// Address to sign
+        #[arg(long)]
+        address: String,
+        // Optional list of specific UTXOs for proof-of-funds (only for `FullWithProofOfFunds`)        #[arg(long)]
+        utxos: Option<Vec<OutPoint>>,
+    },
+    /// Verify a BIP322 signature
+    #[cfg(feature = "bip322")]
+    VerifyBip322 {
+        /// The signature proof to verify
+        #[arg(long)]
+        proof: String,
+        /// The message that was signed
+        #[arg(long)]
+        message: String,
+        /// The signature format (e.g., Legacy, Simple, Full)
+        #[arg(long, default_value = "simple")]
+        signature_type: String,
+        /// The address associated with the signature
+        #[arg(long)]
+        address: String,
+    },
 }
 
 /// Wallet subcommands that needs a blockchain backend.
index a98b172dff82e81c51a9002d8b7213c8f166ffef..ad0872631de1a5a009490e32fdd4eaebe543a4a5 100644 (file)
@@ -70,6 +70,11 @@ use std::str::FromStr;
 ))]
 use std::sync::Arc;
 
+#[cfg(feature = "bip322")]
+use crate::error::BDKCliError;
+#[cfg(feature = "bip322")]
+use bdk_bip322::{BIP322, Bip322Proof, Bip322VerificationResult};
+
 #[cfg(any(
     feature = "electrum",
     feature = "esplora",
@@ -592,6 +597,46 @@ pub fn handle_offline_wallet_subcommand(
                 &json!({ "psbt": BASE64_STANDARD.encode(final_psbt.serialize()) }),
             )?)
         }
+        #[cfg(feature = "bip322")]
+        SignBip322 {
+            message,
+            signature_type,
+            address,
+            utxos,
+        } => {
+            let address: Address = parse_address(&address)?;
+            let signature_format = parse_signature_format(&signature_type)?;
+
+            let proof: Bip322Proof = wallet
+                .sign_bip322(message.as_str(), signature_format, &address, utxos)
+                .map_err(|e| {
+                    BDKCliError::Generic(format!("Failed to sign BIP-322 message: {e}"))
+                })?;
+
+            Ok(json!({"proof": proof.to_base64()}).to_string())
+        }
+        #[cfg(feature = "bip322")]
+        VerifyBip322 {
+            proof,
+            message,
+            signature_type,
+            address,
+        } => {
+            let address: Address = parse_address(&address)?;
+            let signature_format = parse_signature_format(&signature_type)?;
+
+            let parsed_proof: Bip322Proof = Bip322Proof::from_base64(&proof)
+                .map_err(|e| BDKCliError::Generic(format!("Invalid proof: {e}")))?;
+
+            let is_valid: Bip322VerificationResult =
+                wallet.verify_bip322(&parsed_proof, &message, signature_format, &address)?;
+
+            Ok(json!({
+                "valid": is_valid.valid,
+                "proven_amount": is_valid.proven_amount.map(|a| a.to_sat()) // optional field
+            })
+            .to_string())
+        }
     }
 }
 
index 76e56a0f63e9554abd4b044dcc9eb1463693df7b..cf60c3803d9e89f88ab9a818d39ee32cb69c88cd 100644 (file)
@@ -56,6 +56,9 @@ use bdk_wallet::descriptor::Segwitv0;
 use bdk_wallet::keys::{GeneratableKey, GeneratedKey, bip39::WordCount};
 use serde_json::{Value, json};
 
+#[cfg(feature = "bip322")]
+use bdk_bip322::SignatureFormat;
+
 /// Parse the recipient (Address,Amount) argument from cli input.
 pub(crate) fn parse_recipient(s: &str) -> Result<(ScriptBuf, u64), String> {
     let parts: Vec<_> = s.split(':').collect();
@@ -95,6 +98,21 @@ pub(crate) fn parse_address(address_str: &str) -> Result<Address, Error> {
     Ok(unchecked_address.assume_checked())
 }
 
+/// Function to parse the signature format from a string
+#[cfg(feature = "bip322")]
+pub(crate) fn parse_signature_format(format_str: &str) -> Result<SignatureFormat, Error> {
+    match format_str.to_lowercase().as_str() {
+        "legacy" => Ok(SignatureFormat::Legacy),
+        "simple" => Ok(SignatureFormat::Simple),
+        "full" => Ok(SignatureFormat::Full),
+        "fullproofoffunds" => Ok(SignatureFormat::FullProofOfFunds),
+        _ => Err(Error::Generic(
+            "Invalid signature format. Use 'legacy', 'simple', 'full', or 'fullproofoffunds'"
+                .to_string(),
+        )),
+    }
+}
+
 /// Prepare bdk-cli home directory
 ///
 /// This function is called to check if [`crate::CliOpts`] datadir is set.