nip47
Version:
A flexible library for sending and receiving payments via NWC.
120 lines (117 loc) • 3.38 kB
JavaScript
// src/nwc/PaymentRequest.ts
import { NDKEvent } from "@nostr-dev-kit/ndk";
// src/nwc/Nwc.ts
import { nip04, nip19, finishEvent } from "nostr-tools";
var Kinds = {
NwcInfo: 13194,
NwcRequest: 23194,
NwcResponse: 23195
};
var NWC = class _NWC {
// relay: Relay;
relayUrl;
secret;
walletPubkey;
options;
subscribers;
// from nostr-tools/nip47
static parseWalletConnectUrl(walletConnectUrl) {
walletConnectUrl = walletConnectUrl.replace("nostrwalletconnect://", "http://").replace("nostr+walletconnect://", "http://");
const url = new URL(walletConnectUrl);
const options = {};
options.walletPubkey = url.host;
const secret = url.searchParams.get("secret");
const relayUrl = url.searchParams.get("relay");
if (secret) {
options.secret = secret;
}
if (relayUrl) {
options.relayUrl = relayUrl;
}
return options;
}
constructor(nostrWalletConnectUrl) {
this.options = _NWC.parseWalletConnectUrl(nostrWalletConnectUrl);
if (!this.options.relayUrl || !this.options.secret || !this.options.walletPubkey) {
throw new Error(
"invalid connection string. Requires relay, secret, and walletPubkey"
);
}
this.relayUrl = this.options.relayUrl;
this.secret = this.options.secret.toLowerCase().startsWith("nsec") ? nip19.decode(this.options.secret).data : this.options.secret;
this.walletPubkey = this.options.walletPubkey.toLowerCase().startsWith("npub") ? nip19.decode(this.options.walletPubkey).data : this.options.walletPubkey;
this.subscribers = {};
if (globalThis.WebSocket === void 0) {
console.error(
"WebSocket is undefined. Make sure to `import websocket-polyfill` for nodejs environments"
);
}
}
async makeNWCRequestEvent(invoice) {
if (!invoice)
throw new Error("invoice is required");
const content = {
method: "pay_invoice",
params: {
invoice
}
};
const encryptedContent = await nip04.encrypt(
this.secret,
this.walletPubkey,
JSON.stringify(content)
);
const eventTemplate = {
kind: Kinds.NwcRequest,
created_at: Math.round(Date.now() / 1e3),
content: encryptedContent,
tags: [["p", this.walletPubkey]]
};
return finishEvent(eventTemplate, this.secret);
}
async decryptContent(encryptedContent) {
const content = await nip04.decrypt(this.secret, this.walletPubkey, encryptedContent);
return JSON.parse(content);
}
};
// src/nwc/PaymentRequest.ts
var PaymentRequestEvent = class _PaymentRequestEvent extends NDKEvent {
invoice;
nwc;
event;
constructor(nwc, invoice, event) {
super(void 0, event);
this.nwc = nwc;
this.invoice = invoice;
this.event = new NDKEvent(void 0, event);
}
static async create(nwcOrUrl, invoice) {
let nwc;
if (typeof nwcOrUrl === "string") {
nwc = new NWC(nwcOrUrl);
} else {
nwc = nwcOrUrl;
}
const event = await nwc.makeNWCRequestEvent(invoice);
return new _PaymentRequestEvent(nwc, invoice, event);
}
get responseFilter() {
return {
kinds: [23195],
tags: [
["e", this.id],
["p", this.pubkey]
]
};
}
getResponseFilter() {
return this.responseFilter;
}
get relayToListenTo() {
return this.nwc.relayUrl;
}
};
export {
NWC,
PaymentRequestEvent
};