Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Bolt12Invoice #605

Merged
merged 2 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/commonMain/kotlin/fr/acinq/lightning/Features.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import fr.acinq.lightning.utils.or
import kotlinx.serialization.Serializable

/** Feature scope as defined in Bolt 9. */
enum class FeatureScope { Init, Node, Invoice }
enum class FeatureScope { Init, Node, Invoice, Bolt12 }

enum class FeatureSupport {
Mandatory {
Expand Down Expand Up @@ -88,7 +88,7 @@ sealed class Feature {
object BasicMultiPartPayment : Feature() {
override val rfcName get() = "basic_mpp"
override val mandatory get() = 16
override val scopes: Set<FeatureScope> get() = setOf(FeatureScope.Init, FeatureScope.Node, FeatureScope.Invoice)
override val scopes: Set<FeatureScope> get() = setOf(FeatureScope.Init, FeatureScope.Node, FeatureScope.Invoice, FeatureScope.Bolt12)
}

@Serializable
Expand All @@ -105,6 +105,13 @@ sealed class Feature {
override val scopes: Set<FeatureScope> get() = setOf(FeatureScope.Init, FeatureScope.Node)
}

@Serializable
object RouteBlinding : Feature() {
override val rfcName get() = "option_route_blinding"
override val mandatory get() = 24
override val scopes: Set<FeatureScope> get() = setOf(FeatureScope.Init, FeatureScope.Node, FeatureScope.Invoice)
}

@Serializable
object ShutdownAnySegwit : Feature() {
override val rfcName get() = "option_shutdown_anysegwit"
Expand Down Expand Up @@ -268,6 +275,8 @@ data class Features(val activated: Map<Feature, FeatureSupport>, val unknown: Se

fun invoiceFeatures(): Features = Features(activated.filter { it.key.scopes.contains(FeatureScope.Invoice) }, unknown)

fun bolt12Features(): Features = Features(activated.filter { it.key.scopes.contains(FeatureScope.Bolt12) }, unknown)

/** NB: this method is not reflexive, see [[Features.areCompatible]] if you want symmetric validation. */
fun areSupported(remoteFeatures: Features): Boolean {
// we allow unknown odd features (it's ok to be odd)
Expand Down
7 changes: 4 additions & 3 deletions src/commonMain/kotlin/fr/acinq/lightning/db/PaymentsDb.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import fr.acinq.bitcoin.utils.Either
import fr.acinq.lightning.MilliSatoshi
import fr.acinq.lightning.ShortChannelId
import fr.acinq.lightning.channel.ChannelException
import fr.acinq.lightning.payment.Bolt11Invoice
import fr.acinq.lightning.payment.FinalFailure
import fr.acinq.lightning.payment.PaymentRequest
import fr.acinq.lightning.utils.*
Expand Down Expand Up @@ -147,7 +148,7 @@ data class IncomingPayment(val preimage: ByteVector32, val origin: Origin, val r

sealed class Origin {
/** A normal, invoice-based lightning payment. */
data class Invoice(val paymentRequest: PaymentRequest) : Origin()
data class Invoice(val paymentRequest: Bolt11Invoice) : Origin()

/** KeySend payments are spontaneous donations for which we didn't create an invoice. */
data object KeySend : Origin()
Expand Down Expand Up @@ -249,7 +250,7 @@ data class LightningOutgoingPayment(
) : OutgoingPayment() {

/** Create an outgoing payment in a pending status, without any parts yet. */
constructor(id: UUID, amount: MilliSatoshi, recipient: PublicKey, invoice: PaymentRequest) : this(id, amount, recipient, Details.Normal(invoice), listOf(), Status.Pending)
constructor(id: UUID, amount: MilliSatoshi, recipient: PublicKey, invoice: Bolt11Invoice) : this(id, amount, recipient, Details.Normal(invoice), listOf(), Status.Pending)

val paymentHash: ByteVector32 = details.paymentHash

Expand Down Expand Up @@ -284,7 +285,7 @@ data class LightningOutgoingPayment(
abstract val paymentHash: ByteVector32

/** A normal lightning payment. */
data class Normal(val paymentRequest: PaymentRequest) : Details() {
data class Normal(val paymentRequest: Bolt11Invoice) : Details() {
override val paymentHash: ByteVector32 = paymentRequest.paymentHash
}

Expand Down
6 changes: 3 additions & 3 deletions src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ data object Disconnected : PeerCommand()
sealed class PaymentCommand : PeerCommand()
private data object CheckPaymentsTimeout : PaymentCommand()
data class PayToOpenResponseCommand(val payToOpenResponse: PayToOpenResponse) : PeerCommand()
data class SendPayment(val paymentId: UUID, val amount: MilliSatoshi, val recipient: PublicKey, val paymentRequest: PaymentRequest, val trampolineFeesOverride: List<TrampolineFees>? = null) : PaymentCommand() {
data class SendPayment(val paymentId: UUID, val amount: MilliSatoshi, val recipient: PublicKey, val paymentRequest: Bolt11Invoice, val trampolineFeesOverride: List<TrampolineFees>? = null) : PaymentCommand() {
val paymentHash: ByteVector32 = paymentRequest.paymentHash
}

Expand Down Expand Up @@ -614,7 +614,7 @@ class Peer(
}
}

suspend fun createInvoice(paymentPreimage: ByteVector32, amount: MilliSatoshi?, description: Either<String, ByteVector32>, expirySeconds: Long? = null): PaymentRequest {
suspend fun createInvoice(paymentPreimage: ByteVector32, amount: MilliSatoshi?, description: Either<String, ByteVector32>, expirySeconds: Long? = null): Bolt11Invoice {
// we add one extra hop which uses a virtual channel with a "peer id", using the highest remote fees and expiry across all
// channels to maximize the likelihood of success on the first payment attempt
val remoteChannelUpdates = _channels.values.mapNotNull { channelState ->
Expand All @@ -627,7 +627,7 @@ class Peer(
}
val extraHops = listOf(
listOf(
PaymentRequest.TaggedField.ExtraHop(
Bolt11Invoice.TaggedField.ExtraHop(
nodeId = walletParams.trampolineNode.id,
shortChannelId = ShortChannelId.peerId(nodeParams.nodeId),
feeBase = remoteChannelUpdates.maxOfOrNull { it.feeBaseMsat } ?: walletParams.invoiceDefaultRoutingFees.feeBase,
Expand Down
Loading
Loading