Skip to content

Commit

Permalink
Offer types (#602)
Browse files Browse the repository at this point in the history
Adds types for Bolt 12 offers and invoice requests (but not invoice yet).
  • Loading branch information
thomash-acinq authored Feb 19, 2024
1 parent 9bd3489 commit 2fe01d5
Show file tree
Hide file tree
Showing 3 changed files with 1,410 additions and 1 deletion.
57 changes: 56 additions & 1 deletion src/commonMain/kotlin/fr/acinq/lightning/wire/MessageOnion.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import fr.acinq.bitcoin.io.ByteArrayInput
import fr.acinq.bitcoin.io.ByteArrayOutput
import fr.acinq.bitcoin.io.Input
import fr.acinq.bitcoin.io.Output
import fr.acinq.lightning.EncodedNodeId
import fr.acinq.lightning.crypto.RouteBlinding

sealed class OnionMessagePayloadTlv : Tlv {
Expand Down Expand Up @@ -58,6 +57,62 @@ sealed class OnionMessagePayloadTlv : Tlv {
EncryptedData(ByteVector(LightningCodecs.bytes(input, input.availableBytes)))
}
}

/**
* In order to pay a Bolt 12 offer, we must send an onion message to request an invoice corresponding to that offer.
* The creator of the offer will send us an invoice back through our blinded reply path.
*/
data class InvoiceRequest(val tlvs: TlvStream<OfferTypes.InvoiceRequestTlv>) : OnionMessagePayloadTlv() {
override val tag: Long get() = InvoiceRequest.tag
override fun write(out: Output) = OfferTypes.InvoiceRequest.tlvSerializer.write(tlvs, out)

companion object : TlvValueReader<InvoiceRequest> {
const val tag: Long = 64

override fun read(input: Input): InvoiceRequest =
InvoiceRequest(OfferTypes.InvoiceRequest.tlvSerializer.read(input))
}
}

/**
* When receiving an invoice request, we must send an onion message back containing an invoice corresponding to the
* requested offer (if it was an offer we published).
*/
data class Invoice(val tlvs: TlvStream<OfferTypes.InvoiceTlv>) : OnionMessagePayloadTlv() {
override val tag: Long get() = Invoice.tag
override fun write(out: Output) = OfferTypes.Invoice.tlvSerializer.write(tlvs, out)

companion object : TlvValueReader<Invoice> {
const val tag: Long = 66

override fun read(input: Input): Invoice =
Invoice(OfferTypes.Invoice.tlvSerializer.read(input))
}
}

/**
* This message may be used when we receive an invalid invoice or invoice request.
* It contains information helping senders figure out why their message was invalid.
*/
data class InvoiceError(val tlvs: TlvStream<OfferTypes.InvoiceErrorTlv>) : OnionMessagePayloadTlv() {
override val tag: Long get() = InvoiceError.tag
override fun write(out: Output) = tlvSerializer.write(tlvs, out)

companion object : TlvValueReader<InvoiceError> {
const val tag: Long = 68

val tlvSerializer = TlvStreamSerializer(
true, @Suppress("UNCHECKED_CAST") mapOf(
OfferTypes.ErroneousField.tag to OfferTypes.ErroneousField.Companion as TlvValueReader<OfferTypes.InvoiceErrorTlv>,
OfferTypes.SuggestedValue.tag to OfferTypes.SuggestedValue.Companion as TlvValueReader<OfferTypes.InvoiceErrorTlv>,
OfferTypes.Error.tag to OfferTypes.Error.Companion as TlvValueReader<OfferTypes.InvoiceErrorTlv>,
)
)

override fun read(input: Input): InvoiceError =
InvoiceError(tlvSerializer.read(input))
}
}
}

data class MessageOnion(val records: TlvStream<OnionMessagePayloadTlv>) {
Expand Down
Loading

0 comments on commit 2fe01d5

Please sign in to comment.