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

RPC: parse BOLT12 invoices and offers #2843

Closed
wants to merge 2 commits into from
Closed
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
2 changes: 1 addition & 1 deletion contrib/eclair-cli.bash-completion
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ _eclair-cli()
*)
# works fine, but is too slow at the moment.
# allopts=$($eclaircli help 2>&1 | awk '$1 ~ /^"/ { sub(/,/, ""); print $1}' | sed 's/[":]//g')
allopts="allchannels allupdates audit bumpforceclose channel channelbalances channels channelstats close closedchannels connect cpfpbumpfees createinvoice deleteinvoice disconnect findroute findroutebetweennodes findroutetonode forceclose getdescriptors getinfo getinvoice getmasterxpub getnewaddress getreceivedinfo getsentinfo globalbalance listinvoices listpendinginvoices listreceivedpayments networkfees node nodes onchainbalance onchaintransactions open parseinvoice payinvoice payoffer peers rbfopen sendonchain sendonionmessage sendtonode sendtoroute signmessage splicein spliceout stop updaterelayfee usablebalances verifymessage"
allopts="allchannels allupdates audit bumpforceclose channel channelbalances channels channelstats close closedchannels connect cpfpbumpfees createinvoice deleteinvoice disconnect findroute findroutebetweennodes findroutetonode forceclose getdescriptors getinfo getinvoice getmasterxpub getnewaddress getreceivedinfo getsentinfo globalbalance listinvoices listpendinginvoices listreceivedpayments networkfees node nodes onchainbalance onchaintransactions open parseinvoice parseoffer payinvoice payoffer peers rbfopen sendonchain sendonionmessage sendtonode sendtoroute signmessage splicein spliceout stop updaterelayfee usablebalances verifymessage"

if ! [[ " $allopts " =~ " $prev " ]]; then # prevent double arguments
if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then
Expand Down
1 change: 1 addition & 0 deletions eclair-core/eclair-cli
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ and COMMAND is one of the available commands:
- listinvoices
- listpendinginvoices
- parseinvoice
- parseoffer
- deleteinvoice

