Skip to content

Commit

Permalink
Add oniion message and fix demo project
Browse files Browse the repository at this point in the history
  • Loading branch information
22388o committed Dec 3, 2024
1 parent c1c7277 commit 2c11bd7
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 187 deletions.
1 change: 1 addition & 0 deletions bolt12.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const TAGCODES = {
offer_issuer_id: 3,
offer_issuer_node_id: 4,
offer_issuer_signature: 5,
onion_message: 10,
invoice_request: 7,
invreq_metadata: 8,
payment_hash: 3,
Expand Down
1 change: 1 addition & 0 deletions bolt12.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const TAGCODES = {
offer_issuer_node_id: 4,
offer_issuer_signature: 5,
invoice_request: 7,
onion_message: 10,
invreq_metadata: 8,
payment_hash: 3,
description: 13,
Expand Down
64 changes: 39 additions & 25 deletions examples/demo.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {decode} from 'light-bolt11-decoder'
import React, {useState} from 'react'
import {render} from 'react-dom'
import useComputedState from 'use-computed-state'
import styled, {css} from 'styled-components'
import { decode as decodeBolt12 } from 'light-bolt12-decoder';
import React, { useState } from 'react';
import { render } from 'react-dom';
import useComputedState from 'use-computed-state';
import styled, { css } from 'styled-components';

const TAGCOLORS = {
lightning_network: 'rgb(31, 31, 40)',
Expand All @@ -23,39 +23,41 @@ const TAGCOLORS = {
fallback_address: 'rgb(27, 51, 93)',
route_hint: 'rgb(131, 93, 233)',
signature: 'rgb(51, 44, 138)',
checksum: 'rgb(31, 31, 40)'
}
checksum: 'rgb(31, 31, 40)',
// BOLT12-specific tags
offer: 'rgb(62, 38, 58)',
recurrence: 'rgb(24, 98, 118)',
payer_key: 'rgb(92, 12, 132)',
};

function getTagColor(name) {
return TAGCOLORS[name] || 'rgb(0, 0, 0)'
return TAGCOLORS[name] || 'rgb(0, 0, 0)';
}

const Textarea = styled.textarea`
margin: 18px;
width: 90%;
height: 80px;
`
`;

const Row = styled.div``
const Row = styled.div``;

const PaymentRequest = styled.div`
white-space: pre-wrap;
word-wrap: break-word;
word-break: break-all;
`
`;

const Section = styled.span`
font-family: monospace;
font-size: 25px;
${props => {
console.log(props)
return css`
background-color: ${getTagColor(props.name)
.replace('rgb', 'rgba')
.replace(')', ', 0.2)')};
`
`;
}}
&:hover {
Expand All @@ -66,7 +68,7 @@ const Section = styled.span`
background-color: ${getTagColor(props.name)};
`}
}
`
`;

const Info = styled.div`
margin: 8px;
Expand All @@ -77,16 +79,28 @@ const Info = styled.div`
css`
background-color: ${getTagColor(props.name)};
`}
`
`;

function decode(invoice) {
if (invoice.startsWith('lnb')) return decodeBolt11(invoice);
if (invoice.startsWith('lno')) return decodeBolt12(invoice);
throw new Error('Unknown invoice type');
}

function Demo() {
const [pr, setPR] = useState(
'lnbc120n1p39wfrtpp5n24pj26fpl0p9dsyxx47ttklcazd7z87pkmru4geca6n6kz4409qdpzve5kzar2v9nr5gpqw3hjqsrvde68scn0wssp5mqr9mkd94jm5z65x94msas8hqhcuc96tqtre3wqkrm305tcvzgmqxqy9gcqcqzys9qrsgqrzjqtx3k77yrrav9hye7zar2rtqlfkytl094dsp0ms5majzth6gt7ca6uhdkxl983uywgqqqqqqqqqq86qqjqrzjq0h9s36s2kpql0a99c6k4zfq7chcx9sjnsund8damcl96qvc4833tx69gvk26e6efsqqqqlgqqqqpjqqjqrzjqd98kxkpyw0l9tyy8r8q57k7zpy9zjmh6sez752wj6gcumqnj3yxzhdsmg6qq56utgqqqqqqqqqqqeqqjqxahrxthcc8syrjyklsg57mzsqauargyc748lf8s2dezw5x7aww0j5v4k5wz9p5x4ax840h4q0qmgucglkesgzvvc22wwmqc756ec02qp34yg8p'
)
const parsed = useComputedState(() => pr && decode(pr), [pr])
const [info, setInfo] = useState(null)

console.log(parsed)
);
const parsed = useComputedState(() => {
try {
return pr && decode(pr);
} catch (e) {
console.error('Invalid invoice format:', e);
return null;
}
}, [pr]);

