Skip to content

Commit 4d0dfaa

Browse files
committed
Add event handling and other functions to ffi
1 parent dcc8871 commit 4d0dfaa

3 files changed

Lines changed: 268 additions & 4 deletions

File tree

orange-sdk/src/ffi/orange/mod.rs

Lines changed: 200 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::bitcoin::hashes::Hash;
22
use crate::ffi::bitcoin_payment_instructions::Amount;
3-
use crate::{PaymentId as OrangePaymentId, Transaction as OrangeTransaction};
3+
use crate::{
4+
PaymentId as OrangePaymentId, Transaction as OrangeTransaction, event::Event as OrangeEvent,
5+
};
46
use crate::{impl_from_core_type, impl_into_core_type};
57
use std::sync::Arc;
68

@@ -153,3 +155,200 @@ impl From<crate::store::PaymentType> for PaymentType {
153155
}
154156
}
155157
}
158+
159+
/// An event emitted by [`Wallet`], which should be handled by the user.
160+
///
161+
/// [`Wallet`]: [`crate::Wallet`]
162+
#[derive(Debug, Clone, Eq, PartialEq, uniffi::Enum)]
163+
pub enum Event {
164+
/// An outgoing payment was successful.
165+
PaymentSuccessful {
166+
/// A local identifier used to track the payment.
167+
payment_id: Arc<PaymentId>,
168+
/// The hash of the payment.
169+
payment_hash: Vec<u8>,
170+
/// The preimage to the `payment_hash`.
171+
///
172+
/// Note that this serves as a payment receipt.
173+
payment_preimage: Vec<u8>,
174+
/// The total fee which was spent at intermediate hops in this payment.
175+
fee_paid_msat: Option<u64>,
176+
},
177+
/// An outgoing payment has failed.
178+
PaymentFailed {
179+
/// A local identifier used to track the payment.
180+
payment_id: Arc<PaymentId>,
181+
/// The hash of the payment.
182+
///
183+
/// This will be `None` if the payment failed before receiving an invoice when paying a
184+
/// BOLT12 [`Offer`].
185+
///
186+
/// [`Offer`]: ldk_node::lightning::offers::offer::Offer
187+
payment_hash: Option<Vec<u8>>,
188+
/// The reason why the payment failed.
189+
///
190+
/// Will be `None` if the failure reason is not known.
191+
reason: Option<String>,
192+
},
193+
/// A payment has been received.
194+
PaymentReceived {
195+
/// A local identifier used to track the payment.
196+
payment_id: Arc<PaymentId>,
197+
/// The hash of the payment.
198+
payment_hash: Vec<u8>,
199+
/// The value, in msats, that has been received.
200+
amount_msat: u64,
201+
/// Custom TLV records received on the payment
202+
custom_records: Vec<Vec<u8>>,
203+
/// The value, in msats, that was skimmed off of this payment as an extra fee taken by LSP.
204+
/// Typically, this is only present for payments that result in opening a channel.
205+
lsp_fee_msats: Option<u64>,
206+
},
207+
/// A payment has been received.
208+
OnchainPaymentReceived {
209+
/// A local identifier used to track the payment.
210+
payment_id: Arc<PaymentId>,
211+
/// The transaction ID.
212+
txid: Vec<u8>,
213+
/// The value, in sats, that has been received.
214+
amount_sat: u64,
215+
},
216+
/// A channel is ready to be used.
217+
ChannelOpened {
218+
/// The `channel_id` of the channel.
219+
channel_id: Vec<u8>,
220+
/// The `user_channel_id` of the channel.
221+
user_channel_id: Vec<u8>,
222+
/// The `node_id` of the channel counterparty.
223+
counterparty_node_id: Vec<u8>,
224+
/// The outpoint of the channel's funding transaction.
225+
funding_txo: String,
226+
},
227+
/// A channel has been closed.
228+
///
229+
/// When a channel is closed, we will disable automatic rebalancing
230+
/// so new channels will not be opened until it is explicitly enabled again.
231+
ChannelClosed {
232+
/// The `channel_id` of the channel.
233+
channel_id: Vec<u8>,
234+
/// The `user_channel_id` of the channel.
235+
user_channel_id: Vec<u8>,
236+
/// The `node_id` of the channel counterparty.
237+
counterparty_node_id: Vec<u8>,
238+
/// Why the channel was closed.
239+
///
240+
/// Will be `None` if the closure reason is not known.
241+
reason: Option<String>,
242+
},
243+
/// A rebalance from our trusted wallet has been initiated.
244+
RebalanceInitiated {
245+
/// The `payment_id` of the transaction that triggered the rebalance.
246+
trigger_payment_id: Arc<PaymentId>,
247+
/// The `payment_id` of the rebalance payment sent from the trusted wallet.
248+
trusted_rebalance_payment_id: Vec<u8>,
249+
/// The amount, in msats, of the rebalance payment.
250+
amount_msat: u64,
251+
},
252+
/// A rebalance from our trusted wallet was successful.
253+
RebalanceSuccessful {
254+
/// The `payment_id` of the transaction that triggered the rebalance.
255+
trigger_payment_id: Arc<PaymentId>,
256+
/// The `payment_id` of the rebalance payment sent from the trusted wallet.
257+
trusted_rebalance_payment_id: Vec<u8>,
258+
/// The `payment_id` of the rebalance payment sent to the LN wallet.
259+
ln_rebalance_payment_id: Vec<u8>,
260+
/// The amount, in msats, of the rebalance payment.
261+
amount_msat: u64,
262+
/// The fee paid, in msats, for the rebalance payment.
263+
fee_msat: u64,
264+
},
265+
}
266+
267+
impl From<OrangeEvent> for Event {
268+
fn from(value: OrangeEvent) -> Self {
269+
match value {
270+
OrangeEvent::PaymentSuccessful {
271+
payment_id,
272+
payment_hash,
273+
payment_preimage,
274+
fee_paid_msat,
275+
} => Event::PaymentSuccessful {
276+
payment_id: Arc::new(payment_id.into()),
277+
payment_hash: payment_hash.0.to_vec(),
278+
payment_preimage: payment_preimage.0.to_vec(),
279+
fee_paid_msat,
280+
},
281+
OrangeEvent::PaymentFailed { payment_id, payment_hash, reason } => {
282+
Event::PaymentFailed {
283+
payment_id: Arc::new(payment_id.into()),
284+
payment_hash: payment_hash.map(|h| h.0.to_vec()),
285+
reason: reason.map(|r| format!("{:?}", r)),
286+
}
287+
},
288+
OrangeEvent::PaymentReceived {
289+
payment_id,
290+
payment_hash,
291+
amount_msat,
292+
custom_records,
293+
lsp_fee_msats,
294+
} => Event::PaymentReceived {
295+
payment_id: Arc::new(payment_id.into()),
296+
payment_hash: payment_hash.0.to_vec(),
297+
amount_msat,
298+
custom_records: custom_records.into_iter().map(|r| r.value).collect(),
299+
lsp_fee_msats,
300+
},
301+
OrangeEvent::OnchainPaymentReceived { payment_id, txid, amount_sat, status: _ } => {
302+
Event::OnchainPaymentReceived {
303+
payment_id: Arc::new(payment_id.into()),
304+
txid: txid.to_byte_array().to_vec(),
305+
amount_sat,
306+
}
307+
},
308+
OrangeEvent::ChannelOpened {
309+
channel_id,
310+
user_channel_id,
311+
counterparty_node_id,
312+
funding_txo,
313+
} => Event::ChannelOpened {
314+
channel_id: channel_id.0.to_vec(),
315+
user_channel_id: user_channel_id.0.to_be_bytes().to_vec(),
316+
counterparty_node_id: counterparty_node_id.serialize().to_vec(),
317+
funding_txo: funding_txo.to_string(),
318+
},
319+
OrangeEvent::ChannelClosed {
320+
channel_id,
321+
user_channel_id,
322+
counterparty_node_id,
323+
reason,
324+
} => Event::ChannelClosed {
325+
channel_id: channel_id.0.to_vec(),
326+
user_channel_id: user_channel_id.0.to_be_bytes().to_vec(),
327+
counterparty_node_id: counterparty_node_id.serialize().to_vec(),
328+
reason: reason.map(|r| format!("{:?}", r)),
329+
},
330+
OrangeEvent::RebalanceInitiated {
331+
trigger_payment_id,
332+
trusted_rebalance_payment_id,
333+
amount_msat,
334+
} => Event::RebalanceInitiated {
335+
trigger_payment_id: Arc::new(trigger_payment_id.into()),
336+
trusted_rebalance_payment_id: trusted_rebalance_payment_id.to_vec(),
337+
amount_msat,
338+
},
339+
OrangeEvent::RebalanceSuccessful {
340+
trigger_payment_id,
341+
trusted_rebalance_payment_id,
342+
ln_rebalance_payment_id,
343+
amount_msat,
344+
fee_msat,
345+
} => Event::RebalanceSuccessful {
346+
trigger_payment_id: Arc::new(trigger_payment_id.into()),
347+
trusted_rebalance_payment_id: trusted_rebalance_payment_id.to_vec(),
348+
ln_rebalance_payment_id: ln_rebalance_payment_id.to_vec(),
349+
amount_msat,
350+
fee_msat,
351+
},
352+
}
353+
}
354+
}

