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

feat: add decode invoice function #131

Closed
wants to merge 4 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
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@
},
"dependencies": {
"crypto-js": "^4.1.1",
"nostr-tools": "1.13.1",
"events": "^3.3.0"
"events": "^3.3.0",
"light-bolt11-decoder": "^3.0.0",
"nostr-tools": "1.13.1"
},
"devDependencies": {
"@commitlint/cli": "^17.7.1",
Expand Down
32 changes: 32 additions & 0 deletions src/decodeInvoice.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { decodeInvoice } from "./decodeInvoice";

const invoice =
"lnbc10n1pj4xmazpp5ns890al37jpreen4rlpl6fsw2hlp9n9hm0ts4dvwvcxq8atf4v6qhp50kncf9zk35xg4lxewt4974ry6mudygsztsz8qn3ar8pn3mtpe50scqzzsxqyz5vqsp5k508kdmvfpuac6lvn9wumr9x4mcpnh2t6jyp5kkxcjhueq4xjxqq9qyyssq0m88mwgknhkqfsa9u8e9dp8v93xlm0lqggslzj8mpsnx3mdzm8z5k9ns7g299pfm9zwm4crs00a364cmpraxr54jw5cf2qx9vycucggqz2ggul";

describe("decodeInvoice", () => {
test("get amount from invoice", () => {
const decodedInvoice = decodeInvoice(invoice);
const amountSection = decodedInvoice.sections.find(
(section) => section.name === "amount",
);
if (amountSection?.name !== "amount") {
throw new Error("did not find amount section");
}
const value = amountSection.value;
expect(value).toEqual("1000");
});

test("get payment hash from invoice", () => {
const decodedInvoice = decodeInvoice(invoice);
const paymentHashSection = decodedInvoice.sections.find(
(section) => section.name === "payment_hash",
);
if (paymentHashSection?.name !== "payment_hash") {
throw new Error("did not find payment_hash section");
}
const value = paymentHashSection.value;
expect(value).toEqual(
"9c0e57f7f1f4823ce6751fc3fd260e55fe12ccb7dbd70ab58e660c03f569ab34",
);
});
});
13 changes: 13 additions & 0 deletions src/decodeInvoice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { decode } from "light-bolt11-decoder";
export function decodeInvoice(invoice: string) {
if (!invoice) {
throw new Error("No invoice provided");
}

try {
return decode(invoice);
} catch (error) {
console.error("Failed to decode invoice", error);
throw error;
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * as auth from "./auth";
export * as types from "./types";
export * as webln from "./webln";
export { Client } from "./client";
export * from "./decodeInvoice";
Copy link
Contributor

Choose a reason for hiding this comment

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

hmmm, I don't think this is a nice API.
Just exposing the global function because that people don't have to import it from the light-bolt11-decoder.

doesn't this make more sense to have in the Invoice https://github.com/getAlby/js-lightning-tools/blob/master/src/invoice.ts

So I can initialize an invoice and then have all the data available there?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bumi sounds good to me. Would it make sense for this sdk to depend on lightning-tools? or should people install both packages as they are doing now? I think it would be nice to have some support for decoding invoices in this library?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Update: we could add a small link to the README

Decoding Invoices

See lightning-tools

90 changes: 90 additions & 0 deletions src/light-bolt11-decoder.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// TODO: remove when https://github.com/nbd-wtf/light-bolt11-decoder/pull/4 is merged
declare module "light-bolt11-decoder" {
type NetworkSection = {
name: "coin_network";
letters: string;
value?: {
bech32: string;
pubKeyHash: number;
scriptHash: number;
validWitnessVersions: number[];
};
};

type FeatureBits = {
option_data_loss_protect: string;
initial_routing_sync: string;
option_upfront_shutdown_script: string;
gossip_queries: string;
var_onion_optin: string;
gossip_queries_ex: string;
option_static_remotekey: string;
payment_secret: string;
basic_mpp: string;
option_support_large_channel: string;
extra_bits: {
start_bit: number;
bits: unknown[];
has_required: boolean;
};
};

type RouteHint = {
pubkey: string;
short_channel_id: string;
fee_base_msat: number;
fee_proportional_millionths: number;
cltv_expiry_delta: number;
};

type RouteHintSection = {
name: "route_hint";
tag: "r";
letters: string;
value: RouteHint[];
};

type FeatureBitsSection = {
name: "feature_bits";
tag: "9";
letters: string;
value: FeatureBits;
};

type Section =
| { name: "paymentRequest"; value: string }
| { name: "expiry"; value: number }
| { name: "checksum"; letters: string }
| NetworkSection
| { name: "amount"; letters: string; value: string }
| { name: "separator"; letters: string }
| { name: "timestamp"; letters: string; value: number }
| { name: "payment_hash"; tag: "p"; letters: string; value: string }
| { name: "description"; tag: "d"; letters: string; value: string }
| { name: "payment_secret"; tag: "s"; letters: string; value: string }
| {
name: "min_final_cltv_expiry";
tag: "c";
letters: string;
value: number;
}
| FeatureBitsSection
| RouteHintSection
| { name: "signature"; letters: string; value: string };

type PaymentJSON = {
paymentRequest: string;
sections: Section[];
expiry: number;
route_hints: RouteHint[][];
};

type DecodedInvoice = {
paymentRequest: string;
sections: Section[];
expiry: number;
route_hints: RouteHint[][];
};

function decode(invoice: string): DecodedInvoice;
}
7 changes: 7 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5412,6 +5412,13 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"

light-bolt11-decoder@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/light-bolt11-decoder/-/light-bolt11-decoder-3.0.0.tgz#f644576120426c9ef65621bde254f11016055044"
integrity sha512-AKvOigD2pmC8ktnn2TIqdJu0K0qk6ukUmTvHwF3JNkm8uWCqt18Ijn33A/a7gaRZ4PghJ59X+8+MXrzLKdBTmQ==
dependencies:
"@scure/base" "1.1.1"

[email protected], lilconfig@^2.0.3, lilconfig@^2.0.5:
version "2.1.0"
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
Expand Down