Skip to content

Commit

Permalink
nostr: add sign_psbt method to NIP46
Browse files Browse the repository at this point in the history
  • Loading branch information
yukibtc committed Jul 20, 2023
1 parent 8de9228 commit 239f046
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 4 deletions.
2 changes: 1 addition & 1 deletion crates/nostr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ nip06 = ["dep:bip39", "dep:bitcoin"]
nip11 = ["dep:reqwest"]
nip19 = ["dep:bech32"]
nip21 = ["nip19"]
nip46 = ["nip04"]
nip46 = ["dep:bitcoin", "bitcoin?/base64", "bitcoin?/serde", "nip04"]
nip47 = ["nip04"]

[dependencies]
Expand Down
64 changes: 61 additions & 3 deletions crates/nostr/src/nips/nip46.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ use core::fmt;
use core::str::FromStr;
use std::borrow::Cow;

use bitcoin::psbt::PartiallySignedTransaction;
use bitcoin::Network;
use bitcoin_hashes::sha256::Hash as Sha256Hash;
use bitcoin_hashes::Hash;
use secp256k1::schnorr::Signature;
use secp256k1::{rand, Message as Secp256k1Message, XOnlyPublicKey};
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_json::{json, Value};
use url::form_urlencoded::byte_serialize;
use url::Url;
Expand Down Expand Up @@ -117,7 +119,7 @@ impl From<unsigned::Error> for Error {
}

/// Request
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Request {
/// Describe
Describe,
Expand Down Expand Up @@ -152,6 +154,19 @@ pub enum Request {
},
/// Sign Schnorr
SignSchnorr(String),
/// Sign PSBT
SignPSBT {
/// Bitcoin Network
network: Network,
/// PSBT
#[serde(
serialize_with = "serialize_psbt",
deserialize_with = "deserialize_psbt"
)]
psbt: PartiallySignedTransaction,
/// Descriptor
descriptor: Option<String>,
},
}

impl Request {
Expand All @@ -167,6 +182,7 @@ impl Request {
Self::Nip04Encrypt { .. } => "nip04_encrypt".to_string(),
Self::Nip04Decrypt { .. } => "nip04_decrypt".to_string(),
Self::SignSchnorr(_) => "sign_schnorr".to_string(),
Self::SignPSBT { .. } => "sign_psbt".to_string(),
}
}

Expand All @@ -185,6 +201,17 @@ impl Request {
Self::Nip04Encrypt { public_key, text } => vec![json!(public_key), json!(text)],
Self::Nip04Decrypt { public_key, text } => vec![json!(public_key), json!(text)],
Self::SignSchnorr(value) => vec![json!(value)],
Self::SignPSBT {
network,
psbt,
descriptor,
} => {
let mut params = vec![json!(network.to_string()), json!(psbt.to_string())];
if let Some(descriptor) = descriptor {
params.push(json!(descriptor));
}
params
}
}
}

Expand Down Expand Up @@ -237,6 +264,7 @@ impl Request {
let sig: Signature = keys.sign_schnorr(&message)?;
Some(Response::SignSchnorr(sig))
}
Self::SignPSBT { .. } => None,
};
Ok(res)
}
Expand All @@ -256,7 +284,7 @@ pub struct DelegationResult {
}

/// Response
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Response {
/// Describe
Describe(Vec<String>),
Expand All @@ -272,6 +300,17 @@ pub enum Response {
Nip04Decrypt(String),
/// Sign Schnorr
SignSchnorr(Signature),
/// Sign PSBT
SignPSBT {
/// PSBT
#[serde(
serialize_with = "serialize_psbt",
deserialize_with = "deserialize_psbt"
)]
psbt: PartiallySignedTransaction,
/// Finalized
finalized: bool,
},
}

/// Message
Expand Down Expand Up @@ -320,6 +359,10 @@ impl Message {
Response::Nip04Encrypt(encrypted_content) => json!(encrypted_content),
Response::Nip04Decrypt(decrypted_content) => json!(decrypted_content),
Response::SignSchnorr(sig) => json!(sig),
Response::SignPSBT { psbt, finalized } => json!({
"psbt": psbt.to_string(),
"finalized": finalized,
}),
}),
error: None,
}
Expand Down Expand Up @@ -624,6 +667,21 @@ impl fmt::Display for NostrConnectURI {
}
}

fn serialize_psbt<S>(psbt: &PartiallySignedTransaction, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&psbt.to_string())
}

fn deserialize_psbt<'de, D>(deserializer: D) -> Result<PartiallySignedTransaction, D::Error>
where
D: Deserializer<'de>,
{
let psbt = String::deserialize(deserializer)?;
PartiallySignedTransaction::from_str(&psbt).map_err(serde::de::Error::custom)
}

#[cfg(test)]
mod test {
use std::str::FromStr;
Expand Down

0 comments on commit 239f046

Please sign in to comment.