feat: improve error reporting for wallet payments

This commit is contained in:
Kieran 2023-05-17 16:30:23 +01:00
parent 202b9933e0
commit 167f1c5e65
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
4 changed files with 46 additions and 6 deletions

View File

@ -1,6 +1,7 @@
import { ReactNode, useSyncExternalStore } from "react";
import { v4 as uuid } from "uuid";
import ExternalStore from "ExternalStore";
import Icon from "Icons/Icon";
import { ReactNode, useSyncExternalStore } from "react";
import { unixNow } from "Util";
import "./Toaster.css";
@ -9,6 +10,7 @@ interface ToastNotification {
element: ReactNode;
expire?: number;
icon?: string;
id?: string;
}
class ToasterSlots extends ExternalStore<Array<ToastNotification>> {
@ -17,6 +19,7 @@ class ToasterSlots extends ExternalStore<Array<ToastNotification>> {
push(n: ToastNotification) {
n.expire ??= unixNow() + 3;
n.id ??= uuid();
this.#stack.push(n);
this.notifyChange();
}
@ -43,7 +46,7 @@ export default function Toaster() {
return (
<div className="toaster">
{toast.map(a => (
<div className="card flex">
<div className="card flex" key={a.id}>
<Icon name={a.icon ?? "bell"} className="mr5" />
{a.element}
</div>

View File

@ -123,7 +123,7 @@ export default class LNDHubWallet implements LNWallet {
},
});
const json = await rsp.json();
if ("error" in json) {
if ("code" in json && !rsp.ok) {
const err = json as ErrorResponse;
throw new WalletError(err.code, err.message);
}

View File

@ -1,7 +1,7 @@
import { Connection, RawEvent } from "@snort/nostr";
import { EventBuilder } from "System";
import { EventExt } from "System/EventExt";
import { LNWallet, WalletError, WalletErrorCode, WalletInfo, WalletInvoice } from "Wallet";
import { LNWallet, WalletError, WalletErrorCode, WalletInfo, WalletInvoice, WalletInvoiceState } from "Wallet";
interface WalletConnectConfig {
relayUrl: string;
@ -14,6 +14,23 @@ interface QueueObj {
reject: (e: Error) => void;
}
interface WalletConnectResponse<T> {
result_type?: string;
result?: T;
error?: {
code:
| "RATE_LIMITED"
| "NOT_IMPLEMENTED"
| "INSUFFICIENT_BALANCE"
| "QUOTA_EXCEEDED"
| "RESTRICTED"
| "UNAUTHORIZED"
| "INTERNAL"
| "OTHER";
message: string;
};
}
export class NostrConnectWallet implements LNWallet {
#config: WalletConnectConfig;
#conn?: Connection;
@ -83,9 +100,18 @@ export class NostrConnectWallet implements LNWallet {
async payInvoice(pr: string) {
await this.login();
return await this.#rpc<WalletInvoice>("pay_invoice", {
const rsp = await this.#rpc<WalletConnectResponse<WalletInvoice>>("pay_invoice", {
invoice: pr,
});
if (!rsp.error) {
return {
...rsp.result,
pr,
state: WalletInvoiceState.Paid,
} as WalletInvoice;
} else {
throw new WalletError(WalletErrorCode.GeneralError, rsp.error.message);
}
}
getInvoices() {

View File

@ -47,6 +47,7 @@ class ZapPool extends ExternalStore<Array<ZapPoolRecipient>> {
const invoice = await svc.getInvoice(amtSend, `SnortZapPool: ${x.split}%`);
if (invoice.pr) {
const result = await wallet.payInvoice(invoice.pr);
console.debug("ZPC", invoice, result);
if (result.state === WalletInvoiceState.Paid) {
x.sum -= amtSend;
Toastore.push({
@ -58,13 +59,23 @@ class ZapPool extends ExternalStore<Array<ZapPoolRecipient>> {
icon: "zap",
});
} else {
throw new Error("Payment failed");
throw new Error(`Failed to pay invoice, unknown reason`);
}
} else {
throw new Error(invoice.reason ?? "Failed to get invoice");
}
} catch (e) {
console.error(e);
if (e instanceof Error) {
const profile = UserCache.getFromCache(x.pubkey);
Toastore.push({
element: `Failed to send sats to ${getDisplayName(profile, x.pubkey)} (${
e.message
}), please try again later`,
expire: unixNow() + 10,
icon: "close",
});
}
}
}
this.#save();