mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2025-12-17 06:14:21 +01:00
handle lsp errors
This commit is contained in:
committed by
Tony Giorgio
parent
3f36d5a475
commit
3d2195e6cf
35
scripts/errorsToTs.cjs
Normal file
35
scripts/errorsToTs.cjs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
const fs = require("fs").promises;
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const filePath = process.argv[2]; // grab the file path from the command-line arguments
|
||||||
|
|
||||||
|
if (!filePath) {
|
||||||
|
console.error("Please provide a file path.");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let file;
|
||||||
|
|
||||||
|
try {
|
||||||
|
file = await fs.readFile(filePath, "utf-8");
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to read file at path: ${filePath}`);
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const regex = /#\s*\[error\(\s*"([^"]*)"\s*\)\]/g;
|
||||||
|
|
||||||
|
let matches = file.match(regex);
|
||||||
|
|
||||||
|
if (matches) {
|
||||||
|
let errors = matches.map((match) => match.match(/"(.*?)"/)[1]); // capture text within ""
|
||||||
|
let typeScriptTypeString = `type MutinyError = "${errors.join(
|
||||||
|
'"\n\t| "'
|
||||||
|
)}";`;
|
||||||
|
|
||||||
|
console.log(typeScriptTypeString);
|
||||||
|
} else {
|
||||||
|
console.error("No matches found in the provided file.");
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -68,12 +68,20 @@ export function IntegratedQr(props: {
|
|||||||
<p class="text-xl font-bold">Copied</p>
|
<p class="text-xl font-bold">Copied</p>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
<div class="w-full flex justify-between items-center py-4 max-w-[256px]">
|
<div
|
||||||
|
class="w-full flex items-center py-4 max-w-[256px]"
|
||||||
|
classList={{
|
||||||
|
"justify-between": props.kind !== "onchain",
|
||||||
|
"justify-end": props.kind === "onchain"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Show when={props.kind !== "onchain"}>
|
||||||
<Amount
|
<Amount
|
||||||
amountSats={Number(props.amountSats)}
|
amountSats={Number(props.amountSats)}
|
||||||
showFiat
|
showFiat
|
||||||
whiteBg
|
whiteBg
|
||||||
/>
|
/>
|
||||||
|
</Show>
|
||||||
<KindIndicator kind={props.kind} />
|
<KindIndicator kind={props.kind} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
68
src/logic/errorDispatch.ts
Normal file
68
src/logic/errorDispatch.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// IMPORTANT: this should match 1:1 with the MutinyJsError enum in mutiny-wasm
|
||||||
|
// If we can handle all of these, we can handle all the errors that Mutiny can throw
|
||||||
|
|
||||||
|
// WARNING: autogenerated code, generated by errorsToTs.cjs
|
||||||
|
type MutinyError =
|
||||||
|
| "Mutiny is already running."
|
||||||
|
| "Mutiny is not running."
|
||||||
|
| "Resource Not found."
|
||||||
|
| "Funding transaction could not be created."
|
||||||
|
| "Network connection closed."
|
||||||
|
| "The invoice or address is on a different network."
|
||||||
|
| "An invoice must not get payed twice."
|
||||||
|
| "Payment timed out."
|
||||||
|
| "The given invoice is invalid."
|
||||||
|
| "Failed to create invoice."
|
||||||
|
| "Channel reserve amount is too high."
|
||||||
|
| "We do not have enough balance to pay the given amount."
|
||||||
|
| "Failed to call on the given LNURL."
|
||||||
|
| "Failed to make a request to the LSP."
|
||||||
|
| "Failed to request channel from LSP due to funding error."
|
||||||
|
| "Failed to have a connection to the LSP node."
|
||||||
|
| "Subscription Client Not Configured"
|
||||||
|
| "Invalid Parameter"
|
||||||
|
| "Called incorrect lnurl function."
|
||||||
|
| "Failed to find route."
|
||||||
|
| "Failed to parse the given peer information."
|
||||||
|
| "Failed to create channel."
|
||||||
|
| "Failed to close channel."
|
||||||
|
| "Failed to persist data."
|
||||||
|
| "Failed to read data from storage."
|
||||||
|
| "Failed to decode lightning data."
|
||||||
|
| "Failed to generate seed"
|
||||||
|
| "Invalid mnemonic"
|
||||||
|
| "Failed to conduct wallet operation."
|
||||||
|
| "Failed to sign given transaction."
|
||||||
|
| "Failed to conduct chain access operation."
|
||||||
|
| "Failed to to sync on-chain wallet."
|
||||||
|
| "Failed to execute a rapid gossip sync function"
|
||||||
|
| "Failed to read or write json from the front end"
|
||||||
|
| "The given node pubkey is invalid."
|
||||||
|
| "Failed to get the bitcoin price."
|
||||||
|
| "Satoshi amount is invalid"
|
||||||
|
| "Failed to execute a dlc function"
|
||||||
|
| "Failed to execute a wasm_bindgen function"
|
||||||
|
| "Invalid Arguments were given"
|
||||||
|
| "Incorrect password entered."
|
||||||
|
| "Unknown Error";
|
||||||
|
|
||||||
|
export function matchError(e: unknown): Error {
|
||||||
|
let errorString;
|
||||||
|
|
||||||
|
if (e instanceof Error) {
|
||||||
|
errorString = e.message;
|
||||||
|
} else if (typeof e === "string") {
|
||||||
|
errorString = e;
|
||||||
|
} else {
|
||||||
|
errorString = "Unknown error";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (errorString as MutinyError) {
|
||||||
|
case "Failed to make a request to the LSP.":
|
||||||
|
case "Failed to request channel from LSP due to funding error.":
|
||||||
|
case "Failed to have a connection to the LSP node.":
|
||||||
|
return new Error("LSP error, only on-chain is available for now.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Error(errorString);
|
||||||
|
}
|
||||||
@@ -45,6 +45,8 @@ import { FeesModal } from "~/components/MoreInfoModal";
|
|||||||
import { IntegratedQr } from "~/components/IntegratedQR";
|
import { IntegratedQr } from "~/components/IntegratedQR";
|
||||||
import side2side from "~/assets/icons/side-to-side.svg";
|
import side2side from "~/assets/icons/side-to-side.svg";
|
||||||
import { useI18n } from "~/i18n/context";
|
import { useI18n } from "~/i18n/context";
|
||||||
|
import eify from "~/utils/eify";
|
||||||
|
import { matchError } from "~/logic/errorDispatch";
|
||||||
|
|
||||||
type OnChainTx = {
|
type OnChainTx = {
|
||||||
transaction: {
|
transaction: {
|
||||||
@@ -167,6 +169,9 @@ export default function Receive() {
|
|||||||
// The flavor of the receive
|
// The flavor of the receive
|
||||||
const [flavor, setFlavor] = createSignal<ReceiveFlavor>("unified");
|
const [flavor, setFlavor] = createSignal<ReceiveFlavor>("unified");
|
||||||
|
|
||||||
|
// loading state for the continue button
|
||||||
|
const [loading, setLoading] = createSignal(false);
|
||||||
|
|
||||||
const receiveString = createMemo(() => {
|
const receiveString = createMemo(() => {
|
||||||
if (unified() && receiveState() === "show") {
|
if (unified() && receiveState() === "show") {
|
||||||
if (flavor() === "unified") {
|
if (flavor() === "unified") {
|
||||||
@@ -227,8 +232,23 @@ export default function Receive() {
|
|||||||
|
|
||||||
async function getUnifiedQr(amount: string) {
|
async function getUnifiedQr(amount: string) {
|
||||||
const bigAmount = BigInt(amount);
|
const bigAmount = BigInt(amount);
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
// Both paths use tags so we'll do this once
|
||||||
|
let tags;
|
||||||
|
|
||||||
|
try {
|
||||||
|
tags = await processContacts(selectedValues());
|
||||||
|
} catch (e) {
|
||||||
|
showToast(eify(e));
|
||||||
|
console.error(e);
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Happy path
|
||||||
|
// First we try to get both an invoice and an address
|
||||||
try {
|
try {
|
||||||
const tags = await processContacts(selectedValues());
|
|
||||||
const raw = await state.mutiny_wallet?.create_bip21(
|
const raw = await state.mutiny_wallet?.create_bip21(
|
||||||
bigAmount,
|
bigAmount,
|
||||||
tags
|
tags
|
||||||
@@ -241,11 +261,32 @@ export default function Receive() {
|
|||||||
lightning: raw?.invoice
|
lightning: raw?.invoice
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
return `bitcoin:${raw?.address}?${params}`;
|
return `bitcoin:${raw?.address}?${params}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showToast(new Error("Failed to create invoice. Please try again."));
|
showToast(matchError(e));
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we didn't return before this, that means create_bip21 failed
|
||||||
|
// So now we'll just try and get an address without the invoice
|
||||||
|
try {
|
||||||
|
const raw = await state.mutiny_wallet?.get_new_address(tags);
|
||||||
|
|
||||||
|
// Save the raw info so we can watch the address
|
||||||
|
setBip21Raw(raw);
|
||||||
|
|
||||||
|
setFlavor("onchain");
|
||||||
|
|
||||||
|
// We won't meddle with a "unified" QR here
|
||||||
|
return raw?.address;
|
||||||
|
} catch (e) {
|
||||||
|
// If THAT failed we're really screwed
|
||||||
|
showToast(matchError(e));
|
||||||
|
console.error(e);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onSubmit(e: Event) {
|
async function onSubmit(e: Event) {
|
||||||
@@ -267,6 +308,8 @@ export default function Receive() {
|
|||||||
const address = bip21.address;
|
const address = bip21.address;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Lightning invoice might be blank
|
||||||
|
if (lightning) {
|
||||||
const invoice = await state.mutiny_wallet?.get_invoice(
|
const invoice = await state.mutiny_wallet?.get_invoice(
|
||||||
lightning
|
lightning
|
||||||
);
|
);
|
||||||
@@ -281,6 +324,7 @@ export default function Receive() {
|
|||||||
setPaymentInvoice(invoice);
|
setPaymentInvoice(invoice);
|
||||||
return "lightning_paid";
|
return "lightning_paid";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const tx = (await state.mutiny_wallet?.check_address(
|
const tx = (await state.mutiny_wallet?.check_address(
|
||||||
address
|
address
|
||||||
@@ -350,7 +394,9 @@ export default function Receive() {
|
|||||||
<TagEditor
|
<TagEditor
|
||||||
selectedValues={selectedValues()}
|
selectedValues={selectedValues()}
|
||||||
setSelectedValues={setSelectedValues}
|
setSelectedValues={setSelectedValues}
|
||||||
placeholder={i18n.t("receive_add_the_sender")}
|
placeholder={i18n.t(
|
||||||
|
"receive_add_the_sender"
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
@@ -360,6 +406,7 @@ export default function Receive() {
|
|||||||
disabled={!amount()}
|
disabled={!amount()}
|
||||||
intent="green"
|
intent="green"
|
||||||
onClick={onSubmit}
|
onClick={onSubmit}
|
||||||
|
loading={loading()}
|
||||||
>
|
>
|
||||||
{i18n.t("continue")}
|
{i18n.t("continue")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -375,6 +422,8 @@ export default function Receive() {
|
|||||||
<p class="text-neutral-400 text-center">
|
<p class="text-neutral-400 text-center">
|
||||||
{i18n.t("keep_mutiny_open")}
|
{i18n.t("keep_mutiny_open")}
|
||||||
</p>
|
</p>
|
||||||
|
{/* Only show method chooser when we have an invoice */}
|
||||||
|
<Show when={bip21Raw()?.invoice}>
|
||||||
<button
|
<button
|
||||||
class="font-bold text-m-grey-400 flex gap-2 p-2 items-center mx-auto"
|
class="font-bold text-m-grey-400 flex gap-2 p-2 items-center mx-auto"
|
||||||
onClick={() => setMethodChooserOpen(true)}
|
onClick={() => setMethodChooserOpen(true)}
|
||||||
@@ -385,7 +434,9 @@ export default function Receive() {
|
|||||||
<SimpleDialog
|
<SimpleDialog
|
||||||
title="Choose payment format"
|
title="Choose payment format"
|
||||||
open={methodChooserOpen()}
|
open={methodChooserOpen()}
|
||||||
setOpen={(open) => setMethodChooserOpen(open)}
|
setOpen={(open) =>
|
||||||
|
setMethodChooserOpen(open)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<StyledRadioGroup
|
<StyledRadioGroup
|
||||||
value={flavor()}
|
value={flavor()}
|
||||||
@@ -395,6 +446,7 @@ export default function Receive() {
|
|||||||
vertical
|
vertical
|
||||||
/>
|
/>
|
||||||
</SimpleDialog>
|
</SimpleDialog>
|
||||||
|
</Show>
|
||||||
</Match>
|
</Match>
|
||||||
<Match
|
<Match
|
||||||
when={
|
when={
|
||||||
|
|||||||
Reference in New Issue
Block a user