=== Payment ===
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,10 @@ object InvoiceSerializer extends MinimalSerializer({
MilliSatoshiSerializer +
CltvExpiryDeltaSerializer
))
import fr.acinq.eclair.json.JsonSerializers.formats
val fieldList = List(
JField("prefix", JString(p.prefix)),
JField("timestamp", JLong(p.createdAt.toLong)),
JField("timestamp", Extraction.decompose(p.createdAt)),
JField("nodeId", JString(p.nodeId.toString())),
JField("serialized", JString(p.toString)),
p.description.fold(string => JField("description", JString(string)), hash => JField("descriptionHash", JString(hash.toHex))),
Expand All @@ -456,6 +457,7 @@ object InvoiceSerializer extends MinimalSerializer({
routingInfo
JObject(fieldList)
case p: Bolt12Invoice =>
import fr.acinq.eclair.json.JsonSerializers.formats
val fieldList = List(
JField("amount", JLong(p.amount.toLong)),
JField("nodeId", JString(p.nodeId.toString())),
Expand All @@ -475,8 +477,8 @@ object InvoiceSerializer extends MinimalSerializer({
JField("blindedNodeIds", JArray(blindedNodes.map(n => JString(n.blindedPublicKey.toString)).toList))
))
}).toList)),
JField("createdAt", JLong(p.createdAt.toLong)),
JField("expiresAt", JLong((p.createdAt + p.relativeExpiry).toLong)),
JField("createdAt", Extraction.decompose(p.createdAt)),
JField("expiresAt", Extraction.decompose((p.createdAt + p.relativeExpiry))),
JField("serialized", JString(p.toString)))
JObject(fieldList)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ private class OfferPayment(replyTo: ActorRef,
Behaviors.stopped
case None =>
context.spawnAnonymous(CompactBlindedPathsResolver(router)) ! Resolve(context.messageAdapter[Seq[ResolvedPath]](WrappedResolvedPaths), payload.invoice.blindedPaths)
context.log.info(s"BOLT12 invoice: ${payload.invoice}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: remove?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really. It's really useful for debugging. How else could we know what kind of invoices our counterparties send to us?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand...? Why is it useful to log the Bolt 12 invoice we receive? If the payment completes it will be stored in our payments DB. If the payment fails, do you really need the invoice to investigate why it failed? It will generally be easy to figure out what fails without it?

waitForResolvedPaths(payload.invoice)
}
case WrappedMessageResponse(Postman.Response(payload)) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import fr.acinq.eclair.payment.{Invoice, PaymentSettlingOnChain}
import fr.acinq.eclair.transactions.Transactions._
import fr.acinq.eclair.transactions.{CommitmentSpec, IncomingHtlc, OutgoingHtlc}
import fr.acinq.eclair.wire.internal.channel.ChannelCodecs
import fr.acinq.eclair.wire.protocol.OfferTypes.Offer
import fr.acinq.eclair.wire.protocol._
import org.scalatest.funsuite.AnyFunSuiteLike
import org.scalatest.matchers.should.Matchers
Expand Down Expand Up @@ -302,25 +303,31 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat
test("Bolt 11 invoice") {
val ref = "lnbcrt50n1p0fm9cdpp5al3wvsfkc6p7fxy89eu8gm4aww9mseu9syrcqtpa4mvx42qelkwqdq9v9ekgxqrrss9qypqsqsp5wl2t45v0hj4lgud0zjxcnjccd29ts0p2kh4vpw75vnhyyzyjtjtqarpvqg33asgh3z5ghfuvhvtf39xtnu9e7aqczpgxa9quwsxkd9rnwmx06pve9awgeewxqh90dqgrhzgsqc09ek6uejr93z8puafm6gsqgrk0hy"
val pr = Invoice.fromString(ref).get
JsonSerializers.serialization.write(pr)(JsonSerializers.formats) shouldBe """{"prefix":"lnbcrt","timestamp":1587386125,"nodeId":"03b207771ddba774e318970e9972da2491ff8e54f777ad0528b6526773730248a0","serialized":"lnbcrt50n1p0fm9cdpp5al3wvsfkc6p7fxy89eu8gm4aww9mseu9syrcqtpa4mvx42qelkwqdq9v9ekgxqrrss9qypqsqsp5wl2t45v0hj4lgud0zjxcnjccd29ts0p2kh4vpw75vnhyyzyjtjtqarpvqg33asgh3z5ghfuvhvtf39xtnu9e7aqczpgxa9quwsxkd9rnwmx06pve9awgeewxqh90dqgrhzgsqc09ek6uejr93z8puafm6gsqgrk0hy","description":"asd","paymentHash":"efe2e64136c683e498872e78746ebd738bb867858107802c3daed86aa819fd9c","expiry":3600,"amount":5000,"features":{"activated":{"var_onion_optin":"optional","payment_secret":"optional"},"unknown":[]},"routingInfo":[]}"""
JsonSerializers.serialization.write(pr)(JsonSerializers.formats) shouldBe """{"prefix":"lnbcrt","timestamp":{"iso":"2020-04-20T12:35:25Z","unix":1587386125},"nodeId":"03b207771ddba774e318970e9972da2491ff8e54f777ad0528b6526773730248a0","serialized":"lnbcrt50n1p0fm9cdpp5al3wvsfkc6p7fxy89eu8gm4aww9mseu9syrcqtpa4mvx42qelkwqdq9v9ekgxqrrss9qypqsqsp5wl2t45v0hj4lgud0zjxcnjccd29ts0p2kh4vpw75vnhyyzyjtjtqarpvqg33asgh3z5ghfuvhvtf39xtnu9e7aqczpgxa9quwsxkd9rnwmx06pve9awgeewxqh90dqgrhzgsqc09ek6uejr93z8puafm6gsqgrk0hy","description":"asd","paymentHash":"efe2e64136c683e498872e78746ebd738bb867858107802c3daed86aa819fd9c","expiry":3600,"amount":5000,"features":{"activated":{"var_onion_optin":"optional","payment_secret":"optional"},"unknown":[]},"routingInfo":[]}"""
}

test("Bolt 11 invoice with routing hints") {
val ref = "lntb1pst2q8xpp5qysan6j5xeq97tytxf7pfr0n75na8rztqhh03glmlgsqsyuqzgnqdqqxqrrss9qy9qsqsp5qq67gcxrn2drj5p0lc6p8wgdpqwxnc2h4s9kra5489q0fqsvhumsrzjqfqnj4upt5z6hdludky9vgk4ehzmwu2dk9rcevzczw5ywstehq79c83xr5qqqkqqqqqqqqlgqqqqqeqqjqrzjqwfn3p9278ttzzpe0e00uhyxhned3j5d9acqak5emwfpflp8z2cng838tqqqqxgqqqqqqqlgqqqqqeqqjqkxs4223x2r6sat65asfp0k2pze2rswe9np9vq08waqvsp832ffgymzgx8hgzejasesfxwcw6jj93azwq9klwuzmef3llns3n95pztgqpawp7an"
val pr = Invoice.fromString(ref).get
JsonSerializers.serialization.write(pr)(JsonSerializers.formats) shouldBe """{"prefix":"lntb","timestamp":1622474982,"nodeId":"03e89e4c3d41dc5332c2fb6cc66d12bfb9257ba681945a242f27a08d5ad210d891","serialized":"lntb1pst2q8xpp5qysan6j5xeq97tytxf7pfr0n75na8rztqhh03glmlgsqsyuqzgnqdqqxqrrss9qy9qsqsp5qq67gcxrn2drj5p0lc6p8wgdpqwxnc2h4s9kra5489q0fqsvhumsrzjqfqnj4upt5z6hdludky9vgk4ehzmwu2dk9rcevzczw5ywstehq79c83xr5qqqkqqqqqqqqlgqqqqqeqqjqrzjqwfn3p9278ttzzpe0e00uhyxhned3j5d9acqak5emwfpflp8z2cng838tqqqqxgqqqqqqqlgqqqqqeqqjqkxs4223x2r6sat65asfp0k2pze2rswe9np9vq08waqvsp832ffgymzgx8hgzejasesfxwcw6jj93azwq9klwuzmef3llns3n95pztgqpawp7an","description":"","paymentHash":"0121d9ea5436405f2c8b327c148df3f527d38c4b05eef8a3fbfa200813801226","expiry":3600,"features":{"activated":{"var_onion_optin":"optional","payment_secret":"optional","basic_mpp":"optional"},"unknown":[]},"routingInfo":[[{"nodeId":"02413957815d05abb7fc6d885622d5cdc5b7714db1478cb05813a8474179b83c5c","shortChannelId":"1975837x88x0","feeBase":1000,"feeProportionalMillionths":100,"cltvExpiryDelta":144}],[{"nodeId":"03933884aaf1d6b108397e5efe5c86bcf2d8ca8d2f700eda99db9214fc2712b134","shortChannelId":"1976152x25x0","feeBase":1000,"feeProportionalMillionths":100,"cltvExpiryDelta":144}]]}"""
JsonSerializers.serialization.write(pr)(JsonSerializers.formats) shouldBe """{"prefix":"lntb","timestamp":{"iso":"2021-05-31T15:29:42Z","unix":1622474982},"nodeId":"03e89e4c3d41dc5332c2fb6cc66d12bfb9257ba681945a242f27a08d5ad210d891","serialized":"lntb1pst2q8xpp5qysan6j5xeq97tytxf7pfr0n75na8rztqhh03glmlgsqsyuqzgnqdqqxqrrss9qy9qsqsp5qq67gcxrn2drj5p0lc6p8wgdpqwxnc2h4s9kra5489q0fqsvhumsrzjqfqnj4upt5z6hdludky9vgk4ehzmwu2dk9rcevzczw5ywstehq79c83xr5qqqkqqqqqqqqlgqqqqqeqqjqrzjqwfn3p9278ttzzpe0e00uhyxhned3j5d9acqak5emwfpflp8z2cng838tqqqqxgqqqqqqqlgqqqqqeqqjqkxs4223x2r6sat65asfp0k2pze2rswe9np9vq08waqvsp832ffgymzgx8hgzejasesfxwcw6jj93azwq9klwuzmef3llns3n95pztgqpawp7an","description":"","paymentHash":"0121d9ea5436405f2c8b327c148df3f527d38c4b05eef8a3fbfa200813801226","expiry":3600,"features":{"activated":{"var_onion_optin":"optional","payment_secret":"optional","basic_mpp":"optional"},"unknown":[]},"routingInfo":[[{"nodeId":"02413957815d05abb7fc6d885622d5cdc5b7714db1478cb05813a8474179b83c5c","shortChannelId":"1975837x88x0","feeBase":1000,"feeProportionalMillionths":100,"cltvExpiryDelta":144}],[{"nodeId":"03933884aaf1d6b108397e5efe5c86bcf2d8ca8d2f700eda99db9214fc2712b134","shortChannelId":"1976152x25x0","feeBase":1000,"feeProportionalMillionths":100,"cltvExpiryDelta":144}]]}"""
}

test("Bolt 11 invoice with metadata") {
val ref = "lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66sp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgqy9gw6ymamd20jumvdgpfphkhp8fzhhdhycw36egcmla5vlrtrmhs9t7psfy3hkkdqzm9eq64fjg558znccds5nhsfmxveha5xe0dykgpspdha0"
val pr = Invoice.fromString(ref).get
JsonSerializers.serialization.write(pr)(JsonSerializers.formats) shouldBe """{"prefix":"lnbc","timestamp":1496314658,"nodeId":"03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad","serialized":"lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66sp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgqy9gw6ymamd20jumvdgpfphkhp8fzhhdhycw36egcmla5vlrtrmhs9t7psfy3hkkdqzm9eq64fjg558znccds5nhsfmxveha5xe0dykgpspdha0","description":"payment metadata inside","paymentHash":"0001020304050607080900010203040506070809000102030405060708090102","paymentMetadata":"01fafaf0","amount":1000000000,"features":{"activated":{"var_onion_optin":"mandatory","payment_secret":"mandatory","option_payment_metadata":"mandatory"},"unknown":[]},"routingInfo":[]}"""
JsonSerializers.serialization.write(pr)(JsonSerializers.formats) shouldBe """{"prefix":"lnbc","timestamp":{"iso":"2017-06-01T10:57:38Z","unix":1496314658},"nodeId":"03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad","serialized":"lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66sp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgqy9gw6ymamd20jumvdgpfphkhp8fzhhdhycw36egcmla5vlrtrmhs9t7psfy3hkkdqzm9eq64fjg558znccds5nhsfmxveha5xe0dykgpspdha0","description":"payment metadata inside","paymentHash":"0001020304050607080900010203040506070809000102030405060708090102","paymentMetadata":"01fafaf0","amount":1000000000,"features":{"activated":{"var_onion_optin":"mandatory","payment_secret":"mandatory","option_payment_metadata":"mandatory"},"unknown":[]},"routingInfo":[]}"""
}

test("Bolt 12 invoice") {
val ref = "lni1qqsf4h8fsnpjkj057gjg9c3eqhv889440xh0z6f5kng9vsaad8pgq7sgqsdjuqsqpgxk66twd9kkzmpqdanxvetjzcss83y2e9lqnu7tht4ntvp24fksw26hwf5yrg6dyk2jz472efs2rjh42qsxlc5vp2m0rvmjcxn2y34wv0m5lyc7sdj7zksgn35dvxgqqqqqqqzjqsdjupkjtqssx05572ha26x39rczan5yft22pgwa72jw8gytavkm5ydn7yf5kpgh5zsq83y2e9lqnu7tht4ntvp24fksw26hwf5yrg6dyk2jz472efs2rjh4q2rd3ny0elv9m7mh38xxwe6ypfheeqeqlwgft05r6dhc50gtw0nv2qgrrl9x2qzzqvwukam32mhkdqrvwwcp5l6jcnnnezdq69vz8gdvvgmsqwk3efqf3f6gmf0ul63940awz429rdhhsts86s0r30e5nffwhrqw90xgxf7f60sm7tcclvyqwz7cer5q9223madstdy2p5q6y8qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqf2qheqqqqq2gprrgshynfszqyk2sgpvkrnmq53kv7r52rpnmtmd9ukredsnygsnymsurdy6e9la6l4hyz4qgxewqmftqggrcj9vjlsf709m46e4kq425mg89dthy6zp5dxjt9fp2l9v5c9pet6lqsx4k5r7rsld3hhe87psyy5cnhhzt4dz838f75734mted7pdsrflpvys23tkafmhctf3musnsaa42h6qjdggyqlhtevutzzpzlnwd8alq"
val pr = Invoice.fromString(ref).get
JsonSerializers.serialization.write(pr)(JsonSerializers.formats) shouldBe """{"amount":456001234,"nodeId":"03c48ac97e09f3cbbaeb35b02aaa6d072b57726841a34d25952157caca60a1caf5","paymentHash":"2cb0e7b052366787450c33daf6d2f2c3cb6132221326e1c1b49ac97fdd7eb720","description":"minimal offer","features":{"activated":{"var_onion_optin":"mandatory","option_route_blinding":"mandatory"},"unknown":[]},"blindedPaths":[{"introductionNodeId":"03c48ac97e09f3cbbaeb35b02aaa6d072b57726841a34d25952157caca60a1caf5","blindedNodeIds":["031fca650042031dcb777156ef66806c73b01a7f52c4e73c89a0d15823a1ac6237"]}],"createdAt":1665412681,"expiresAt":1665412981,"serialized":"lni1qqsf4h8fsnpjkj057gjg9c3eqhv889440xh0z6f5kng9vsaad8pgq7sgqsdjuqsqpgxk66twd9kkzmpqdanxvetjzcss83y2e9lqnu7tht4ntvp24fksw26hwf5yrg6dyk2jz472efs2rjh42qsxlc5vp2m0rvmjcxn2y34wv0m5lyc7sdj7zksgn35dvxgqqqqqqqzjqsdjupkjtqssx05572ha26x39rczan5yft22pgwa72jw8gytavkm5ydn7yf5kpgh5zsq83y2e9lqnu7tht4ntvp24fksw26hwf5yrg6dyk2jz472efs2rjh4q2rd3ny0elv9m7mh38xxwe6ypfheeqeqlwgft05r6dhc50gtw0nv2qgrrl9x2qzzqvwukam32mhkdqrvwwcp5l6jcnnnezdq69vz8gdvvgmsqwk3efqf3f6gmf0ul63940awz429rdhhsts86s0r30e5nffwhrqw90xgxf7f60sm7tcclvyqwz7cer5q9223madstdy2p5q6y8qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqf2qheqqqqq2gprrgshynfszqyk2sgpvkrnmq53kv7r52rpnmtmd9ukredsnygsnymsurdy6e9la6l4hyz4qgxewqmftqggrcj9vjlsf709m46e4kq425mg89dthy6zp5dxjt9fp2l9v5c9pet6lqsx4k5r7rsld3hhe87psyy5cnhhzt4dz838f75734mted7pdsrflpvys23tkafmhctf3musnsaa42h6qjdggyqlhtevutzzpzlnwd8alq"}"""
JsonSerializers.serialization.write(pr)(JsonSerializers.formats) shouldBe """{"amount":456001234,"nodeId":"03c48ac97e09f3cbbaeb35b02aaa6d072b57726841a34d25952157caca60a1caf5","paymentHash":"2cb0e7b052366787450c33daf6d2f2c3cb6132221326e1c1b49ac97fdd7eb720","description":"minimal offer","features":{"activated":{"var_onion_optin":"mandatory","option_route_blinding":"mandatory"},"unknown":[]},"blindedPaths":[{"introductionNodeId":"03c48ac97e09f3cbbaeb35b02aaa6d072b57726841a34d25952157caca60a1caf5","blindedNodeIds":["031fca650042031dcb777156ef66806c73b01a7f52c4e73c89a0d15823a1ac6237"]}],"createdAt":{"iso":"2022-10-10T14:38:01Z","unix":1665412681},"expiresAt":{"iso":"2022-10-10T14:43:01Z","unix":1665412981},"serialized":"lni1qqsf4h8fsnpjkj057gjg9c3eqhv889440xh0z6f5kng9vsaad8pgq7sgqsdjuqsqpgxk66twd9kkzmpqdanxvetjzcss83y2e9lqnu7tht4ntvp24fksw26hwf5yrg6dyk2jz472efs2rjh42qsxlc5vp2m0rvmjcxn2y34wv0m5lyc7sdj7zksgn35dvxgqqqqqqqzjqsdjupkjtqssx05572ha26x39rczan5yft22pgwa72jw8gytavkm5ydn7yf5kpgh5zsq83y2e9lqnu7tht4ntvp24fksw26hwf5yrg6dyk2jz472efs2rjh4q2rd3ny0elv9m7mh38xxwe6ypfheeqeqlwgft05r6dhc50gtw0nv2qgrrl9x2qzzqvwukam32mhkdqrvwwcp5l6jcnnnezdq69vz8gdvvgmsqwk3efqf3f6gmf0ul63940awz429rdhhsts86s0r30e5nffwhrqw90xgxf7f60sm7tcclvyqwz7cer5q9223madstdy2p5q6y8qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqf2qheqqqqq2gprrgshynfszqyk2sgpvkrnmq53kv7r52rpnmtmd9ukredsnygsnymsurdy6e9la6l4hyz4qgxewqmftqggrcj9vjlsf709m46e4kq425mg89dthy6zp5dxjt9fp2l9v5c9pet6lqsx4k5r7rsld3hhe87psyy5cnhhzt4dz838f75734mted7pdsrflpvys23tkafmhctf3musnsaa42h6qjdggyqlhtevutzzpzlnwd8alq"}"""
}

test("Bolt 12 offer") {
val ref = "lno1qgsyxjtl6luzd9t3pr62xr7eemp6awnejusgf6gw45q75vcfqqqqqqqgqgcrjzsdgfhkcapqxyezqmmxvejhyrqrqgqqq93pq0zg4jt7p8euhwhtxkcz42ndqu44wunggx356fv4y9tu4jnq58902"
val o = Offer.decode(ref).get
JsonSerializers.serialization.write(o)(JsonSerializers.formats) shouldBe """{"records":{"OfferChains":{"chains":["43497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000"]},"OfferDescription":{"description":"Bolt 12 offer"},"OfferAmount":{"amount":12345},"OfferFeatures":{"features":{"activated":{"basic_mpp":"optional"},"unknown":[]}},"OfferNodeId":{"publicKey":"03c48ac97e09f3cbbaeb35b02aaa6d072b57726841a34d25952157caca60a1caf5"}}}"""
}

test("GlobalBalance serializer") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import fr.acinq.eclair.ApiTypes.ChannelIdentifier
import fr.acinq.eclair.api.serde.FormParamExtractors._
import fr.acinq.eclair.api.serde.JsonSupport._
import fr.acinq.eclair.blockchain.fee.ConfirmationPriority
import fr.acinq.eclair.payment.Bolt11Invoice
import fr.acinq.eclair.payment.{Bolt11Invoice, Invoice}
import fr.acinq.eclair.wire.protocol.OfferTypes.Offer
import fr.acinq.eclair.{MilliSatoshi, Paginated, ShortChannelId, TimestampSecond}

Expand All @@ -47,7 +47,7 @@ trait ExtraDirectives extends Directives {
val outPointsFormParam: NameUnmarshallerReceptacle[List[OutPoint]] = "outpoints".as[List[OutPoint]](outPointListUnmarshaller)
val paymentHashFormParam: NameUnmarshallerReceptacle[ByteVector32] = "paymentHash".as[ByteVector32](bytes32Unmarshaller)
val amountMsatFormParam: NameReceptacle[MilliSatoshi] = "amountMsat".as[MilliSatoshi]
val invoiceFormParam: NameReceptacle[Bolt11Invoice] = "invoice".as[Bolt11Invoice]
val invoiceFormParam: NameUnmarshallerReceptacle[Invoice] = "invoice".as[Invoice](invoiceUnmarshaller)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should keep this for Bolt 11 only, Bolt 12 invoices should be obtained with the invoice_request flow and never accepted as a parameter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand the question, sorry.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually not a question but a statement. I guess t-bast added a question mark to ask if you object to this statement.
Your reason to use it is parseinvoice and I agree that it would be nice to have, but it would be cleaner to keep this only for Bolt11Invoice (renaming it to bolt11invoiceFormParam) and create a new invoiceFormParam that you use only for parseinvoice.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the spec point of view, Bolt 12 invoices should not be exposed to end users, only the offer should be exposed. You shouldn't be able to explicitly pay a Bolt 12 invoice, APIs should only allow you to pay a Bolt 12 offer.

So I'm not sure why you'd want to be able to parse them, since they're meant to be internal objects that aren't exposed to end users. On top of that, they're just a TLV stream, so it won't look nice in JSON at all...

val routeFormatFormParam: NameUnmarshallerReceptacle[RouteFormat] = "format".as[RouteFormat](routeFormatUnmarshaller)
val ignoreNodeIdsFormParam: NameUnmarshallerReceptacle[List[PublicKey]] = "ignoreNodeIds".as[List[PublicKey]](pubkeyListUnmarshaller)
val ignoreShortChannelIdsFormParam: NameUnmarshallerReceptacle[List[ShortChannelId]] = "ignoreShortChannelIds".as[List[ShortChannelId]](shortChannelIdsUnmarshaller)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ trait Invoice {
}
}

val invoiceRoutes: Route = createInvoice ~ getInvoice ~ listInvoices ~ listPendingInvoices ~ parseInvoice ~ deleteInvoice
val parseOffer: Route = postRequest("parseoffer") { implicit t =>
formFields(offerFormParam) { offer =>
complete(offer)
}
}

val invoiceRoutes: Route = createInvoice ~ getInvoice ~ listInvoices ~ listPendingInvoices ~ parseInvoice ~ deleteInvoice ~ parseOffer

}
Loading
Loading