mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-19 13:44:55 +01:00
feat(cdk-cli): decode, send, receice payment request
This commit is contained in:
@@ -25,8 +25,15 @@ tracing = { version = "0.1", default-features = false, features = ["attributes",
|
|||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
home = "0.5.5"
|
home = "0.5.5"
|
||||||
nostr-sdk = { version = "0.33.0", default-features = false, features = [
|
nostr-sdk = { version = "0.35.0", default-features = false, features = [
|
||||||
"nip04",
|
"nip04",
|
||||||
"nip44"
|
"nip44",
|
||||||
|
"nip59"
|
||||||
|
]}
|
||||||
|
reqwest = { version = "0.12", default-features = false, features = [
|
||||||
|
"json",
|
||||||
|
"rustls-tls",
|
||||||
|
"rustls-tls-native-roots",
|
||||||
|
"socks",
|
||||||
]}
|
]}
|
||||||
url = "2.3"
|
url = "2.3"
|
||||||
|
|||||||
@@ -72,6 +72,12 @@ enum Commands {
|
|||||||
UpdateMintUrl(sub_commands::update_mint_url::UpdateMintUrlSubCommand),
|
UpdateMintUrl(sub_commands::update_mint_url::UpdateMintUrlSubCommand),
|
||||||
/// Get proofs from mint.
|
/// Get proofs from mint.
|
||||||
ListMintProofs,
|
ListMintProofs,
|
||||||
|
/// Decode a payment request
|
||||||
|
DecodeRequest(sub_commands::decode_request::DecodePaymentRequestSubCommand),
|
||||||
|
/// Pay a payment request
|
||||||
|
PayRequest(sub_commands::pay_request::PayRequestSubCommand),
|
||||||
|
/// Create Payment request
|
||||||
|
CreateRequest(sub_commands::create_request::CreateRequestSubCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@@ -204,5 +210,14 @@ async fn main() -> Result<()> {
|
|||||||
Commands::ListMintProofs => {
|
Commands::ListMintProofs => {
|
||||||
sub_commands::list_mint_proofs::proofs(&multi_mint_wallet).await
|
sub_commands::list_mint_proofs::proofs(&multi_mint_wallet).await
|
||||||
}
|
}
|
||||||
|
Commands::DecodeRequest(sub_command_args) => {
|
||||||
|
sub_commands::decode_request::decode_payment_request(sub_command_args)
|
||||||
|
}
|
||||||
|
Commands::PayRequest(sub_command_args) => {
|
||||||
|
sub_commands::pay_request::pay_request(&multi_mint_wallet, sub_command_args).await
|
||||||
|
}
|
||||||
|
Commands::CreateRequest(sub_command_args) => {
|
||||||
|
sub_commands::create_request::create_request(&multi_mint_wallet, sub_command_args).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
104
crates/cdk-cli/src/sub_commands/create_request.rs
Normal file
104
crates/cdk-cli/src/sub_commands/create_request.rs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use cdk::{
|
||||||
|
nuts::{
|
||||||
|
nut18::TransportType, CurrencyUnit, PaymentRequest, PaymentRequestPayload, Token, Transport,
|
||||||
|
},
|
||||||
|
wallet::MultiMintWallet,
|
||||||
|
};
|
||||||
|
use clap::Args;
|
||||||
|
use nostr_sdk::prelude::*;
|
||||||
|
use nostr_sdk::{nips::nip19::Nip19Profile, Client as NostrClient, Filter, Keys, ToBech32};
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
pub struct CreateRequestSubCommand {
|
||||||
|
#[arg(short, long)]
|
||||||
|
amount: Option<u64>,
|
||||||
|
/// Currency unit e.g. sat
|
||||||
|
#[arg(default_value = "sat")]
|
||||||
|
unit: String,
|
||||||
|
/// Quote description
|
||||||
|
description: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_request(
|
||||||
|
multi_mint_wallet: &MultiMintWallet,
|
||||||
|
sub_command_args: &CreateRequestSubCommand,
|
||||||
|
) -> Result<()> {
|
||||||
|
let keys = Keys::generate();
|
||||||
|
let relays = vec!["wss://relay.nos.social", "wss://relay.damus.io"];
|
||||||
|
|
||||||
|
let nprofile = Nip19Profile::new(keys.public_key, relays.clone())?;
|
||||||
|
|
||||||
|
let nostr_transport = Transport {
|
||||||
|
_type: TransportType::Nostr,
|
||||||
|
target: nprofile.to_bech32()?,
|
||||||
|
tags: Some(vec![vec!["n".to_string(), "17".to_string()]]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mints: Vec<cdk::mint_url::MintUrl> = multi_mint_wallet
|
||||||
|
.get_balances(&CurrencyUnit::Sat)
|
||||||
|
.await?
|
||||||
|
.keys()
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let req = PaymentRequest {
|
||||||
|
payment_id: None,
|
||||||
|
amount: sub_command_args.amount.map(|a| a.into()),
|
||||||
|
unit: None,
|
||||||
|
single_use: Some(true),
|
||||||
|
mints: Some(mints),
|
||||||
|
description: sub_command_args.description.clone(),
|
||||||
|
transports: vec![nostr_transport],
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("{}", req);
|
||||||
|
|
||||||
|
let client = NostrClient::new(keys);
|
||||||
|
|
||||||
|
let filter = Filter::new().pubkey(nprofile.public_key);
|
||||||
|
|
||||||
|
for relay in relays {
|
||||||
|
client.add_read_relay(relay).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.connect().await;
|
||||||
|
|
||||||
|
client.subscribe(vec![filter], None).await?;
|
||||||
|
|
||||||
|
// Handle subscription notifications with `handle_notifications` method
|
||||||
|
client
|
||||||
|
.handle_notifications(|notification| async {
|
||||||
|
let mut exit = false;
|
||||||
|
if let RelayPoolNotification::Event {
|
||||||
|
subscription_id: _,
|
||||||
|
event,
|
||||||
|
..
|
||||||
|
} = notification
|
||||||
|
{
|
||||||
|
let unwrapped = client.unwrap_gift_wrap(&event).await?;
|
||||||
|
|
||||||
|
let rumor = unwrapped.rumor;
|
||||||
|
|
||||||
|
let payload: PaymentRequestPayload = serde_json::from_str(&rumor.content)?;
|
||||||
|
|
||||||
|
let token = Token::new(
|
||||||
|
payload.mint,
|
||||||
|
payload.proofs,
|
||||||
|
payload.memo,
|
||||||
|
Some(payload.unit),
|
||||||
|
);
|
||||||
|
|
||||||
|
let amount = multi_mint_wallet
|
||||||
|
.receive(&token.to_string(), &[], &[])
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Received {}", amount);
|
||||||
|
exit = true;
|
||||||
|
}
|
||||||
|
Ok(exit) // Set to true to exit from the loop
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
19
crates/cdk-cli/src/sub_commands/decode_request.rs
Normal file
19
crates/cdk-cli/src/sub_commands/decode_request.rs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use cdk::nuts::PaymentRequest;
|
||||||
|
use cdk::util::serialize_to_cbor_diag;
|
||||||
|
use clap::Args;
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
pub struct DecodePaymentRequestSubCommand {
|
||||||
|
/// Payment request
|
||||||
|
payment_request: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_payment_request(sub_command_args: &DecodePaymentRequestSubCommand) -> Result<()> {
|
||||||
|
let payment_request = PaymentRequest::from_str(&sub_command_args.payment_request)?;
|
||||||
|
|
||||||
|
println!("{:}", serialize_to_cbor_diag(&payment_request)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
pub mod balance;
|
pub mod balance;
|
||||||
pub mod burn;
|
pub mod burn;
|
||||||
pub mod check_spent;
|
pub mod check_spent;
|
||||||
|
pub mod create_request;
|
||||||
|
pub mod decode_request;
|
||||||
pub mod decode_token;
|
pub mod decode_token;
|
||||||
pub mod list_mint_proofs;
|
pub mod list_mint_proofs;
|
||||||
pub mod melt;
|
pub mod melt;
|
||||||
pub mod mint;
|
pub mod mint;
|
||||||
pub mod mint_info;
|
pub mod mint_info;
|
||||||
|
pub mod pay_request;
|
||||||
pub mod pending_mints;
|
pub mod pending_mints;
|
||||||
pub mod receive;
|
pub mod receive;
|
||||||
pub mod restore;
|
pub mod restore;
|
||||||
|
|||||||
177
crates/cdk-cli/src/sub_commands/pay_request.rs
Normal file
177
crates/cdk-cli/src/sub_commands/pay_request.rs
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use cdk::{
|
||||||
|
amount::SplitTarget,
|
||||||
|
nuts::{nut18::TransportType, PaymentRequest, PaymentRequestPayload},
|
||||||
|
wallet::{MultiMintWallet, SendKind},
|
||||||
|
};
|
||||||
|
use clap::Args;
|
||||||
|
use nostr_sdk::{nips::nip19::Nip19Profile, Client as NostrClient, EventBuilder, FromBech32, Keys};
|
||||||
|
use reqwest::Client;
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
pub struct PayRequestSubCommand {
|
||||||
|
payment_request: PaymentRequest,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn pay_request(
|
||||||
|
multi_mint_wallet: &MultiMintWallet,
|
||||||
|
sub_command_args: &PayRequestSubCommand,
|
||||||
|
) -> Result<()> {
|
||||||
|
let payment_request = &sub_command_args.payment_request;
|
||||||
|
|
||||||
|
let unit = payment_request.unit;
|
||||||
|
|
||||||
|
let amount = match payment_request.amount {
|
||||||
|
Some(amount) => amount,
|
||||||
|
None => {
|
||||||
|
println!("Enter the amount you would like to pay");
|
||||||
|
|
||||||
|
let mut user_input = String::new();
|
||||||
|
let stdin = io::stdin();
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
stdin.read_line(&mut user_input)?;
|
||||||
|
|
||||||
|
let amount: u64 = user_input.trim().parse()?;
|
||||||
|
|
||||||
|
amount.into()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let request_mints = &payment_request.mints;
|
||||||
|
|
||||||
|
let wallet_mints = multi_mint_wallet.get_wallets().await;
|
||||||
|
|
||||||
|
// Wallets where unit, balance and mint match request
|
||||||
|
let mut matching_wallets = vec![];
|
||||||
|
|
||||||
|
for wallet in wallet_mints.iter() {
|
||||||
|
let balance = wallet.total_balance().await?;
|
||||||
|
|
||||||
|
if let Some(request_mints) = request_mints {
|
||||||
|
if !request_mints.contains(&wallet.mint_url) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(unit) = unit {
|
||||||
|
if wallet.unit != unit {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if balance >= amount {
|
||||||
|
matching_wallets.push(wallet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let matching_wallet = matching_wallets.first().unwrap();
|
||||||
|
|
||||||
|
// We prefer nostr transport if it is available to hide ip.
|
||||||
|
let transport = payment_request
|
||||||
|
.transports
|
||||||
|
.iter()
|
||||||
|
.find(|t| t._type == TransportType::Nostr)
|
||||||
|
.or_else(|| {
|
||||||
|
payment_request
|
||||||
|
.transports
|
||||||
|
.iter()
|
||||||
|
.find(|t| t._type == TransportType::HttpPost)
|
||||||
|
})
|
||||||
|
.ok_or(anyhow!("No supported transport method found"))?;
|
||||||
|
|
||||||
|
let proofs = matching_wallet
|
||||||
|
.send(
|
||||||
|
amount,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
&SplitTarget::default(),
|
||||||
|
&SendKind::default(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.proofs()
|
||||||
|
.get(&matching_wallet.mint_url)
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
let payload = PaymentRequestPayload {
|
||||||
|
id: payment_request.payment_id.clone(),
|
||||||
|
memo: None,
|
||||||
|
mint: matching_wallet.mint_url.clone(),
|
||||||
|
unit: matching_wallet.unit,
|
||||||
|
proofs,
|
||||||
|
};
|
||||||
|
|
||||||
|
match transport._type {
|
||||||
|
TransportType::Nostr => {
|
||||||
|
let keys = Keys::generate();
|
||||||
|
let client = NostrClient::new(keys);
|
||||||
|
let nprofile = Nip19Profile::from_bech32(&transport.target)?;
|
||||||
|
|
||||||
|
println!("{:?}", nprofile.relays);
|
||||||
|
|
||||||
|
let rumor = EventBuilder::new(
|
||||||
|
nostr_sdk::Kind::from_u16(14),
|
||||||
|
serde_json::to_string(&payload)?,
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
let relays = nprofile.relays;
|
||||||
|
|
||||||
|
for relay in relays.iter() {
|
||||||
|
client.add_write_relay(relay).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.connect().await;
|
||||||
|
|
||||||
|
let gift_wrap = client
|
||||||
|
.gift_wrap_to(relays, &nprofile.public_key, rumor, None)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Published event {} succufully to {}",
|
||||||
|
gift_wrap.val,
|
||||||
|
gift_wrap
|
||||||
|
.success
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
);
|
||||||
|
|
||||||
|
if !gift_wrap.failed.is_empty() {
|
||||||
|
println!(
|
||||||
|
"Could not publish to {:?}",
|
||||||
|
gift_wrap
|
||||||
|
.failed
|
||||||
|
.keys()
|
||||||
|
.map(|relay| relay.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TransportType::HttpPost => {
|
||||||
|
let client = Client::new();
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.post(transport.target.clone())
|
||||||
|
.json(&payload)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let status = res.status();
|
||||||
|
if status.is_success() {
|
||||||
|
println!("Successfully posted payment");
|
||||||
|
} else {
|
||||||
|
println!("{:?}", res);
|
||||||
|
println!("Error posting payment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -184,20 +184,25 @@ async fn nostr_receive(
|
|||||||
|
|
||||||
let client = nostr_sdk::Client::default();
|
let client = nostr_sdk::Client::default();
|
||||||
|
|
||||||
client.add_relays(relays).await?;
|
|
||||||
|
|
||||||
client.connect().await;
|
client.connect().await;
|
||||||
|
|
||||||
let events = client.get_events_of(vec![filter], None).await?;
|
let events = client
|
||||||
|
.get_events_of(
|
||||||
|
vec![filter],
|
||||||
|
nostr_sdk::EventSource::Relays {
|
||||||
|
timeout: None,
|
||||||
|
specific_relays: Some(relays),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let mut tokens: HashSet<String> = HashSet::new();
|
let mut tokens: HashSet<String> = HashSet::new();
|
||||||
|
|
||||||
let keys = Keys::from_str(&(nostr_signing_key).to_secret_hex())?;
|
let keys = Keys::from_str(&(nostr_signing_key).to_secret_hex())?;
|
||||||
|
|
||||||
for event in events {
|
for event in events {
|
||||||
if event.kind() == Kind::EncryptedDirectMessage {
|
if event.kind == Kind::EncryptedDirectMessage {
|
||||||
if let Ok(msg) = nip04::decrypt(keys.secret_key()?, event.author_ref(), event.content())
|
if let Ok(msg) = nip04::decrypt(keys.secret_key(), &event.pubkey, event.content) {
|
||||||
{
|
|
||||||
if let Some(token) = cdk::wallet::util::token_from_text(&msg) {
|
if let Some(token) = cdk::wallet::util::token_from_text(&msg) {
|
||||||
tokens.insert(token.to_string());
|
tokens.insert(token.to_string());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,3 +47,4 @@ pub use nut11::{Conditions, P2PKWitness, SigFlag, SpendingConditions};
|
|||||||
pub use nut12::{BlindSignatureDleq, ProofDleq};
|
pub use nut12::{BlindSignatureDleq, ProofDleq};
|
||||||
pub use nut14::HTLCWitness;
|
pub use nut14::HTLCWitness;
|
||||||
pub use nut15::{Mpp, MppMethodSettings, Settings as NUT15Settings};
|
pub use nut15::{Mpp, MppMethodSettings, Settings as NUT15Settings};
|
||||||
|
pub use nut18::{PaymentRequest, PaymentRequestPayload, Transport};
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use thiserror::Error;
|
|||||||
|
|
||||||
use crate::{mint_url::MintUrl, Amount};
|
use crate::{mint_url::MintUrl, Amount};
|
||||||
|
|
||||||
use super::CurrencyUnit;
|
use super::{CurrencyUnit, Proofs};
|
||||||
|
|
||||||
const PAYMENT_REQUEST_PREFIX: &str = "creqA";
|
const PAYMENT_REQUEST_PREFIX: &str = "creqA";
|
||||||
|
|
||||||
@@ -32,12 +32,39 @@ pub enum Error {
|
|||||||
Base64Error(#[from] bitcoin::base64::DecodeError),
|
Base64Error(#[from] bitcoin::base64::DecodeError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transport Type
|
||||||
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum TransportType {
|
||||||
|
/// Nostr
|
||||||
|
#[serde(rename = "nostr")]
|
||||||
|
Nostr,
|
||||||
|
/// Http post
|
||||||
|
#[serde(rename = "post")]
|
||||||
|
HttpPost,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TransportType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
use serde::ser::Error;
|
||||||
|
let t = serde_json::to_string(self).map_err(|e| fmt::Error::custom(e.to_string()))?;
|
||||||
|
write!(f, "{}", t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Transport {
|
||||||
|
type Err = serde_json::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
serde_json::from_str(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Transport
|
/// Transport
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Transport {
|
pub struct Transport {
|
||||||
/// Type
|
/// Type
|
||||||
#[serde(rename = "t")]
|
#[serde(rename = "t")]
|
||||||
pub _type: String,
|
pub _type: TransportType,
|
||||||
/// Target
|
/// Target
|
||||||
#[serde(rename = "a")]
|
#[serde(rename = "a")]
|
||||||
pub target: String,
|
pub target: String,
|
||||||
@@ -47,7 +74,7 @@ pub struct Transport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Payment Request
|
/// Payment Request
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct PaymentRequest {
|
pub struct PaymentRequest {
|
||||||
/// `Payment id`
|
/// `Payment id`
|
||||||
#[serde(rename = "i")]
|
#[serde(rename = "i")]
|
||||||
@@ -98,6 +125,21 @@ impl FromStr for PaymentRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Payment Request
|
||||||
|
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct PaymentRequestPayload {
|
||||||
|
/// Id
|
||||||
|
pub id: Option<String>,
|
||||||
|
/// Memo
|
||||||
|
pub memo: Option<String>,
|
||||||
|
/// Mint
|
||||||
|
pub mint: MintUrl,
|
||||||
|
/// Unit
|
||||||
|
pub unit: CurrencyUnit,
|
||||||
|
/// Proofs
|
||||||
|
pub proofs: Proofs,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
@@ -121,7 +163,7 @@ mod tests {
|
|||||||
|
|
||||||
let transport = req.transports.first().unwrap();
|
let transport = req.transports.first().unwrap();
|
||||||
|
|
||||||
let expected_transport = Transport {_type: "nostr".to_string(), target: "nprofile1qy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsz9mhwden5te0wfjkccte9curxven9eehqctrv5hszrthwden5te0dehhxtnvdakqqgydaqy7curk439ykptkysv7udhdhu68sucm295akqefdehkf0d495cwunl5".to_string(), tags: Some(vec![vec!["n".to_string(), "17".to_string()]])};
|
let expected_transport = Transport {_type: TransportType::Nostr, target: "nprofile1qy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsz9mhwden5te0wfjkccte9curxven9eehqctrv5hszrthwden5te0dehhxtnvdakqqgydaqy7curk439ykptkysv7udhdhu68sucm295akqefdehkf0d495cwunl5".to_string(), tags: Some(vec![vec!["n".to_string(), "17".to_string()]])};
|
||||||
|
|
||||||
assert_eq!(transport, &expected_transport);
|
assert_eq!(transport, &expected_transport);
|
||||||
|
|
||||||
@@ -130,7 +172,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_roundtrip_payment_req() -> anyhow::Result<()> {
|
fn test_roundtrip_payment_req() -> anyhow::Result<()> {
|
||||||
let transport = Transport {_type: "nostr".to_string(), target: "nprofile1qy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsz9mhwden5te0wfjkccte9curxven9eehqctrv5hszrthwden5te0dehhxtnvdakqqgydaqy7curk439ykptkysv7udhdhu68sucm295akqefdehkf0d495cwunl5".to_string(), tags: Some(vec![vec!["n".to_string(), "17".to_string()]])};
|
let transport = Transport {_type: TransportType::Nostr, target: "nprofile1qy28wumn8ghj7un9d3shjtnyv9kh2uewd9hsz9mhwden5te0wfjkccte9curxven9eehqctrv5hszrthwden5te0dehhxtnvdakqqgydaqy7curk439ykptkysv7udhdhu68sucm295akqefdehkf0d495cwunl5".to_string(), tags: Some(vec![vec!["n".to_string(), "17".to_string()]])};
|
||||||
|
|
||||||
let request = PaymentRequest {
|
let request = PaymentRequest {
|
||||||
payment_id: Some("b7a90176".to_string()),
|
payment_id: Some("b7a90176".to_string()),
|
||||||
|
|||||||
Reference in New Issue
Block a user