From 0ef14ef5a257c794b51440dfaf16d44797f08778 Mon Sep 17 00:00:00 2001 From: Thomas HUET Date: Fri, 3 Oct 2025 11:48:15 +0200 Subject: [PATCH] Offers in EUR --- .../kotlin/fr/acinq/lightning/NodeParams.kt | 2 +- .../fr/acinq/lightning/payment/OfferManager.kt | 12 ++++-------- .../kotlin/fr/acinq/lightning/wire/OfferTypes.kt | 5 +++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/NodeParams.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/NodeParams.kt index fd2bcc079..9563cd2d7 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/NodeParams.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/NodeParams.kt @@ -283,7 +283,7 @@ data class NodeParams( fun randomOffer(trampolineNodeId: PublicKey, amount: MilliSatoshi?, description: String?): Pair { // We generate a random nonce to ensure that this offer is unique. val nonce = randomBytes32() - return OfferManager.deterministicOffer(chainHash, nodePrivateKey, trampolineNodeId, amount, description, nonce) + return OfferManager.deterministicOffer(chainHash, nodePrivateKey, trampolineNodeId, amount?.toLong(), description, nonce) } } diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/payment/OfferManager.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/payment/OfferManager.kt index 9760ebbde..3ee21b6d4 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/payment/OfferManager.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/payment/OfferManager.kt @@ -20,6 +20,7 @@ import fr.acinq.lightning.message.OnionMessages.buildMessage import fr.acinq.lightning.utils.currentTimestampMillis import fr.acinq.lightning.utils.toByteVector import fr.acinq.lightning.wire.* +import fr.acinq.lightning.wire.OfferTypes.OfferAmount import kotlinx.coroutines.flow.MutableSharedFlow sealed class OnionMessageAction { @@ -232,7 +233,7 @@ class OfferManager(val nodeParams: NodeParams, val walletParams: WalletParams, v private fun isOurOffer(offer: OfferTypes.Offer, pathId: ByteVector?, blindedPrivateKey: PrivateKey): Boolean = when { pathId != null && pathId.size() != 32 -> false else -> { - val expected = deterministicOffer(nodeParams.chainHash, nodeParams.nodePrivateKey, walletParams.trampolineNode.id, offer.amountMsat, offer.description, pathId?.let { ByteVector32(it) }) + val expected = deterministicOffer(nodeParams.chainHash, nodeParams.nodePrivateKey, walletParams.trampolineNode.id, offer.records.get()?.amount, offer.description, pathId?.let { ByteVector32(it) }) expected == Pair(offer, blindedPrivateKey) } } @@ -246,7 +247,7 @@ class OfferManager(val nodeParams: NodeParams, val walletParams: WalletParams, v chainHash: BlockHash, nodePrivateKey: PrivateKey, trampolineNodeId: PublicKey, - amount: MilliSatoshi?, + amount: Long?, description: String?, pathId: ByteVector32?, ): Pair { @@ -255,15 +256,10 @@ class OfferManager(val nodeParams: NodeParams, val walletParams: WalletParams, v // - the offer parameters (amount, description and pathId) // - our trampoline node, which is used as an introduction node for the offer's blinded path // - our private key, which ensures that nobody else can generate the same path key secret - val tweak = when { - amount == null && description == null && pathId == null -> "bolt 12 default offer".encodeToByteArray().byteVector() - else -> { + val tweak = "bolt 12 deterministic offer".encodeToByteArray().byteVector() + - Crypto.sha256("offer amount".encodeToByteArray() + (amount?.let { Pack.writeInt64BE(it.msat) } ?: ByteArray(0))) + Crypto.sha256("offer description".encodeToByteArray() + (description?.encodeToByteArray() ?: ByteArray(0))) + Crypto.sha256("offer path_id".encodeToByteArray().byteVector() + (pathId ?: ByteVector.empty)) - } - } val sessionKey = PrivateKey(Crypto.sha256(tweak + trampolineNodeId.value + nodePrivateKey.value).byteVector32()) return OfferTypes.Offer.createBlindedOffer(chainHash, nodePrivateKey, trampolineNodeId, amount, description, Features.empty, sessionKey, pathId) } diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/wire/OfferTypes.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/wire/OfferTypes.kt index 7b11a5d73..7df84cd60 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/wire/OfferTypes.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/wire/OfferTypes.kt @@ -797,7 +797,7 @@ object OfferTypes { chainHash: BlockHash, nodePrivateKey: PrivateKey, trampolineNodeId: PublicKey, - amount: MilliSatoshi?, + amount: Long?, description: String?, features: Features, blindedPathSessionKey: PrivateKey, @@ -811,7 +811,8 @@ object OfferTypes { ) val tlvs = setOfNotNull( if (chainHash != Block.LivenetGenesisBlock.hash) OfferChains(listOf(chainHash)) else null, - amount?.let { OfferAmount(it.toLong()) }, + amount?.let { OfferAmount(it) }, + amount?.let { OfferCurrency("EUR") }, description?.let { OfferDescription(it) }, features.bolt12Features().let { if (it != Features.empty) OfferFeatures(it.toByteArray().toByteVector()) else null }, // Note that we don't include an offer_node_id since we're using a blinded path.