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: use new nwc client from sdk #2987

Merged
merged 8 commits into from
Jul 15, 2024
102 changes: 58 additions & 44 deletions src/extension/background-script/connectors/nwc.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { webln } from "@getalby/sdk";
import { NostrWebLNProvider } from "@getalby/sdk/dist/webln";
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, {
Expand Down Expand Up @@ -35,9 +35,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 [
Expand All @@ -54,13 +59,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() {
Expand All @@ -70,14 +75,14 @@ class NWCConnector implements Connector {
async getInfo(): Promise<GetInfoResponse> {
const info = await this.nwc.getInfo();
return {
data: info.node,
data: info,
};
}

async getBalance(): Promise<GetBalanceResponse> {
const balance = await this.nwc.getBalance();
return {
data: { balance: balance.balance, currency: "BTC" },
data: { balance: Math.floor(balance.balance / 1000), currency: "BTC" },
};
}

Expand All @@ -96,9 +101,9 @@ class NWCConnector implements Connector {
payment_hash: transaction.payment_hash,
settled: true,
settleDate: transaction.settled_at * 1000,
totalAmount: transaction.amount,
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
),
})
Expand All @@ -112,22 +117,17 @@ class NWCConnector implements Connector {

async makeInvoice(args: MakeInvoiceArgs): Promise<MakeInvoiceResponse> {
const invoice = await this.nwc.makeInvoice({
amount: args.amount,
defaultMemo: args.memo,
amount:
typeof args.amount === "number"
? args.amount * 1000
: parseInt(args.amount) * 1000 || 0,
description: args.memo,
});

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");
}

return {
data: {
paymentRequest: invoice.paymentRequest,
rHash: paymentHash,
paymentRequest: invoice.invoice,
rHash: invoice.payment_hash,
},
};
}
Expand All @@ -141,26 +141,29 @@ 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,
});

return {
data: {
preimage: response.preimage,
paymentHash,
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_amt: Math.floor(parseInt(invoice.millisatoshis || "0") / 1000),
// TODO: How to get fees?
total_fees: 0,
},
},
};
}

async keysend(args: KeysendArgs): Promise<SendPaymentResponse> {
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,
im-adithya marked this conversation as resolved.
Show resolved Hide resolved
tlv_records: this.customRecordsToTlv(args.customRecords),
});

const paymentHash = SHA256(data.preimage).toString(Hex);
Expand All @@ -172,7 +175,7 @@ class NWCConnector implements Connector {

route: {
total_amt: args.amount,
// TODO: How to get fees from WebLN?
// TODO: How to get fees?
total_fees: 0,
},
},
Expand All @@ -182,12 +185,12 @@ class NWCConnector implements Connector {
async checkPayment(args: CheckPaymentArgs): Promise<CheckPaymentResponse> {
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,
},
};
Expand All @@ -202,7 +205,7 @@ class NWCConnector implements Connector {
}

async signMessage(args: SignMessageArgs): Promise<SignMessageResponse> {
const response = await this.nwc.signMessage(args.message);
const response = await this.nwc.signMessage({ message: args.message });

return Promise.resolve({
data: {
Expand All @@ -215,21 +218,32 @@ class NWCConnector implements Connector {
connectPeer(args: ConnectPeerArgs): Promise<ConnectPeerResponse> {
throw new Error("Method not implemented.");
}
}

function mapTLVRecords(
tlvRecords: TLVRecord[] | undefined
): ConnectorTransaction["custom_records"] | undefined {
if (!tlvRecords) {
return undefined;
private customRecordsToTlv(
customRecords: Record<string, string>
): TlvRecord[] {
return Object.entries(customRecords).map(([key, value]) => ({
type: parseInt(key),
value: UTF8.parse(value).toString(Hex),
}));
}
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;
Loading