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: connect to btcpay via core lightning #3016

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions src/app/router/connectorRoutes.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import ChooseConnector from "@screens/connectors/ChooseConnector";
import ConnectBtcpay from "@screens/connectors/ConnectBtcpay";
import ConnectCitadel from "@screens/connectors/ConnectCitadel";
import ConnectEclair from "@screens/connectors/ConnectEclair";
import ConnectGaloy, { galoyUrls } from "@screens/connectors/ConnectGaloy";
Expand All @@ -14,6 +13,8 @@ import ConnectUmbrel from "@screens/connectors/ConnectUmbrel";
import { Route } from "react-router-dom";
import i18n from "~/i18n/i18nConfig";

import ConnectBtcpayCommando from "~/app/screens/connectors/ConnectBtcpayCommando";
import ConnectBtcpayLND from "~/app/screens/connectors/ConnectBtcpayLND";
import ConnectNWC from "~/app/screens/connectors/ConnectNWC";
import ConnectVoltage from "~/app/screens/connectors/ConnectVoltage";
import ConnectCommando from "../screens/connectors/ConnectCommando";
Expand Down Expand Up @@ -81,6 +82,18 @@ const connectorMap: { [key: string]: ConnectorRoute } = {
title: i18n.t("translation:choose_connector.umbrel_lightning_node.title"),
logo: lightning_node,
},
"btcpay-lnd": {
path: "lnd",
element: <ConnectBtcpayLND />,
title: i18n.t("translation:choose_connector.lnd.title"),
logo: lnd,
},
"btcpay-commando": {
path: "commando",
element: <ConnectBtcpayCommando />,
title: i18n.t("translation:choose_connector.commando.title"),
logo: core_ln,
},
"raspiblitz-lnd": {
path: "lnd",
element: <ConnectRaspiBlitz />,
Expand Down Expand Up @@ -153,12 +166,6 @@ const connectorMap: { [key: string]: ConnectorRoute } = {
title: i18n.t("translation:choose_connector.bitcoin_jungle.title"),
logo: galoyBitcoinJungle,
},
btcpay: {
path: "btcpay",
element: <ConnectBtcpay />,
title: i18n.t("translation:choose_connector.btcpay.title"),
logo: btcpay,
},
voltage: {
path: "voltage",
element: <ConnectVoltage />,
Expand Down Expand Up @@ -203,6 +210,10 @@ const distributionMap: { [key: string]: { logo: string; children: Route[] } } =
connectorMap["lnbits"],
],
},
btcpay: {
logo: btcpay,
children: [connectorMap["btcpay-lnd"], connectorMap["btcpay-commando"]],
},
umbrel: {
logo: umbrel,
children: [
Expand Down Expand Up @@ -250,7 +261,7 @@ function getConnectorRoutes(): ConnectorRoute[] {
connectorMap["lnbits"],
connectorMap["lnd-hub-go"],
connectorMap["eclair"],
connectorMap["btcpay"],
getDistribution("btcpay"),
connectorMap["voltage"],
connectorMap[galoyPaths.blink],
connectorMap[galoyPaths.bitcoinJungle],
Expand Down
144 changes: 144 additions & 0 deletions src/app/screens/connectors/ConnectBtcpayCommando/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import CompanionDownloadInfo from "@components/CompanionDownloadInfo";
import ConnectorForm from "@components/ConnectorForm";
import TextField from "@components/form/TextField";
import ConnectionErrorToast from "@components/toasts/ConnectionErrorToast";
import fetchAdapter from "@vespaiach/axios-fetch-adapter";
import axios from "axios";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import toast from "~/app/components/Toast";
import msg from "~/common/lib/msg";

import logo from "/static/assets/icons/btcpay.svg";

const initialFormData = {
url: "",
macaroon: "",
name: "",
};

export default function ConnectBtcpayCommando() {
const navigate = useNavigate();
const { t } = useTranslation("translation", {
keyPrefix: "choose_connector.btcpay_commando",
});
const [formData, setFormData] = useState(initialFormData);
const [loading, setLoading] = useState(false);
const [hasTorSupport, setHasTorSupport] = useState(false);

function getConfigUrl(data: string) {
const configUrl = data.trim().replace("config=", "");
try {
return new URL(configUrl);
} catch (e) {
return null;
}
}
async function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
const configUrl = getConfigUrl(event.target.value);
if (!configUrl) {
return;
}
const host = configUrl.host;
try {
const response = await axios.get<{
configurations: [{ uri: string; adminMacaroon: string }];
}>(configUrl.toString(), { adapter: fetchAdapter });

if (response.data.configurations[0].uri) {
setFormData({
url: response.data.configurations[0].uri,
macaroon: response.data.configurations[0].adminMacaroon,
name: host,
});
}
} catch (e) {
console.error(e);
toast.error(t("errors.connection_failed"));
}
}

function getConnectorType() {
if (formData.url.match(/\.onion/i) && !hasTorSupport) {
return "nativelnd";
}
// default to LND
return "lnd";
}

async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
setLoading(true);
const { url, macaroon, name } = formData;
const account = {
name: name || "LND",
config: {
macaroon,
url,
},
connector: getConnectorType(),
};

try {
let validation;
// TODO: for native connectors we currently skip the validation because it is too slow (booting up Tor etc.)
if (account.connector === "nativelnd") {
validation = { valid: true, error: "" };
} else {
validation = await msg.request("validateAccount", account);
}

if (validation.valid) {
const addResult = await msg.request("addAccount", account);
if (addResult.accountId) {
await msg.request("selectAccount", {
id: addResult.accountId,
});
navigate("/test-connection");
}
} else {
toast.error(
<ConnectionErrorToast message={validation.error as string} />
);
}
} catch (e) {
console.error(e);
let message = "";
if (e instanceof Error) {
message += `${e.message}`;
}
toast.error(<ConnectionErrorToast message={message} />);
}
setLoading(false);
}

return (
<ConnectorForm
title={t("page.title")}
description={t("page.instructions")}
logo={logo}
submitLoading={loading}
submitDisabled={formData.url === "" || formData.macaroon === ""}
onSubmit={handleSubmit}
>
<TextField
id="btcpay-config"
label={t("config.label")}
placeholder={t("config.placeholder")}
onChange={handleChange}
required
autoFocus={true}
/>
{formData.url.match(/\.onion/i) && (
<div className="mt-6">
<CompanionDownloadInfo
hasTorCallback={(hasTor: boolean) => {
setHasTorSupport(hasTor);
}}
/>
</div>
)}
</ConnectorForm>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ const initialFormData = {
name: "",
};

export default function ConnectBtcpay() {
export default function ConnectBtcpayLND() {
const navigate = useNavigate();
const { t } = useTranslation("translation", {
keyPrefix: "choose_connector.btcpay",
keyPrefix: "choose_connector.btcpay_lnd",
});
const [formData, setFormData] = useState(initialFormData);
const [loading, setLoading] = useState(false);
Expand Down
21 changes: 18 additions & 3 deletions src/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,25 @@
}
},
"btcpay": {
"title": "BTCPay Server",
"title": "BTCPay Server"
},
"btcpay_lnd": {
"page": {
"title": "Connect to BTCPay LND",
"instructions": "Navigate to your BTCPayServer and log in as an admin. Go to Server Settings > Services > LND REST - See information. Then Click \"See QR Code information\" and copy the QR Code data. Paste it below:"
},
"config": {
"label": "Config data",
"placeholder": "config=https://your-btc-pay.org/lnd-config/212121/lnd.co"
},
"errors": {
"connection_failed": "Connection failed. Is the BTCPay connection URL correct and accessible?"
}
},
"btcpay_commando": {
"page": {
"title": "Connect to your BTCPay LND node",
"instructions": "Navigate to your BTCPayServer and log in as an admin. Go to Server Settings > Services > LND Rest - See information. Then Click \"See QR Code information\" and copy the QR Code data. Paste it below:"
"title": "Connect to BTCPay CLN",
"instructions": "Navigate to your BTCPayServer and log in as an admin. Go to Server Settings > Services > C- Lightning REST - See information. Then Click \"See QR Code information\" and copy the QR Code data. Paste it below:"
},
"config": {
"label": "Config data",
Expand Down
Loading