Skip to content

Commit 3fbdb48

Browse files
ffi: use dictionary for PaidBolt12Invoice due to UniFFI limitation
This patch reverts PaidBolt12Invoice to a dictionary format in the UDL while keeping the simplified structure without the redundant kind field. Problem: UniFFI doesn't support Object types (interfaces) in enum variant data. The previous commit attempted to use [Enum] interface format, but this fails to compile because Bolt12Invoice and StaticInvoice are defined as interfaces. Solution: Use a dictionary with optional fields instead of an enum. Users check which field is Some to determine the invoice type: - bolt12_invoice: A standard BOLT12 invoice (supports proof of payment) - static_invoice: A static invoice for async payments This is still an improvement over the original implementation as it removes the redundant PaidBolt12InvoiceKind enum field. The non-uniffi Rust API keeps the cleaner enum representation. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4442e83 commit 3fbdb48

File tree

2 files changed

+36
-24
lines changed

2 files changed

+36
-24
lines changed

bindings/ldk_node.udl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -873,10 +873,12 @@ interface StaticInvoice {
873873
sequence<u8> encode();
874874
};
875875

876-
[Enum]
877-
interface PaidBolt12Invoice {
878-
Bolt12Invoice(Bolt12Invoice invoice);
879-
StaticInvoice(StaticInvoice invoice);
876+
// Note: UniFFI doesn't support Object types in enum variant data, so we use
877+
// a dictionary with optional fields. Check which field is Some to determine
878+
// the invoice type.
879+
dictionary PaidBolt12Invoice {
880+
Bolt12Invoice? bolt12_invoice;
881+
StaticInvoice? static_invoice;
880882
};
881883

882884
[Custom]

src/ffi/types.rs

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -801,39 +801,43 @@ impl AsRef<LdkStaticInvoice> for StaticInvoice {
801801
///
802802
/// This is used in [`Event::PaymentSuccessful`] to provide proof of payment for BOLT12 payments.
803803
///
804+
/// Note: Due to UniFFI limitations with Object types in enum variants, this is exposed as a
805+
/// struct with optional fields. Check which field is `Some` to determine the invoice type:
806+
/// - `bolt12_invoice`: A standard BOLT12 invoice (supports proof of payment)
807+
/// - `static_invoice`: A static invoice for async payments (does NOT support proof of payment)
808+
///
804809
/// [`Event::PaymentSuccessful`]: crate::Event::PaymentSuccessful
805810
#[derive(Debug, Clone, PartialEq, Eq)]
806-
pub enum PaidBolt12Invoice {
807-
/// A standard BOLT12 invoice.
808-
Bolt12Invoice(Arc<Bolt12Invoice>),
809-
/// A static invoice for async payments.
810-
StaticInvoice(Arc<StaticInvoice>),
811+
pub struct PaidBolt12Invoice {
812+
/// The paid BOLT12 invoice, if this is a regular BOLT12 invoice.
813+
pub bolt12_invoice: Option<Arc<Bolt12Invoice>>,
814+
/// The paid static invoice, if this is a static invoice (async payment).
815+
pub static_invoice: Option<Arc<StaticInvoice>>,
811816
}
812817

813818
impl From<LdkPaidBolt12Invoice> for PaidBolt12Invoice {
814819
fn from(ldk_invoice: LdkPaidBolt12Invoice) -> Self {
815820
match ldk_invoice {
816-
LdkPaidBolt12Invoice::Bolt12Invoice(invoice) => {
817-
PaidBolt12Invoice::Bolt12Invoice(Arc::new(Bolt12Invoice { inner: invoice }))
821+
LdkPaidBolt12Invoice::Bolt12Invoice(invoice) => PaidBolt12Invoice {
822+
bolt12_invoice: Some(Arc::new(Bolt12Invoice { inner: invoice })),
823+
static_invoice: None,
818824
},
819-
LdkPaidBolt12Invoice::StaticInvoice(invoice) => {
820-
PaidBolt12Invoice::StaticInvoice(Arc::new(StaticInvoice { inner: invoice }))
825+
LdkPaidBolt12Invoice::StaticInvoice(invoice) => PaidBolt12Invoice {
826+
bolt12_invoice: None,
827+
static_invoice: Some(Arc::new(StaticInvoice { inner: invoice })),
821828
},
822829
}
823830
}
824831
}
825832

826833
impl Writeable for PaidBolt12Invoice {
827834
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), lightning::io::Error> {
828-
match self {
829-
PaidBolt12Invoice::Bolt12Invoice(invoice) => {
830-
0u8.write(writer)?;
831-
invoice.inner.encode().write(writer)?;
832-
},
833-
PaidBolt12Invoice::StaticInvoice(invoice) => {
834-
1u8.write(writer)?;
835-
invoice.inner.encode().write(writer)?;
836-
},
835+
if let Some(invoice) = &self.bolt12_invoice {
836+
0u8.write(writer)?;
837+
invoice.inner.encode().write(writer)?;
838+
} else if let Some(invoice) = &self.static_invoice {
839+
1u8.write(writer)?;
840+
invoice.inner.encode().write(writer)?;
837841
}
838842
Ok(())
839843
}
@@ -847,12 +851,18 @@ impl Readable for PaidBolt12Invoice {
847851
0 => {
848852
let invoice =
849853
LdkBolt12Invoice::try_from(bytes).map_err(|_| DecodeError::InvalidValue)?;
850-
Ok(PaidBolt12Invoice::Bolt12Invoice(Arc::new(Bolt12Invoice { inner: invoice })))
854+
Ok(PaidBolt12Invoice {
855+
bolt12_invoice: Some(Arc::new(Bolt12Invoice { inner: invoice })),
856+
static_invoice: None,
857+
})
851858
},
852859
1 => {
853860
let invoice =
854861
LdkStaticInvoice::try_from(bytes).map_err(|_| DecodeError::InvalidValue)?;
855-
Ok(PaidBolt12Invoice::StaticInvoice(Arc::new(StaticInvoice { inner: invoice })))
862+
Ok(PaidBolt12Invoice {
863+
bolt12_invoice: None,
864+
static_invoice: Some(Arc::new(StaticInvoice { inner: invoice })),
865+
})
856866
},
857867
_ => Err(DecodeError::InvalidValue),
858868
}

0 commit comments

Comments
 (0)