From 706df575b3e108c21a243f3b708db379bf965cfb Mon Sep 17 00:00:00 2001 From: im-adithya Date: Fri, 5 Jan 2024 19:10:45 +0530 Subject: [PATCH 1/6] chore(makeInvoice): use paymentHash from result --- .../background-script/connectors/nwc.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/extension/background-script/connectors/nwc.ts b/src/extension/background-script/connectors/nwc.ts index 5f065f77d1..08f4c1d985 100644 --- a/src/extension/background-script/connectors/nwc.ts +++ b/src/extension/background-script/connectors/nwc.ts @@ -76,6 +76,7 @@ class NWCConnector implements Connector { unpaid: false, limit: 50, // restricted by relay max event payload size }); + console.info(listTransactionsResponse); const transactions: ConnectorTransaction[] = listTransactionsResponse.transactions.map( @@ -98,22 +99,25 @@ class NWCConnector implements Connector { } async makeInvoice(args: MakeInvoiceArgs): Promise { - const invoice = await this.nwc.makeInvoice({ + const result = await this.nwc.makeInvoice({ amount: args.amount, defaultMemo: args.memo, }); + let paymentHash = result.paymentHash; - const decodedInvoice = lightningPayReq.decode(invoice.paymentRequest); - const paymentHash = decodedInvoice.tags.find( - (tag) => tag.tagName === "payment_hash" - )?.data as string | undefined; if (!paymentHash) { - throw new Error("Could not find payment hash in invoice"); + const decodedInvoice = lightningPayReq.decode(result.paymentRequest); + paymentHash = decodedInvoice.tags.find( + (tag) => tag.tagName === "payment_hash" + )?.data as string | undefined; + if (!paymentHash) { + throw new Error("Could not find payment hash in invoice"); + } } return { data: { - paymentRequest: invoice.paymentRequest, + paymentRequest: result.paymentRequest, rHash: paymentHash, }, }; From 6f9b5def1dbd1cf18f055107bb2a78b1dbb5a300 Mon Sep 17 00:00:00 2001 From: im-adithya Date: Tue, 2 Jul 2024 15:38:33 +0530 Subject: [PATCH 2/6] feat: use new nwc client from sdk --- .../background-script/connectors/nwc.ts | 87 +++++++++++-------- 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/src/extension/background-script/connectors/nwc.ts b/src/extension/background-script/connectors/nwc.ts index 65f720cddf..9e7eb7800c 100644 --- a/src/extension/background-script/connectors/nwc.ts +++ b/src/extension/background-script/connectors/nwc.ts @@ -1,5 +1,4 @@ -import { webln } from "@getalby/sdk"; -import { NostrWebLNProvider } from "@getalby/sdk/dist/webln"; +import { nwc } from "@getalby/sdk"; import lightningPayReq from "bolt11-signet"; import Hex from "crypto-js/enc-hex"; import SHA256 from "crypto-js/sha256"; @@ -26,9 +25,14 @@ interface Config { nostrWalletConnectUrl: string; } +interface TlvRecord { + type: number; + value: string; +} + class NWCConnector implements Connector { config: Config; - nwc: NostrWebLNProvider; + nwc: nwc.NWCClient; get supportedMethods() { return [ @@ -45,13 +49,13 @@ class NWCConnector implements Connector { constructor(account: Account, config: Config) { this.config = config; - this.nwc = new webln.NostrWebLNProvider({ + this.nwc = new nwc.NWCClient({ nostrWalletConnectUrl: this.config.nostrWalletConnectUrl, }); } async init() { - return this.nwc.enable(); + return Promise.resolve(); } async unload() { @@ -61,14 +65,14 @@ class NWCConnector implements Connector { async getInfo(): Promise { const info = await this.nwc.getInfo(); return { - data: info.node, + data: info, }; } async getBalance(): Promise { const balance = await this.nwc.getBalance(); return { - data: { balance: balance.balance, currency: "BTC" }, + data: { balance: balance.balance / 1000, currency: "BTC" }, }; } @@ -77,7 +81,6 @@ class NWCConnector implements Connector { unpaid: false, limit: 50, // restricted by relay max event payload size }); - console.info(listTransactionsResponse); const transactions: ConnectorTransaction[] = listTransactionsResponse.transactions.map( @@ -88,7 +91,7 @@ class NWCConnector implements Connector { payment_hash: transaction.payment_hash, settled: true, settleDate: transaction.settled_at * 1000, - totalAmount: transaction.amount, + totalAmount: transaction.amount / 1000, type: transaction.type == "incoming" ? "received" : "sent", }) ); @@ -100,26 +103,18 @@ class NWCConnector implements Connector { } async makeInvoice(args: MakeInvoiceArgs): Promise { - const result = await this.nwc.makeInvoice({ - amount: args.amount, - defaultMemo: args.memo, + const invoice = await this.nwc.makeInvoice({ + amount: + typeof args.amount === "number" + ? args.amount * 1000 + : parseInt(args.amount) * 1000 || 0, + description: args.memo, }); - let paymentHash = result.paymentHash; - - if (!paymentHash) { - const decodedInvoice = lightningPayReq.decode(result.paymentRequest); - paymentHash = decodedInvoice.tags.find( - (tag) => tag.tagName === "payment_hash" - )?.data as string | undefined; - if (!paymentHash) { - throw new Error("Could not find payment hash in invoice"); - } - } return { data: { - paymentRequest: result.paymentRequest, - rHash: paymentHash, + paymentRequest: invoice.invoice, + rHash: invoice.payment_hash, }, }; } @@ -133,7 +128,14 @@ class NWCConnector implements Connector { throw new Error("Could not find payment hash in invoice"); } - const response = await this.nwc.sendPayment(args.paymentRequest); + const response = await this.nwc.payInvoice({ + invoice: args.paymentRequest, + }); + + const transaction = await this.nwc.lookupInvoice({ + invoice: args.paymentRequest, + }); + return { data: { preimage: response.preimage, @@ -141,22 +143,25 @@ class NWCConnector implements Connector { route: { // TODO: how to get amount paid for zero-amount invoices? total_amt: parseInt(invoice.millisatoshis || "0") / 1000, - // TODO: How to get fees from WebLN? - total_fees: 0, + total_fees: transaction.fees_paid / 1000, }, }, }; } async keysend(args: KeysendArgs): Promise { - const data = await this.nwc.keysend({ - destination: args.pubkey, - amount: args.amount, - customRecords: args.customRecords, + const data = await this.nwc.payKeysend({ + pubkey: args.pubkey, + amount: args.amount * 1000, + tlv_records: this.convertCustomRecords(args.customRecords), }); const paymentHash = SHA256(data.preimage).toString(Hex); + const transaction = await this.nwc.lookupInvoice({ + payment_hash: paymentHash, + }); + return { data: { preimage: data.preimage, @@ -164,8 +169,7 @@ class NWCConnector implements Connector { route: { total_amt: args.amount, - // TODO: How to get fees from WebLN? - total_fees: 0, + total_fees: transaction.fees_paid / 1000, }, }, }; @@ -174,12 +178,12 @@ class NWCConnector implements Connector { async checkPayment(args: CheckPaymentArgs): Promise { try { const response = await this.nwc.lookupInvoice({ - paymentHash: args.paymentHash, + payment_hash: args.paymentHash, }); return { data: { - paid: response.paid, + paid: !!response.settled_at, preimage: response.preimage, }, }; @@ -194,7 +198,7 @@ class NWCConnector implements Connector { } async signMessage(args: SignMessageArgs): Promise { - const response = await this.nwc.signMessage(args.message); + const response = await this.nwc.signMessage({ message: args.message }); return Promise.resolve({ data: { @@ -207,6 +211,15 @@ class NWCConnector implements Connector { connectPeer(args: ConnectPeerArgs): Promise { throw new Error("Method not implemented."); } + + private convertCustomRecords( + customRecords: Record + ): TlvRecord[] { + return Object.entries(customRecords).map(([key, value]) => ({ + type: parseInt(key), + value: value, + })); + } } export default NWCConnector; From d66905cd722228dd9b58d7557b5e7610dc80de4e Mon Sep 17 00:00:00 2001 From: pavanjoshi914 Date: Tue, 9 Jul 2024 13:50:21 +0530 Subject: [PATCH 3/6] fix: hex encoded tlv values, use floor when converting transaction amounts --- src/extension/background-script/connectors/nwc.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/extension/background-script/connectors/nwc.ts b/src/extension/background-script/connectors/nwc.ts index abba0bb3cf..2d687584b5 100644 --- a/src/extension/background-script/connectors/nwc.ts +++ b/src/extension/background-script/connectors/nwc.ts @@ -81,7 +81,7 @@ class NWCConnector implements Connector { async getBalance(): Promise { const balance = await this.nwc.getBalance(); return { - data: { balance: balance.balance / 1000, currency: "BTC" }, + data: { balance: Math.floor(balance.balance / 1000), currency: "BTC" }, }; } @@ -100,7 +100,7 @@ class NWCConnector implements Connector { payment_hash: transaction.payment_hash, settled: true, settleDate: transaction.settled_at * 1000, - totalAmount: transaction.amount / 1000, + totalAmount: Math.floor(transaction.amount / 1000), type: transaction.type == "incoming" ? "received" : "sent", custom_records: mapTLVRecords( transaction.metadata?.["tlv_records"] as TLVRecord[] | undefined @@ -154,8 +154,8 @@ class NWCConnector implements Connector { paymentHash, route: { // TODO: how to get amount paid for zero-amount invoices? - total_amt: parseInt(invoice.millisatoshis || "0") / 1000, - total_fees: transaction.fees_paid / 1000, + total_amt: Math.floor(parseInt(invoice.millisatoshis || "0") / 1000), + total_fees: Math.floor(transaction.fees_paid / 1000), }, }, }; @@ -181,7 +181,7 @@ class NWCConnector implements Connector { route: { total_amt: args.amount, - total_fees: transaction.fees_paid / 1000, + total_fees: Math.floor(transaction.fees_paid / 1000), }, }, }; @@ -229,7 +229,7 @@ class NWCConnector implements Connector { ): TlvRecord[] { return Object.entries(customRecords).map(([key, value]) => ({ type: parseInt(key), - value: value, + value: Hex.parse(value).toString(Base64), })); } } From 5d8b06deae21f441fff8bcf9829b0818672817ab Mon Sep 17 00:00:00 2001 From: im-adithya Date: Wed, 10 Jul 2024 18:03:00 +0530 Subject: [PATCH 4/6] chore: convert to keysend records to hex --- src/extension/background-script/connectors/nwc.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/extension/background-script/connectors/nwc.ts b/src/extension/background-script/connectors/nwc.ts index 2d687584b5..ecf1461e98 100644 --- a/src/extension/background-script/connectors/nwc.ts +++ b/src/extension/background-script/connectors/nwc.ts @@ -2,6 +2,7 @@ import { nwc } from "@getalby/sdk"; import lightningPayReq from "bolt11-signet"; import Base64 from "crypto-js/enc-base64"; import Hex from "crypto-js/enc-hex"; +import UTF8 from "crypto-js/enc-utf8"; import SHA256 from "crypto-js/sha256"; import { Account } from "~/types"; import Connector, { @@ -229,7 +230,7 @@ class NWCConnector implements Connector { ): TlvRecord[] { return Object.entries(customRecords).map(([key, value]) => ({ type: parseInt(key), - value: Hex.parse(value).toString(Base64), + value: UTF8.parse(value).toString(Hex), })); } } From 92ee3d0caab906183fdc20807339a9f6c12d2ffe Mon Sep 17 00:00:00 2001 From: im-adithya Date: Thu, 11 Jul 2024 12:42:54 +0530 Subject: [PATCH 5/6] chore: remove fetching fees --- src/extension/background-script/connectors/nwc.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/extension/background-script/connectors/nwc.ts b/src/extension/background-script/connectors/nwc.ts index ecf1461e98..407c7ec6c2 100644 --- a/src/extension/background-script/connectors/nwc.ts +++ b/src/extension/background-script/connectors/nwc.ts @@ -145,10 +145,6 @@ class NWCConnector implements Connector { invoice: args.paymentRequest, }); - const transaction = await this.nwc.lookupInvoice({ - invoice: args.paymentRequest, - }); - return { data: { preimage: response.preimage, @@ -156,7 +152,8 @@ class NWCConnector implements Connector { route: { // TODO: how to get amount paid for zero-amount invoices? total_amt: Math.floor(parseInt(invoice.millisatoshis || "0") / 1000), - total_fees: Math.floor(transaction.fees_paid / 1000), + // TODO: How to get fees? + total_fees: 0, }, }, }; @@ -171,10 +168,6 @@ class NWCConnector implements Connector { const paymentHash = SHA256(data.preimage).toString(Hex); - const transaction = await this.nwc.lookupInvoice({ - payment_hash: paymentHash, - }); - return { data: { preimage: data.preimage, @@ -182,7 +175,8 @@ class NWCConnector implements Connector { route: { total_amt: args.amount, - total_fees: Math.floor(transaction.fees_paid / 1000), + // TODO: How to get fees? + total_fees: 0, }, }, }; From 41f63ea810a25787ea9418c9bf028d2b2efee06f Mon Sep 17 00:00:00 2001 From: im-adithya Date: Fri, 12 Jul 2024 16:14:04 +0530 Subject: [PATCH 6/6] chore: naming --- .../background-script/connectors/nwc.ts | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/extension/background-script/connectors/nwc.ts b/src/extension/background-script/connectors/nwc.ts index 407c7ec6c2..edc5a592a6 100644 --- a/src/extension/background-script/connectors/nwc.ts +++ b/src/extension/background-script/connectors/nwc.ts @@ -103,7 +103,7 @@ class NWCConnector implements Connector { settleDate: transaction.settled_at * 1000, totalAmount: Math.floor(transaction.amount / 1000), type: transaction.type == "incoming" ? "received" : "sent", - custom_records: mapTLVRecords( + custom_records: this.tlvToCustomRecords( transaction.metadata?.["tlv_records"] as TLVRecord[] | undefined ), }) @@ -163,7 +163,7 @@ class NWCConnector implements Connector { const data = await this.nwc.payKeysend({ pubkey: args.pubkey, amount: args.amount * 1000, - tlv_records: this.convertCustomRecords(args.customRecords), + tlv_records: this.customRecordsToTlv(args.customRecords), }); const paymentHash = SHA256(data.preimage).toString(Hex); @@ -219,7 +219,7 @@ class NWCConnector implements Connector { throw new Error("Method not implemented."); } - private convertCustomRecords( + private customRecordsToTlv( customRecords: Record ): TlvRecord[] { return Object.entries(customRecords).map(([key, value]) => ({ @@ -227,21 +227,23 @@ class NWCConnector implements Connector { value: UTF8.parse(value).toString(Hex), })); } -} -function mapTLVRecords( - tlvRecords: TLVRecord[] | undefined -): ConnectorTransaction["custom_records"] | undefined { - if (!tlvRecords) { - return undefined; - } - const customRecords: ConnectorTransaction["custom_records"] = {}; - for (const tlv of tlvRecords) { - // TODO: ConnectorTransaction["custom_records"] should not be in base64 format - // as this requires unnecessary re-encoding - customRecords[tlv.type.toString()] = Hex.parse(tlv.value).toString(Base64); + private tlvToCustomRecords( + tlvRecords: TLVRecord[] | undefined + ): ConnectorTransaction["custom_records"] | undefined { + if (!tlvRecords) { + return undefined; + } + const customRecords: ConnectorTransaction["custom_records"] = {}; + for (const tlv of tlvRecords) { + // TODO: ConnectorTransaction["custom_records"] should not be in base64 format + // as this requires unnecessary re-encoding + customRecords[tlv.type.toString()] = Hex.parse(tlv.value).toString( + Base64 + ); + } + return customRecords; } - return customRecords; } export default NWCConnector;