From e604a7ee70b7488457fbd8da3f024b0a951918bb Mon Sep 17 00:00:00 2001 From: im-adithya Date: Wed, 13 Dec 2023 19:27:29 +0530 Subject: [PATCH 01/11] feat: add NWC listTransactions method --- examples/nwc/list-transactions.js | 30 ++++++++++++++++++ src/webln/NostrWeblnProvider.ts | 51 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 examples/nwc/list-transactions.js diff --git a/examples/nwc/list-transactions.js b/examples/nwc/list-transactions.js new file mode 100644 index 0000000..791c6eb --- /dev/null +++ b/examples/nwc/list-transactions.js @@ -0,0 +1,30 @@ +import * as crypto from "node:crypto"; // required in node.js +global.crypto = crypto; // required in node.js +import "websocket-polyfill"; // required in node.js + +import * as readline from "node:readline/promises"; +import { stdin as input, stdout as output } from "node:process"; + +import { webln as providers } from "../../dist/index.module.js"; + +const rl = readline.createInterface({ input, output }); + +const nwcUrl = + process.env.NWC_URL || + (await rl.question("Nostr Wallet Connect URL (nostr+walletconnect://...): ")); +rl.close(); + +const webln = new providers.NostrWebLNProvider({ + nostrWalletConnectUrl: nwcUrl, +}); +await webln.enable(); + +const response = await webln.lookupInvoice({ + from: 1234567890, + until: 1236000000, + type: "incoming", +}); + +console.info(response); + +webln.close(); diff --git a/src/webln/NostrWeblnProvider.ts b/src/webln/NostrWeblnProvider.ts index b82f022..fb5d75f 100644 --- a/src/webln/NostrWeblnProvider.ts +++ b/src/webln/NostrWeblnProvider.ts @@ -36,6 +36,34 @@ const NWCs: Record = { }, }; +interface ListTransactionsArgs { + from?: number; + until?: number; + limit?: number; + offset?: number; + unpaid?: boolean; + type?: string; +} + +interface ListedInvoice { + type: string; + invoice: string; + description: string; + description_hash: string; + preimage: string; + payment_hash: string; + amount: number; + fees_paid: number; + settled_at: number; + created_at: number; + expires_at: number; + metadata?: Record; +} + +interface ListTransactionsResponse { + transactions: ListedInvoice[]; +} + interface NostrWebLNOptions { authorizationUrl?: string; // the URL to the NWC interface for the user to confirm the session relayUrl: string; @@ -58,12 +86,17 @@ type Nip47GetInfoResponse = { methods: string[]; }; +type Nip47ListTransactionsResponse = { + transactions: ListedInvoice[]; +}; + const nip47ToWeblnRequestMap = { get_info: "getInfo", get_balance: "getBalance", make_invoice: "makeInvoice", pay_invoice: "sendPayment", lookup_invoice: "lookupInvoice", + list_transactions: "listTransactions", }; export class NostrWebLNProvider implements WebLNProvider, Nip07Provider { @@ -340,6 +373,24 @@ export class NostrWebLNProvider implements WebLNProvider, Nip07Provider { ); } + listTransactions(args: ListTransactionsArgs) { + this.checkConnected(); + + // maybe we can tailor the response to our needs + return this.executeNip47Request< + ListTransactionsResponse, + Nip47ListTransactionsResponse + >( + "list_transactions", + args, + (results) => + results.transactions.every( + (result) => !!result.invoice && !!result.preimage, + ), + (results) => results, + ); + } + request(method: WebLNRequestMethod, args?: unknown): Promise { throw new Error("Method not implemented."); } From 9f190576ba1ffe4515084c3bbbdffa7d19fd6190 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Thu, 14 Dec 2023 16:06:06 +0700 Subject: [PATCH 02/11] fix: trailing comma config --- .vscode/settings.json | 3 ++- prettierrc.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 1b6457c..adbacfc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "editor.formatOnSave": true, - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", + "prettier.trailingComma": "all" } diff --git a/prettierrc.json b/prettierrc.json index 757fd64..bf357fb 100644 --- a/prettierrc.json +++ b/prettierrc.json @@ -1,3 +1,3 @@ { - "trailingComma": "es5" + "trailingComma": "all" } From 60dc117f41742b34f6243d948bfa6d33030700b8 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Thu, 14 Dec 2023 16:06:48 +0700 Subject: [PATCH 03/11] chore: rename Transaction and add TODOs --- src/webln/NostrWeblnProvider.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/webln/NostrWeblnProvider.ts b/src/webln/NostrWeblnProvider.ts index cf51193..9411156 100644 --- a/src/webln/NostrWeblnProvider.ts +++ b/src/webln/NostrWeblnProvider.ts @@ -36,6 +36,7 @@ const NWCs: Record = { }, }; +// TODO: move to webln-types package interface ListTransactionsArgs { from?: number; until?: number; @@ -45,7 +46,8 @@ interface ListTransactionsArgs { type?: string; } -interface ListedInvoice { +// TODO: move to webln-types package +interface Transaction { type: string; invoice: string; description: string; @@ -60,8 +62,9 @@ interface ListedInvoice { metadata?: Record; } +// TODO: move to webln-types package interface ListTransactionsResponse { - transactions: ListedInvoice[]; + transactions: Transaction[]; } interface NostrWebLNOptions { @@ -87,7 +90,7 @@ type Nip47GetInfoResponse = { }; type Nip47ListTransactionsResponse = { - transactions: ListedInvoice[]; + transactions: Transaction[]; }; type Nip47PayResponse = { From 1253d7e22fe8a90354905df622e82bce8256d314 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Thu, 14 Dec 2023 16:13:33 +0700 Subject: [PATCH 04/11] chore: minor fixes --- src/webln/NostrWeblnProvider.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/webln/NostrWeblnProvider.ts b/src/webln/NostrWeblnProvider.ts index 9411156..05659c4 100644 --- a/src/webln/NostrWeblnProvider.ts +++ b/src/webln/NostrWeblnProvider.ts @@ -89,9 +89,7 @@ type Nip47GetInfoResponse = { methods: string[]; }; -type Nip47ListTransactionsResponse = { - transactions: Transaction[]; -}; +type Nip47ListTransactionsResponse = ListTransactionsResponse; type Nip47PayResponse = { preimage: string; @@ -410,11 +408,9 @@ export class NostrWebLNProvider implements WebLNProvider, Nip07Provider { >( "list_transactions", args, - (results) => - results.transactions.every( - (result) => !!result.invoice && !!result.preimage, - ), - (results) => results, + (response) => !!response.transactions, + // TODO: consider mapping NWC response + (response) => response, ); } From d79437a0afda897a16cdc3301ebfcacb97dda779 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Fri, 15 Dec 2023 14:39:04 +0700 Subject: [PATCH 05/11] fix: list-transactions example --- examples/nwc/list-transactions.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/examples/nwc/list-transactions.js b/examples/nwc/list-transactions.js index 791c6eb..adf9fd8 100644 --- a/examples/nwc/list-transactions.js +++ b/examples/nwc/list-transactions.js @@ -19,12 +19,19 @@ const webln = new providers.NostrWebLNProvider({ }); await webln.enable(); -const response = await webln.lookupInvoice({ - from: 1234567890, - until: 1236000000, - type: "incoming", +const ONE_WEEK_IN_SECONDS = 60 * 60 * 24 * 7; +const response = await webln.listTransactions({ + from: Math.floor(new Date().getTime() / 1000 - ONE_WEEK_IN_SECONDS), + until: Math.ceil(new Date().getTime() / 1000), + limit: 30, + // type: "incoming", }); -console.info(response); +console.info( + response.transactions.length + "transactions, ", + response.transactions.filter((t) => t.type === "incoming").length + + " incoming", + response, +); webln.close(); From d5d05e35ac927ac3b0d63499597adf9506ba138a Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Fri, 15 Dec 2023 14:39:20 +0700 Subject: [PATCH 06/11] chore: improve ListTransactionsArgs type typing --- src/webln/NostrWeblnProvider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webln/NostrWeblnProvider.ts b/src/webln/NostrWeblnProvider.ts index 05659c4..e52dc5d 100644 --- a/src/webln/NostrWeblnProvider.ts +++ b/src/webln/NostrWeblnProvider.ts @@ -43,7 +43,7 @@ interface ListTransactionsArgs { limit?: number; offset?: number; unpaid?: boolean; - type?: string; + type?: "incoming" | "outgoing"; } // TODO: move to webln-types package From e638a1cc1ebd279f35b0ed4d97e361a1f0a9aacf Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Fri, 15 Dec 2023 15:50:02 +0700 Subject: [PATCH 07/11] fix: convert transaction amount from millisats to sats --- examples/nwc/make-invoice.js | 6 +++--- src/webln/NostrWeblnProvider.ts | 9 +++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/nwc/make-invoice.js b/examples/nwc/make-invoice.js index a8a931a..e147cac 100644 --- a/examples/nwc/make-invoice.js +++ b/examples/nwc/make-invoice.js @@ -9,9 +9,9 @@ import { webln as providers } from "../../dist/index.module.js"; const rl = readline.createInterface({ input, output }); -const nwcUrl = await rl.question( - "Nostr Wallet Connect URL (nostr+walletconnect://...): ", -); +const nwcUrl = + process.env.NWC_URL || + (await rl.question("Nostr Wallet Connect URL (nostr+walletconnect://...): ")); rl.close(); const webln = new providers.NostrWebLNProvider({ diff --git a/src/webln/NostrWeblnProvider.ts b/src/webln/NostrWeblnProvider.ts index e52dc5d..7bad92c 100644 --- a/src/webln/NostrWeblnProvider.ts +++ b/src/webln/NostrWeblnProvider.ts @@ -409,8 +409,13 @@ export class NostrWebLNProvider implements WebLNProvider, Nip07Provider { "list_transactions", args, (response) => !!response.transactions, - // TODO: consider mapping NWC response - (response) => response, + (response) => ({ + transactions: response.transactions.map((transaction) => ({ + ...transaction, + // NWC uses msats - convert to sats for webln + amount: Math.floor(transaction.amount / 1000), + })), + }), ); } From 877495729671d573cf5fcfb30b7fcf14e643a092 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Fri, 15 Dec 2023 16:27:44 +0700 Subject: [PATCH 08/11] fix: convert fees_paid to sats --- src/webln/NostrWeblnProvider.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/webln/NostrWeblnProvider.ts b/src/webln/NostrWeblnProvider.ts index 7bad92c..b54b479 100644 --- a/src/webln/NostrWeblnProvider.ts +++ b/src/webln/NostrWeblnProvider.ts @@ -414,6 +414,7 @@ export class NostrWebLNProvider implements WebLNProvider, Nip07Provider { ...transaction, // NWC uses msats - convert to sats for webln amount: Math.floor(transaction.amount / 1000), + fees_paid: Math.floor(transaction.fees_paid / 1000), })), }), ); From 324f7a2ea5c602ef8032b13e324932762d590cc5 Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Fri, 15 Dec 2023 16:47:59 +0700 Subject: [PATCH 09/11] chore: temporarily export list_transaction types --- src/webln/NostrWeblnProvider.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/webln/NostrWeblnProvider.ts b/src/webln/NostrWeblnProvider.ts index b54b479..6fa2fda 100644 --- a/src/webln/NostrWeblnProvider.ts +++ b/src/webln/NostrWeblnProvider.ts @@ -37,7 +37,7 @@ const NWCs: Record = { }; // TODO: move to webln-types package -interface ListTransactionsArgs { +export interface ListTransactionsArgs { from?: number; until?: number; limit?: number; @@ -47,7 +47,7 @@ interface ListTransactionsArgs { } // TODO: move to webln-types package -interface Transaction { +export interface Transaction { type: string; invoice: string; description: string; @@ -63,7 +63,7 @@ interface Transaction { } // TODO: move to webln-types package -interface ListTransactionsResponse { +export interface ListTransactionsResponse { transactions: Transaction[]; } From 16e9541cf59fe198eda59d3e5c4f23aff690a27c Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Mon, 18 Dec 2023 20:01:37 +0700 Subject: [PATCH 10/11] chore: update lookup_invoice and make_invoice to handle updated NIP46 response --- examples/nwc/lookup-invoice.js | 17 +++++++++----- src/webln/NostrWeblnProvider.ts | 41 +++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/examples/nwc/lookup-invoice.js b/examples/nwc/lookup-invoice.js index 0d6e382..4ca5f3f 100644 --- a/examples/nwc/lookup-invoice.js +++ b/examples/nwc/lookup-invoice.js @@ -9,9 +9,11 @@ import { webln as providers } from "../../dist/index.module.js"; const rl = readline.createInterface({ input, output }); -const nwcUrl = await rl.question( - "Nostr Wallet Connect URL (nostr+walletconnect://...): ", -); +const nwcUrl = + process.env.NWC_URL || + (await rl.question("Nostr Wallet Connect URL (nostr+walletconnect://...): ")); + +const invoiceOrPaymentHash = await rl.question("Invoice or payment hash: "); rl.close(); const webln = new providers.NostrWebLNProvider({ @@ -20,9 +22,12 @@ const webln = new providers.NostrWebLNProvider({ await webln.enable(); const response = await webln.lookupInvoice({ // provide one of the below - //invoice: 'lnbc10n1pjwxschpp5hg0pw234n9ww9q4uy25pnvu8y4jzpznysasyf7m9fka36t7fahysdqufet5xgzhv43ycn3qv4uxzmtsd3jscqzzsxqyz5vqsp5uw023qhxuxqfj69rvj9yns5gufczad5gqw4uer5cgqhw90slkavs9qyyssqvv2tw6c30ssgtpejc3zk7ns0svuj8547d8wxj0e36hltljx5a8x4qj59mk2y7qlt6qazf2j38fzc8uag3887nslxz6fe3vnyvg0f2xqqnlvcu2', - payment_hash: - "ba1e172a35995ce282bc22a819b3872564208a64876044fb654dbb1d2fc9edc9", + invoice: invoiceOrPaymentHash.startsWith("ln") + ? invoiceOrPaymentHash + : undefined, + payment_hash: !invoiceOrPaymentHash.startsWith("ln") + ? invoiceOrPaymentHash + : undefined, }); console.info(response); diff --git a/src/webln/NostrWeblnProvider.ts b/src/webln/NostrWeblnProvider.ts index 6fa2fda..088e3f9 100644 --- a/src/webln/NostrWeblnProvider.ts +++ b/src/webln/NostrWeblnProvider.ts @@ -89,7 +89,10 @@ type Nip47GetInfoResponse = { methods: string[]; }; -type Nip47ListTransactionsResponse = ListTransactionsResponse; +type Nip47ListTransactionsResponse = { + transactions: Nip47Transaction[]; +}; +type Nip47Transaction = Transaction; type Nip47PayResponse = { preimage: string; @@ -370,7 +373,7 @@ export class NostrWebLNProvider implements WebLNProvider, Nip07Provider { throw new Error("No amount specified"); } - return this.executeNip47Request( + return this.executeNip47Request( "make_invoice", { amount: amount * 1000, // NIP-47 uses msat @@ -387,14 +390,14 @@ export class NostrWebLNProvider implements WebLNProvider, Nip07Provider { lookupInvoice(args: LookupInvoiceArgs) { this.checkConnected(); - return this.executeNip47Request< - LookupInvoiceResponse, - { invoice: string; paid: boolean } - >( + return this.executeNip47Request( "lookup_invoice", args, - (result) => result.invoice !== undefined && result.paid !== undefined, - (result) => ({ paymentRequest: result.invoice, paid: result.paid }), + (result) => !!result.invoice, + (result) => ({ + paymentRequest: result.invoice, + paid: !!result.settled_at, + }), ); } @@ -410,12 +413,9 @@ export class NostrWebLNProvider implements WebLNProvider, Nip07Provider { args, (response) => !!response.transactions, (response) => ({ - transactions: response.transactions.map((transaction) => ({ - ...transaction, - // NWC uses msats - convert to sats for webln - amount: Math.floor(transaction.amount / 1000), - fees_paid: Math.floor(transaction.fees_paid / 1000), - })), + transactions: response.transactions.map( + mapNip47TransactionToTransaction, + ), }), ); } @@ -588,7 +588,7 @@ export class NostrWebLNProvider implements WebLNProvider, Nip07Provider { } // @ts-ignore // event is still unknown in nostr-tools if (event.kind == 23195 && response.result) { - //console.log("NIP-47 result", response.result); + // console.info("NIP-47 result", response.result); if (resultValidator(response.result)) { resolve(resultMapper(response.result)); this.notify(weblnMethod, response.result); @@ -628,4 +628,15 @@ export class NostrWebLNProvider implements WebLNProvider, Nip07Provider { } } +function mapNip47TransactionToTransaction( + transaction: Nip47Transaction, +): Transaction { + return { + ...transaction, + // NWC uses msats - convert to sats for webln + amount: Math.floor(transaction.amount / 1000), + fees_paid: Math.floor(transaction.fees_paid / 1000), + }; +} + export const NWC = NostrWebLNProvider; From 5c9cf871f954744fee0e3d75cdad72e877d1c6fc Mon Sep 17 00:00:00 2001 From: Roland Bewick Date: Mon, 18 Dec 2023 20:29:08 +0700 Subject: [PATCH 11/11] chore: defensively check fees_paid --- src/webln/NostrWeblnProvider.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/webln/NostrWeblnProvider.ts b/src/webln/NostrWeblnProvider.ts index 088e3f9..93bbd41 100644 --- a/src/webln/NostrWeblnProvider.ts +++ b/src/webln/NostrWeblnProvider.ts @@ -635,7 +635,9 @@ function mapNip47TransactionToTransaction( ...transaction, // NWC uses msats - convert to sats for webln amount: Math.floor(transaction.amount / 1000), - fees_paid: Math.floor(transaction.fees_paid / 1000), + fees_paid: transaction.fees_paid + ? Math.floor(transaction.fees_paid / 1000) + : 0, }; }