Skip to content

Commit

Permalink
Merge pull request #164 from getAlby/task-nwc-transactions
Browse files Browse the repository at this point in the history
feat: add NWC listTransactions method
  • Loading branch information
rolznz authored Dec 18, 2023
2 parents 50c16ae + 5852711 commit 286f513
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 18 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
"editor.defaultFormatter": "esbenp.prettier-vscode",
"prettier.trailingComma": "all"
}
37 changes: 37 additions & 0 deletions examples/nwc/list-transactions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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 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.transactions.length + "transactions, ",
response.transactions.filter((t) => t.type === "incoming").length +
" incoming",
response,
);

webln.close();
17 changes: 11 additions & 6 deletions examples/nwc/lookup-invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions examples/nwc/make-invoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
2 changes: 1 addition & 1 deletion prettierrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"trailingComma": "es5"
"trailingComma": "all"
}
83 changes: 76 additions & 7 deletions src/webln/NostrWeblnProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,37 @@ const NWCs: Record<string, NostrWebLNOptions> = {
},
};

// TODO: move to webln-types package
export interface ListTransactionsArgs {
from?: number;
until?: number;
limit?: number;
offset?: number;
unpaid?: boolean;
type?: "incoming" | "outgoing";
}

// TODO: move to webln-types package
export interface Transaction {
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<string, unknown>;
}

// TODO: move to webln-types package
export interface ListTransactionsResponse {
transactions: Transaction[];
}

interface NostrWebLNOptions {
authorizationUrl?: string; // the URL to the NWC interface for the user to confirm the session
relayUrl: string;
Expand All @@ -58,6 +89,11 @@ type Nip47GetInfoResponse = {
methods: string[];
};

type Nip47ListTransactionsResponse = {
transactions: Nip47Transaction[];
};
type Nip47Transaction = Transaction;

type Nip47PayResponse = {
preimage: string;
};
Expand All @@ -69,6 +105,7 @@ const nip47ToWeblnRequestMap = {
pay_invoice: "sendPayment",
pay_keysend: "payKeysend",
lookup_invoice: "lookupInvoice",
list_transactions: "listTransactions",
};

export class NostrWebLNProvider implements WebLNProvider, Nip07Provider {
Expand Down Expand Up @@ -336,7 +373,7 @@ export class NostrWebLNProvider implements WebLNProvider, Nip07Provider {
throw new Error("No amount specified");
}

return this.executeNip47Request<MakeInvoiceResponse, { invoice: string }>(
return this.executeNip47Request<MakeInvoiceResponse, Nip47Transaction>(
"make_invoice",
{
amount: amount * 1000, // NIP-47 uses msat
Expand All @@ -353,14 +390,33 @@ export class NostrWebLNProvider implements WebLNProvider, Nip07Provider {
lookupInvoice(args: LookupInvoiceArgs) {
this.checkConnected();

return this.executeNip47Request<LookupInvoiceResponse, Nip47Transaction>(
"lookup_invoice",
args,
(result) => !!result.invoice,
(result) => ({
paymentRequest: result.invoice,
paid: !!result.settled_at,
}),
);
}

listTransactions(args: ListTransactionsArgs) {
this.checkConnected();

// maybe we can tailor the response to our needs
return this.executeNip47Request<
LookupInvoiceResponse,
{ invoice: string; paid: boolean }
ListTransactionsResponse,
Nip47ListTransactionsResponse
>(
"lookup_invoice",
"list_transactions",
args,
(result) => result.invoice !== undefined && result.paid !== undefined,
(result) => ({ paymentRequest: result.invoice, paid: result.paid }),
(response) => !!response.transactions,
(response) => ({
transactions: response.transactions.map(
mapNip47TransactionToTransaction,
),
}),
);
}

Expand Down Expand Up @@ -532,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);
Expand Down Expand Up @@ -572,4 +628,17 @@ 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: transaction.fees_paid
? Math.floor(transaction.fees_paid / 1000)
: 0,
};
}

export const NWC = NostrWebLNProvider;

0 comments on commit 286f513

Please sign in to comment.