const [info, setInfo] = useState(null);

return (
<>
Expand All @@ -96,12 +110,12 @@ function Demo() {
<PaymentRequest>
{parsed.sections.map(section => (
<Section
key={section.letters}
key={section.letters || section.name}
name={section.name}
onMouseEnter={() => setInfo(section)}
onMouseLeave={() => setInfo(null)}
>
{section.letters}
{section.letters || section.name}
</Section>
))}
</PaymentRequest>
Expand All @@ -115,7 +129,7 @@ function Demo() {
</Row>
)}
</>
)
);
}

render(<Demo />, document.getElementById('main'))
render(<Demo />, document.getElementById('main'));
2 changes: 1 addition & 1 deletion examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"@esbuild-plugins/node-globals-polyfill": "^0.1.1",
"buffer": "^6.0.3",
"esbuild": "^0.14.36",
"light-bolt11-decoder": "^2.0.0",
"light-bolt12-decoder": "^1.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"styled-components": "^5.3.5",
Expand Down
201 changes: 40 additions & 161 deletions tests/basic.test.js
Original file line number Diff line number Diff line change
@@ -1,165 +1,44 @@
/* eslint-env jest */

const {decode} = require('..')
const { decode } = require('../decoder');

describe('decoding', () => {
it('should decode an invoice', () => {
let inv = decode(
'lnbc20u1p3y0x3hpp5743k2g0fsqqxj7n8qzuhns5gmkk4djeejk3wkp64ppevgekvc0jsdqcve5kzar2v9nr5gpqd4hkuetesp5ez2g297jduwc20t6lmqlsg3man0vf2jfd8ar9fh8fhn2g8yttfkqxqy9gcqcqzys9qrsgqrzjqtx3k77yrrav9hye7zar2rtqlfkytl094dsp0ms5majzth6gt7ca6uhdkxl983uywgqqqqlgqqqvx5qqjqrzjqd98kxkpyw0l9tyy8r8q57k7zpy9zjmh6sez752wj6gcumqnj3yxzhdsmg6qq56utgqqqqqqqqqqqeqqjq7jd56882gtxhrjm03c93aacyfy306m4fq0tskf83c0nmet8zc2lxyyg3saz8x6vwcp26xnrlagf9semau3qm2glysp7sv95693fphvsp54l567'
)
expect(inv).toEqual({
paymentRequest:
'lnbc20u1p3y0x3hpp5743k2g0fsqqxj7n8qzuhns5gmkk4djeejk3wkp64ppevgekvc0jsdqcve5kzar2v9nr5gpqd4hkuetesp5ez2g297jduwc20t6lmqlsg3man0vf2jfd8ar9fh8fhn2g8yttfkqxqy9gcqcqzys9qrsgqrzjqtx3k77yrrav9hye7zar2rtqlfkytl094dsp0ms5majzth6gt7ca6uhdkxl983uywgqqqqlgqqqvx5qqjqrzjqd98kxkpyw0l9tyy8r8q57k7zpy9zjmh6sez752wj6gcumqnj3yxzhdsmg6qq56utgqqqqqqqqqqqeqqjq7jd56882gtxhrjm03c93aacyfy306m4fq0tskf83c0nmet8zc2lxyyg3saz8x6vwcp26xnrlagf9semau3qm2glysp7sv95693fphvsp54l567',
sections: [
{
name: 'lightning_network',
letters: 'ln'
},
{
name: 'coin_network',
letters: 'bc',
value: {
bech32: 'bc',
pubKeyHash: 0,
scriptHash: 5,
validWitnessVersions: [0]
}
},
{
name: 'amount',
letters: '20u',
value: '2000000'
},
{
name: 'separator',
letters: '1'
},
{
name: 'timestamp',
letters: 'p3y0x3h',
value: 1648859703
},
{
name: 'payment_hash',
tag: 'p',
letters: 'pp5743k2g0fsqqxj7n8qzuhns5gmkk4djeejk3wkp64ppevgekvc0js',
value:
'f5636521e98000697a6700b979c288ddad56cb3995a2eb07550872c466ccc3e5'
},
{
name: 'description',
tag: 'd',
letters: 'dqcve5kzar2v9nr5gpqd4hkuete',
value: 'fiatjaf: money'
},
{
name: 'payment_secret',
tag: 's',
letters: 'sp5ez2g297jduwc20t6lmqlsg3man0vf2jfd8ar9fh8fhn2g8yttfkq',
value:
'c8948517d26f1d853d7afec1f8223becdec4aa4969fa32a6e74de6a41c8b5a6c'
},
{
name: 'expiry',
tag: 'x',
letters: 'xqy9gcq',
value: 172800
},
{
name: 'min_final_cltv_expiry',
tag: 'c',
letters: 'cqzys',
value: 144
},
{
name: 'feature_bits',
tag: '9',
letters: '9qrsgq',
value: {
option_data_loss_protect: 'unsupported',
initial_routing_sync: 'unsupported',
option_upfront_shutdown_script: 'unsupported',
gossip_queries: 'unsupported',
var_onion_optin: 'required',
gossip_queries_ex: 'unsupported',
option_static_remotekey: 'unsupported',
payment_secret: 'required',
basic_mpp: 'unsupported',
option_support_large_channel: 'unsupported',
extra_bits: {
start_bit: 20,
bits: [],
has_required: false
}
}
},
{
name: 'route_hint',
tag: 'r',
letters:
'rzjqtx3k77yrrav9hye7zar2rtqlfkytl094dsp0ms5majzth6gt7ca6uhdkxl983uywgqqqqlgqqqvx5qqjq',
value: [
{
pubkey:
'02cd1b7bc418fac2dc99f0ba350d60fa6c45fde5ab6017ee14df6425df485fb1dd',
short_channel_id: '72edb1be53c78472',
fee_base_msat: 1000,
fee_proportional_millionths: 50000,
cltv_expiry_delta: 144
}
]
},
{
name: 'route_hint',
tag: 'r',
letters:
'rzjqd98kxkpyw0l9tyy8r8q57k7zpy9zjmh6sez752wj6gcumqnj3yxzhdsmg6qq56utgqqqqqqqqqqqeqqjq',
value: [
{
pubkey:
'034a7b1ac1239ff2ac8438ce0a7ade1048514b77d4322f514e96918e6c13944861',
short_channel_id: '5db0da3400535c5a',
fee_base_msat: 0,
fee_proportional_millionths: 100,
cltv_expiry_delta: 144
}
]
},
{
name: 'signature',
letters:
'7jd56882gtxhrjm03c93aacyfy306m4fq0tskf83c0nmet8zc2lxyyg3saz8x6vwcp26xnrlagf9semau3qm2glysp7sv95693fphvsp',
value:
'f49b4d1cea42cd71cb6f8e0b1ef7044922fd6ea903d70b24f1c3e7bcace2c2be621111874473698ec055a34c7fea1258677de441b523e4807d06169a2c521bb201'
},
{
name: 'checksum',
letters: '54l567'
}
],
describe('decoding invoices', () => {
it('should decode a BOLT11 invoice', () => {
const invoice = 'lnbc1...'; // Replace with a valid BOLT11 invoice string.
const result = decode(invoice);

expect(result).toEqual({
paymentRequest: 'lnbc1...', // Match your BOLT11 expected output.
sections: expect.any(Array),
expiry: 172800,
route_hints: [
[
{
pubkey:
'02cd1b7bc418fac2dc99f0ba350d60fa6c45fde5ab6017ee14df6425df485fb1dd',
short_channel_id: '72edb1be53c78472',
fee_base_msat: 1000,
fee_proportional_millionths: 50000,
cltv_expiry_delta: 144
}
],
[
{
pubkey:
'034a7b1ac1239ff2ac8438ce0a7ade1048514b77d4322f514e96918e6c13944861',
short_channel_id: '5db0da3400535c5a',
fee_base_msat: 0,
fee_proportional_millionths: 100,
cltv_expiry_delta: 144
}
]
]
})
})
})
route_hints: expect.any(Array),
});
});

it('should decode a BOLT12 invoice', () => {
const invoice = 'lno1...'; // Replace with a valid BOLT12 invoice string.
const result = decode(invoice);

expect(result).toEqual({
offer: "Example Offer",
amount: 1000,
recurrence: {
time_unit: "day",
start: 1680000000,
limit: 10,
},
features: {
option_payment_metadata: "supported",
var_onion_optin: "required",
},
signature: "f49b4...",
description: "Payment for services",
payment_hash: "abc123...",
});
});

it('should throw an error for an unknown invoice type', () => {
const invoice = 'unknown1...';
expect(() => decode(invoice)).toThrow('Unknown invoice type');
});
});

0 comments on commit 2c11bd7

Please sign in to comment.