Skip to content

Commit e378122

Browse files
committed
invoice requests must have an amount
1 parent 7491779 commit e378122

File tree

4 files changed

+9
-15
lines changed

4 files changed

+9
-15
lines changed

eclair-core/src/main/scala/fr/acinq/eclair/payment/Bolt12Invoice.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ case class Bolt12Invoice(records: TlvStream[InvoiceTlv]) extends Invoice {
6060
Left("Wrong node id")
6161
} else if (isExpired()) {
6262
Left("Invoice expired")
63-
} else if (!request.amount.forall(_ == amount)) {
63+
} else if (request.amount != amount) {
6464
Left("Incompatible amount")
6565
} else if (!Features.areCompatible(request.features, features.bolt12Features())) {
6666
Left("Incompatible features")
@@ -106,8 +106,7 @@ object Bolt12Invoice {
106106
paths: Seq[PaymentBlindedRoute],
107107
additionalTlvs: Set[InvoiceTlv] = Set.empty,
108108
customTlvs: Set[GenericTlv] = Set.empty): Bolt12Invoice = {
109-
require(request.amount.nonEmpty || request.offer.amount.nonEmpty)
110-
val amount = request.amount.orElse(request.offer.amount.map(_ * request.quantity)).get
109+
val amount = request.amount
111110
val tlvs: Set[InvoiceTlv] = removeSignature(request.records).records ++ Set(
112111
Some(InvoicePaths(paths.map(_.route))),
113112
Some(InvoiceBlindedPay(paths.map(_.paymentInfo))),

eclair-core/src/main/scala/fr/acinq/eclair/payment/offer/DefaultOfferHandler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ object DefaultOfferHandler {
3434
Behaviors.setup(context =>
3535
Behaviors.receiveMessage {
3636
case OfferManager.HandleInvoiceRequest(replyTo, invoiceRequest) =>
37-
val amount = invoiceRequest.amount.getOrElse(10_000_000 msat)
37+
val amount = invoiceRequest.amount
3838
invoiceRequest.offer.contactInfos.head match {
3939
case OfferTypes.RecipientNodeId(_) =>
4040
val route = InvoiceRequestActor.Route(Nil, nodeParams.channelConf.maxExpiryDelta)

eclair-core/src/main/scala/fr/acinq/eclair/payment/receive/MultiPartHandler.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,7 @@ object MultiPartHandler {
292292
paymentPreimage: ByteVector32,
293293
additionalTlvs: Set[InvoiceTlv] = Set.empty,
294294
customTlvs: Set[GenericTlv] = Set.empty) extends ReceivePayment {
295-
require(invoiceRequest.offer.amount.nonEmpty || invoiceRequest.amount.nonEmpty, "an amount must be specified in the offer or in the invoice request")
296-
297-
val amount = invoiceRequest.amount.orElse(invoiceRequest.offer.amount.map(_ * invoiceRequest.quantity)).get
295+
val amount = invoiceRequest.amount
298296
}
299297

300298
object CreateInvoiceActor {

eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/OfferTypes.scala

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -347,22 +347,18 @@ object OfferTypes {
347347

348348
val metadata: ByteVector = records.get[InvoiceRequestMetadata].get.data
349349
val chain: BlockHash = records.get[InvoiceRequestChain].map(_.hash).getOrElse(Block.LivenetGenesisBlock.hash)
350-
val amount: Option[MilliSatoshi] = records.get[InvoiceRequestAmount].map(_.amount)
350+
private val amount_opt: Option[MilliSatoshi] = records.get[InvoiceRequestAmount].map(_.amount)
351351
val features: Features[Bolt12Feature] = records.get[InvoiceRequestFeatures].map(_.features.bolt12Features()).getOrElse(Features.empty)
352352
val quantity_opt: Option[Long] = records.get[InvoiceRequestQuantity].map(_.quantity)
353353
val quantity: Long = quantity_opt.getOrElse(1)
354+
private val baseInvoiceAmount_opt = offer.amount.map(_ * quantity)
355+
val amount: MilliSatoshi = amount_opt.orElse(baseInvoiceAmount_opt).get
354356
val payerId: PublicKey = records.get[InvoiceRequestPayerId].get.publicKey
355357
val payerNote: Option[String] = records.get[InvoiceRequestPayerNote].map(_.note)
356358
private val signature: ByteVector64 = records.get[Signature].get.signature
357359

358360
def isValid: Boolean = {
359-
val amountOk = offer.amount match {
360-
case Some(offerAmount) =>
361-
val baseInvoiceAmount = offerAmount * quantity
362-
amount.forall(baseInvoiceAmount <= _)
363-
case None => amount.nonEmpty
364-
}
365-
amountOk &&
361+
amount_opt.forall(a => baseInvoiceAmount_opt.forall(b => a >= b)) &&
366362
offer.chains.contains(chain) &&
367363
offer.quantityMax.forall(max => quantity_opt.nonEmpty && quantity <= max) &&
368364
quantity_opt.forall(_ => offer.quantityMax.nonEmpty) &&
@@ -426,6 +422,7 @@ object OfferTypes {
426422
_ -> ()
427423
)
428424
if (records.get[InvoiceRequestMetadata].isEmpty) return Left(MissingRequiredTlv(UInt64(0)))
425+
if (records.get[InvoiceRequestAmount].isEmpty && records.get[OfferAmount].isEmpty) return Left(MissingRequiredTlv(UInt64(82)))
429426
if (records.get[InvoiceRequestPayerId].isEmpty) return Left(MissingRequiredTlv(UInt64(88)))
430427
if (records.get[Signature].isEmpty) return Left(MissingRequiredTlv(UInt64(240)))
431428
if (records.unknown.exists(!isInvoiceRequestTlv(_))) return Left(ForbiddenTlv(records.unknown.find(!isInvoiceRequestTlv(_)).get.tag))

0 commit comments

Comments
 (0)