Skip to content

Commit

Permalink
add list_transactions nwc command
Browse files Browse the repository at this point in the history
  • Loading branch information
elnosh committed Apr 24, 2024
1 parent 00078be commit f855a0a
Show file tree
Hide file tree
Showing 7 changed files with 545 additions and 243 deletions.
82 changes: 78 additions & 4 deletions mutiny-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ use ::nostr::nips::nip47::Method;
use ::nostr::nips::nip57;
#[cfg(target_arch = "wasm32")]
use ::nostr::prelude::rand::rngs::OsRng;
use ::nostr::prelude::ZapRequestData;
use ::nostr::prelude::{LookupInvoiceResponseResult, TransactionType, ZapRequestData};
#[cfg(target_arch = "wasm32")]
use ::nostr::Tag;
use ::nostr::{EventBuilder, EventId, JsonUtil, Keys, Kind};
Expand Down Expand Up @@ -145,6 +145,7 @@ pub trait InvoiceHandler {
fn get_network(&self) -> Network;
async fn get_best_block(&self) -> Result<BestBlock, MutinyError>;
async fn lookup_payment(&self, payment_hash: &[u8; 32]) -> Option<MutinyInvoice>;
async fn get_payments_by_label(&self, label: &str) -> Result<Vec<MutinyInvoice>, MutinyError>;
async fn pay_invoice(
&self,
invoice: &Bolt11Invoice,
Expand All @@ -161,7 +162,7 @@ pub trait InvoiceHandler {
&self,
to_node: PublicKey,
amt_sats: u64,
message: Option<String>,
custom_tlvs: Vec<CustomTLV>,
labels: Vec<String>,
preimage: Option<[u8; 32]>,
) -> Result<MutinyInvoice, MutinyError>;
Expand All @@ -173,6 +174,12 @@ pub struct LnUrlParams {
pub tag: String,
}

#[derive(Clone, Eq, PartialEq, Debug)]
pub struct CustomTLV {
pub tlv_type: u64,
pub value: String,
}

/// Plan is a subscription plan for Mutiny+
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Plan {
Expand Down Expand Up @@ -426,6 +433,60 @@ impl From<Bolt11Invoice> for MutinyInvoice {
}
}

impl From<MutinyInvoice> for LookupInvoiceResponseResult {
fn from(invoice: MutinyInvoice) -> Self {
let transaction_type = if invoice.inbound {
Some(TransactionType::Incoming)
} else {
Some(TransactionType::Outgoing)
};

let (description, description_hash) = match invoice.bolt11.as_ref() {
None => (None, None),
Some(invoice) => match invoice.description() {
Bolt11InvoiceDescription::Direct(desc) => (Some(desc.to_string()), None),
Bolt11InvoiceDescription::Hash(hash) => (None, Some(hash.0.to_string())),
},
};

// try to get created_at from invoice,
// if it is not set, use last_updated as that's our closest approximation
let created_at = invoice
.bolt11
.as_ref()
.map(|b| b.duration_since_epoch().as_secs())
.unwrap_or(invoice.last_updated);

let settled_at = if invoice.status == HTLCStatus::Succeeded {
Some(invoice.last_updated)
} else {
None
};

// only reveal preimage if it is settled
let preimage = if invoice.status == HTLCStatus::Succeeded {
invoice.preimage
} else {
None
};

LookupInvoiceResponseResult {
transaction_type,
invoice: invoice.bolt11.map(|i| i.to_string()),
description,
description_hash,
preimage,
payment_hash: invoice.payment_hash.into_32().to_lower_hex_string(),
amount: invoice.amount_sats.map(|a| a * 1_000).unwrap_or(0),
fees_paid: invoice.fees_paid.map(|a| a * 1_000).unwrap_or(0),
created_at,
expires_at: invoice.expire,
settled_at,
metadata: Default::default(),
}
}
}

impl From<MutinyInvoice> for PaymentInfo {
fn from(invoice: MutinyInvoice) -> Self {
let preimage: Option<[u8; 32]> = invoice
Expand Down Expand Up @@ -3104,6 +3165,19 @@ impl<S: MutinyStorage> InvoiceHandler for MutinyWallet<S> {
.ok()
}

async fn get_payments_by_label(&self, label: &str) -> Result<Vec<MutinyInvoice>, MutinyError> {
let label_activity = self.get_label_activity(&label.to_string()).await?;
let mut invoices: Vec<MutinyInvoice> = Vec::with_capacity(label.len());

for item in label_activity {
if let ActivityItem::Lightning(mutiny_invoice) = item {
invoices.push(*mutiny_invoice);
}
}

Ok(invoices)
}

async fn pay_invoice(
&self,
invoice: &Bolt11Invoice,
Expand All @@ -3125,12 +3199,12 @@ impl<S: MutinyStorage> InvoiceHandler for MutinyWallet<S> {
&self,
to_node: PublicKey,
amt_sats: u64,
message: Option<String>,
custom_tlvs: Vec<CustomTLV>,
labels: Vec<String>,
preimage: Option<[u8; 32]>,
) -> Result<MutinyInvoice, MutinyError> {
self.node_manager
.keysend(None, to_node, amt_sats, message, labels, preimage)
.keysend(None, to_node, amt_sats, custom_tlvs, labels, preimage)
.await
}
}
Expand Down
28 changes: 14 additions & 14 deletions mutiny-core/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
onchain::OnChainWallet,
peermanager::{GossipMessageHandler, PeerManagerImpl},
utils::{self, sleep},
MutinyInvoice, PrivacyLevel,
CustomTLV, MutinyInvoice, PrivacyLevel,
};
use crate::{fees::P2WSH_OUTPUT_SIZE, peermanager::connect_peer_if_necessary};
use crate::{keymanager::PhantomKeysManager, scorer::HubPreferentialScorer};
Expand All @@ -41,7 +41,7 @@ use futures_util::lock::Mutex;
use hex_conservative::DisplayHex;
use lightning::events::bump_transaction::{BumpTransactionEventHandler, Wallet};
use lightning::ln::channelmanager::ChannelDetails;
use lightning::ln::PaymentSecret;
//use lightning::ln::PaymentSecret;
use lightning::onion_message::messenger::OnionMessenger as LdkOnionMessenger;
use lightning::routing::scoring::ProbabilisticScoringDecayParameters;
use lightning::sign::{EntropySource, InMemorySigner, NodeSigner, Recipient};
Expand Down Expand Up @@ -1614,7 +1614,7 @@ impl<S: MutinyStorage> Node<S> {
&self,
to_node: PublicKey,
amt_sats: u64,
message: Option<String>,
custom_tlvs: Vec<CustomTLV>,
labels: Vec<String>,
payment_id: PaymentId,
preimage: Option<[u8; 32]>,
Expand Down Expand Up @@ -1652,10 +1652,6 @@ impl<S: MutinyStorage> Node<S> {
sleep(1_000).await;
}

let mut entropy = [0u8; 32];
getrandom::getrandom(&mut entropy).map_err(|_| MutinyError::SeedGenerationFailed)?;
let payment_secret = PaymentSecret(entropy);

let preimage = match preimage {
Some(value) => PaymentPreimage(value),
None => {
Expand All @@ -1673,13 +1669,17 @@ impl<S: MutinyStorage> Node<S> {
max_total_routing_fee_msat: None,
};

let recipient_onion = if let Some(msg) = message {
// keysend messages are encoded as TLV type 34349334
RecipientOnionFields::secret_only(payment_secret)
.with_custom_tlvs(vec![(34349334, msg.encode())])
let recipient_onion = if !custom_tlvs.is_empty() {
let custom_tlvs: Vec<(u64, Vec<u8>)> = custom_tlvs
.into_iter()
.map(|tlv| (tlv.tlv_type, tlv.value.encode()))
.collect();

RecipientOnionFields::spontaneous_empty()
.with_custom_tlvs(custom_tlvs)
.map_err(|_| {
log_error!(self.logger, "could not encode keysend message");
MutinyError::InvoiceCreationFailed
MutinyError::InvalidArgumentsError
})?
} else {
RecipientOnionFields::spontaneous_empty()
Expand Down Expand Up @@ -1739,7 +1739,7 @@ impl<S: MutinyStorage> Node<S> {
&self,
to_node: PublicKey,
amt_sats: u64,
message: Option<String>,
custom_tlvs: Vec<CustomTLV>,
labels: Vec<String>,
timeout_secs: Option<u64>,
preimage: Option<[u8; 32]>,
Expand All @@ -1753,7 +1753,7 @@ impl<S: MutinyStorage> Node<S> {
.init_keysend_payment(
to_node,
amt_sats,
message,
custom_tlvs,
labels.clone(),
payment_id,
preimage,
Expand Down
6 changes: 3 additions & 3 deletions mutiny-core/src/nodemanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::labels::LabelStorage;
use crate::ldkstorage::CHANNEL_CLOSURE_PREFIX;
use crate::logging::LOGGING_KEY;
use crate::utils::{sleep, spawn};
use crate::MutinyInvoice;
use crate::MutinyWalletConfig;
use crate::{
chain::MutinyChain,
Expand All @@ -23,6 +22,7 @@ use crate::{
node::NodeBuilder,
storage::{MutinyStorage, DEVICE_ID_KEY, KEYCHAIN_STORE_KEY, NEED_FULL_SYNC_KEY},
};
use crate::{CustomTLV, MutinyInvoice};
use anyhow::anyhow;
use async_lock::RwLock;
use bdk::chain::{BlockId, ConfirmationTime};
Expand Down Expand Up @@ -1406,13 +1406,13 @@ impl<S: MutinyStorage> NodeManager<S> {
self_node_pubkey: Option<&PublicKey>,
to_node: PublicKey,
amt_sats: u64,
message: Option<String>,
custom_tlvs: Vec<CustomTLV>,
labels: Vec<String>,
preimage: Option<[u8; 32]>,
) -> Result<MutinyInvoice, MutinyError> {
let node = self.get_node_by_key_or_first(self_node_pubkey).await?;
log_debug!(self.logger, "Keysending to {to_node}");
node.keysend_with_timeout(to_node, amt_sats, message, labels, None, preimage)
node.keysend_with_timeout(to_node, amt_sats, custom_tlvs, labels, None, preimage)
.await
}

Expand Down
1 change: 0 additions & 1 deletion mutiny-core/src/nostr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1541,7 +1541,6 @@ impl<S: MutinyStorage, P: PrimalApi, C: NostrClient> NostrManager<S, P, C> {

self.storage.set_nwc_sync_time(event.created_at.as_u64())?;

// TODO: handle nwc response here
if let Some(mut nwc) = nwc {
nwc.handle_nwc_request(event, invoice_handler, self).await?;
}
Expand Down
Loading

0 comments on commit f855a0a

Please sign in to comment.