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>
|
||||
</div>
|
||||
</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
|
||||
amountSats={Number(props.amountSats)}
|
||||
showFiat
|
||||
whiteBg
|
||||
/>
|
||||
</Show>
|
||||
<KindIndicator kind={props.kind} />
|
||||
</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 side2side from "~/assets/icons/side-to-side.svg";
|
||||
import { useI18n } from "~/i18n/context";
|
||||
import eify from "~/utils/eify";
|
||||
import { matchError } from "~/logic/errorDispatch";
|
||||
|
||||
type OnChainTx = {
|
||||
transaction: {
|
||||
@@ -167,6 +169,9 @@ export default function Receive() {
|
||||
// The flavor of the receive
|
||||
const [flavor, setFlavor] = createSignal<ReceiveFlavor>("unified");
|
||||
|
||||
// loading state for the continue button
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
|
||||
const receiveString = createMemo(() => {
|
||||
if (unified() && receiveState() === "show") {
|
||||
if (flavor() === "unified") {
|
||||
@@ -227,8 +232,23 @@ export default function Receive() {
|
||||
|
||||
async function getUnifiedQr(amount: string) {
|
||||
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 {
|
||||
const tags = await processContacts(selectedValues());
|
||||
const raw = await state.mutiny_wallet?.create_bip21(
|
||||
bigAmount,
|
||||
tags
|
||||
@@ -241,11 +261,32 @@ export default function Receive() {
|
||||
lightning: raw?.invoice
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
return `bitcoin:${raw?.address}?${params}`;
|
||||
} catch (e) {
|
||||
showToast(new Error("Failed to create invoice. Please try again."));
|
||||
showToast(matchError(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) {
|
||||
@@ -267,6 +308,8 @@ export default function Receive() {
|
||||
const address = bip21.address;
|
||||
|
||||
try {
|
||||
// Lightning invoice might be blank
|
||||
if (lightning) {
|
||||
const invoice = await state.mutiny_wallet?.get_invoice(
|
||||
lightning
|
||||
);
|
||||
@@ -281,6 +324,7 @@ export default function Receive() {
|
||||
setPaymentInvoice(invoice);
|
||||
return "lightning_paid";
|
||||
}
|
||||
}
|
||||
|
||||
const tx = (await state.mutiny_wallet?.check_address(
|
||||
address
|
||||
@@ -350,7 +394,9 @@ export default function Receive() {
|
||||
<TagEditor
|
||||
selectedValues={selectedValues()}
|
||||
setSelectedValues={setSelectedValues}
|
||||
placeholder={i18n.t("receive_add_the_sender")}
|
||||
placeholder={i18n.t(
|
||||
"receive_add_the_sender"
|
||||
)}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
@@ -360,6 +406,7 @@ export default function Receive() {
|
||||
disabled={!amount()}
|
||||
intent="green"
|
||||
onClick={onSubmit}
|
||||
loading={loading()}
|
||||
>
|
||||
{i18n.t("continue")}
|
||||
</Button>
|
||||
@@ -375,6 +422,8 @@ export default function Receive() {
|
||||
<p class="text-neutral-400 text-center">
|
||||
{i18n.t("keep_mutiny_open")}
|
||||
</p>
|
||||
{/* Only show method chooser when we have an invoice */}
|
||||
<Show when={bip21Raw()?.invoice}>
|
||||
<button
|
||||
class="font-bold text-m-grey-400 flex gap-2 p-2 items-center mx-auto"
|
||||
onClick={() => setMethodChooserOpen(true)}
|
||||
@@ -385,7 +434,9 @@ export default function Receive() {
|
||||
<SimpleDialog
|
||||
title="Choose payment format"
|
||||
open={methodChooserOpen()}
|
||||
setOpen={(open) => setMethodChooserOpen(open)}
|
||||
setOpen={(open) =>
|
||||
setMethodChooserOpen(open)
|
||||
}
|
||||
>
|
||||
<StyledRadioGroup
|
||||
value={flavor()}
|
||||
@@ -395,6 +446,7 @@ export default function Receive() {
|
||||
vertical
|
||||
/>
|
||||
</SimpleDialog>
|
||||
</Show>
|
||||
</Match>
|
||||
<Match
|
||||
when={
|
||||
|
||||
Reference in New Issue
Block a user