Skip to content

Commit

Permalink
add trampoline payment support
Browse files Browse the repository at this point in the history
  • Loading branch information
JssDWt committed Aug 15, 2024
1 parent 75a21b3 commit 42c0c07
Showing 1 changed file with 87 additions and 15 deletions.
102 changes: 87 additions & 15 deletions libs/sdk-core/src/breez_services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,33 +289,105 @@ impl BreezServices {
}
};

match self
if self
.persister
.get_completed_payment_by_hash(&parsed_invoice.payment_hash)?
.is_some()
{
Some(_) => Err(SendPaymentError::AlreadyPaid),
return Err(SendPaymentError::AlreadyPaid);
}

// If there is an lsp, the invoice route hint does not contain the
// lsp in the hint, and trampoline payments are requested, attempt a
// trampoline payment.
let maybe_trampoline_id = self.get_trampoline_id(&req, &parsed_invoice)?;

self.persist_pending_payment(&parsed_invoice, amount_msat, req.label.clone())?;

// If trampoline is an option, try trampoline first.
let trampoline_result = if let Some(trampoline_id) = maybe_trampoline_id {
debug!("attempting trampoline payment");
match self
.node_api
.send_trampoline_payment(
parsed_invoice.bolt11.clone(),
amount_msat,
req.label.clone(),
trampoline_id,
)
.await
{
Ok(res) => Some(res),
Err(e) => {
warn!("trampoline payment failed: {:?}", e);
None
}
}
} else {
debug!("not attempting trampoline payment");
None
};

// If trampoline failed or didn't happen, fall back to regular payment.
let payment_res = match trampoline_result {
Some(res) => Ok(res),
None => {
self.persist_pending_payment(&parsed_invoice, amount_msat, req.label.clone())?;
let payment_res = self
.node_api
debug!("attempting normal payment");
self.node_api
.send_payment(
parsed_invoice.bolt11.clone(),
req.amount_msat,
req.label.clone(),
)
.map_err(Into::into)
.await;
let payment = self
.on_payment_completed(
parsed_invoice.payee_pubkey.clone(),
Some(parsed_invoice),
req.label,
payment_res,
)
.await?;
Ok(SendPaymentResponse { payment })
.await
}
};

let payment = self
.on_payment_completed(
parsed_invoice.payee_pubkey.clone(),
Some(parsed_invoice),
req.label,
payment_res,
)
.await?;
Ok(SendPaymentResponse { payment })
}

fn get_trampoline_id(
&self,
req: &SendPaymentRequest,
invoice: &LNInvoice,
) -> Result<Option<Vec<u8>>, SendPaymentError> {
// If trampoline is turned off, return immediately
if !req.use_trampoline {
return Ok(None);
}

// Get the persisted LSP id. If no LSP, return early.
let lsp_pubkey = match self.persister.get_lsp_pubkey()? {
Some(lsp_pubkey) => lsp_pubkey,
None => return Ok(None),
};

// If the LSP is in the routing hint, don't use trampoline, but rather
// pay directly to the destination.
if invoice.routing_hints.iter().any(|hint| {
hint.hops
.last()
.map(|hop| hop.src_node_id == lsp_pubkey)
.unwrap_or(false)
}) {
return Ok(None);
}

// If ended up here, this payment will attempt trampoline.
Ok(Some(hex::decode(lsp_pubkey).map_err(|_| {
SendPaymentError::Generic {
err: "failed to decode lsp pubkey".to_string(),
}
})?))
}

/// Pay directly to a node id using keysend
Expand Down

0 comments on commit 42c0c07

Please sign in to comment.