orange-sdk/src/ffi/orange/wallet.rs

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use crate::Balances as OrangeBalances;
2-
32
use crate::SingleUseReceiveUri as OrangeSingleUseReceiveUri;
43
use crate::Wallet as OrangeWallet;
54
use crate::WalletConfig as OrangeWalletConfig;
65
use crate::ffi::bitcoin_payment_instructions::{
76
Amount, ParseError, PaymentInfo, PaymentInstructions,
87
};
98
use crate::ffi::ldk_node::ChannelDetails;
10-
use crate::ffi::orange::config::WalletConfig;
9+
use crate::ffi::orange::Event;
10+
use crate::ffi::orange::config::{Tunables, WalletConfig};
1111
use crate::ffi::orange::error::{InitFailure, WalletError};
1212
use crate::{impl_from_core_type, impl_into_core_type};
1313
use std::sync::Arc;
@@ -162,6 +162,17 @@ impl Wallet {
162162
Ok(())
163163
}
164164

165+
/// Estimates the fees required to pay using the provided PaymentInfo
166+
///
167+
/// This will estimate fees for the optimal payment method based on the current wallet state,
168+
/// including whether the payment would be routed through the trusted wallet or lightning wallet.
169+
pub async fn estimate_fee(
170+
&self, payment_info: Arc<PaymentInfo>,
171+
) -> Result<Arc<Amount>, WalletError> {
172+
let fee = self.inner.estimate_fee(&payment_info.0.instructions).await;
173+
Ok(Arc::new(fee.into()))
174+
}
175+
165176
pub async fn stop(&self) {
166177
self.inner.stop().await
167178
}
@@ -177,4 +188,58 @@ impl Wallet {
177188
pub fn list_channels(&self) -> Vec<Arc<ChannelDetails>> {
178189
self.inner.channels().into_iter().map(|ch| Arc::new(ch.into())).collect()
179190
}
191+
192+
/// List our current channels
193+
pub fn close_channels(&self) -> Result<(), WalletError> {
194+
self.inner.close_channels()?;
195+
Ok(())
196+
}
197+
198+
/// Returns the wallet's configured tunables.
199+
pub fn get_tunables(&self) -> Arc<Tunables> {
200+
Arc::new(self.inner.get_tunables().into())
201+
}
202+
203+
/// Returns the next event in the event queue, if currently available.
204+
///
205+
/// Will return `Some(...)` if an event is available and `None` otherwise.
206+
///
207+
/// **Note:** this will always return the same event until handling is confirmed via [`crate::Wallet::event_handled`].
208+
///
209+
/// **Caution:** Users must handle events as quickly as possible to prevent a large event backlog,
210+
/// which can increase the memory footprint of [`crate::Wallet`].
211+
pub fn next_event(&self) -> Option<Event> {
212+
self.inner.next_event().map(|e| e.into())
213+
}
214+
215+
/// Returns the next event in the event queue.
216+
///
217+
/// Will asynchronously poll the event queue until the next event is ready.
218+
///
219+
/// **Note:** this will always return the same event until handling is confirmed via [`crate::Wallet::event_handled`].
220+
///
221+
/// **Caution:** Users must handle events as quickly as possible to prevent a large event backlog,
222+
/// which can increase the memory footprint of [`crate::Wallet`].
223+
pub async fn next_event_async(&self) -> Event {
224+
self.inner.next_event_async().await.into()
225+
}
226+
227+
/// Returns the next event in the event queue.
228+
///
229+
/// Will block the current thread until the next event is available.
230+
///
231+
/// **Note:** this will always return the same event until handling is confirmed via [`crate::Wallet::event_handled`].
232+
///
233+
/// **Caution:** Users must handle events as quickly as possible to prevent a large event backlog,
234+
/// which can increase the memory footprint of [`crate::Wallet`].
235+
pub fn wait_next_event(&self) -> Event {
236+
self.inner.wait_next_event().into()
237+
}
238+
239+
/// Confirm the last retrieved event handled. Returns true if successful.
240+
///
241+
/// **Note:** This **MUST** be called after each event has been handled.
242+
pub fn event_handled(&self) -> bool {
243+
self.inner.event_handled().is_ok()
244+
}
180245
}

orange-sdk/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1249,7 +1249,7 @@ impl Wallet {
12491249

12501250
/// Returns the next event in the event queue, if currently available.
12511251
///
1252-
/// Will return `Some(..)` if an event is available and `None` otherwise.
1252+
/// Will return `Some(...)` if an event is available and `None` otherwise.
12531253
///
12541254
/// **Note:** this will always return the same event until handling is confirmed via [`Wallet::event_handled`].
12551255
///

0 commit comments

Comments
 (0)