Skip to content

Commit

Permalink
feat: onchain swaps (#2514)
Browse files Browse the repository at this point in the history
* feat: ui for onchain payments

* feat: first working draft with api mocks

* fix: ui updates

* fix: api location update

* fix: translations

* fix: amount validation

* chore: use new swap apis in alby-js-sdk

* fix: add testnet addresses

* fix: pay

* fix: todos

* fix: todos

* fix: ts

* chore: update @getalby/sdk

* fix: update imports

* fix: alby sdk dependency

* fix: address display in send to bitcoin address screen

* chore: only display total fee on swap form

* fix: remove extra space between swap info and confirmation button

* chore: update comments

* chore: add error logs

* fix: add missing target to hyperlink

* chore: add getSwapInfo and createSwap as optional connector methods

* fix: swap confirmation screen spacing issues

* fix: layout & spacing for prompts

* fix: spacing

* fix: minor ui improvements

* fix: add noopener

* fix: add message to error message

* fix: package downgrade

* fix: lint errors

* fix: yarn lock

* fix: packages

* Revert "fix: lint errors"

This reverts commit 7494a47.

* fix: reset formatting for untouched files

* fix: reset formatting for untouched files

* fix: add support email, fixes

* fix: remove info icon from alert component

* fix: disable review button if loading swaps failed

* fix: add better error message if service unavailable

---------

Co-authored-by: Roland Bewick <[email protected]>
  • Loading branch information
reneaaron and rolznz authored Aug 24, 2023
1 parent cd2bf74 commit 42e38ea
Show file tree
Hide file tree
Showing 27 changed files with 644 additions and 75 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
},
"dependencies": {
"@bitcoin-design/bitcoin-icons-react": "^0.1.9",
"@getalby/sdk": "^2.2.3",
"@headlessui/react": "^1.7.16",
"@lightninglabs/lnc-web": "^0.2.4-alpha",
"@noble/curves": "^1.1.0",
Expand All @@ -45,7 +46,6 @@
"@scure/btc-signer": "^0.5.1",
"@tailwindcss/forms": "^0.5.4",
"@vespaiach/axios-fetch-adapter": "^0.3.0",
"alby-js-sdk": "^2.1.2",
"axios": "^0.27.2",
"bech32": "^2.0.0",
"bolt11": "^1.4.1",
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Alert/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ export default function Alert({ type, children }: Props) {
type == "warn" &&
"text-orange-700 bg-orange-50 dark:text-orange-200 dark:bg-orange-900",
type == "info" &&
"text-blue-700 bg-blue-50 dark:text-blue-200 dark:bg-blue-900"
"text-blue-700 bg-blue-50 dark:text-blue-300 dark:bg-blue-900"
)}
>
<p>{children}</p>
{children}
</div>
);
}
38 changes: 18 additions & 20 deletions src/app/components/ConfirmOrCancel/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useRef, useEffect } from "react";
import type { MouseEventHandler } from "react";
import { useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import Button from "~/app/components/Button";
import i18n from "~/i18n/i18nConfig";
Expand Down Expand Up @@ -29,25 +29,23 @@ export default function ConfirmOrCancel({
}, [isFocused]);

return (
<div className="pt-2 pb-4">
<div className="flex flex-row justify-between">
<Button
onClick={onCancel}
label={tCommon("actions.cancel")}
halfWidth
disabled={loading}
/>
<Button
type="submit"
ref={buttonRef}
onClick={onConfirm}
label={label}
primary
disabled={disabled}
loading={loading}
halfWidth
/>
</div>
<div className="flex flex-row justify-between">
<Button
onClick={onCancel}
label={tCommon("actions.cancel")}
halfWidth
disabled={loading}
/>
<Button
type="submit"
ref={buttonRef}
onClick={onConfirm}
label={label}
primary
disabled={disabled}
loading={loading}
halfWidth
/>
</div>
);
}
4 changes: 2 additions & 2 deletions src/app/components/Container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ function Container({

return (
<div
className={`container mx-auto px-4 mb-5 ${getMaxWidthClass(maxWidth)} ${
className={`container mx-auto px-4 pb-4 ${getMaxWidthClass(maxWidth)} ${
justifyBetween
? "h-full flex flex-col justify-between overflow-y-auto no-scrollbar"
? "h-full flex flex-col justify-between no-scrollbar"
: ""
}`}
>
Expand Down
5 changes: 5 additions & 0 deletions src/app/router/Options/Options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import Discover from "~/app/screens/Discover";
import LNURLRedeem from "~/app/screens/LNURLRedeem";
import OnChainReceive from "~/app/screens/OnChainReceive";
import ScanQRCode from "~/app/screens/ScanQRCode";
import SendToBitcoinAddress from "~/app/screens/SendToBitcoinAddress";
import ChooseConnector from "~/app/screens/connectors/ChooseConnector";
import ChooseConnectorPath from "~/app/screens/connectors/ChooseConnectorPath";
import i18n from "~/i18n/i18nConfig";
Expand Down Expand Up @@ -65,6 +66,10 @@ function Options() {
<Route path="send" element={<Send />} />
<Route path="confirmPayment" element={<ConfirmPayment />} />
<Route path="keysend" element={<Keysend />} />
<Route
path="sendToBitcoinAddress"
element={<SendToBitcoinAddress />}
/>
<Route path="receive" element={<Receive />} />
<Route path="onChainReceive" element={<OnChainReceive />} />
<Route path="wallet" element={<DefaultView />} />
Expand Down
5 changes: 5 additions & 0 deletions src/app/router/Popup/Popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { ToastContainer } from "react-toastify";
import Providers from "~/app/context/Providers";
import LNURLRedeem from "~/app/screens/LNURLRedeem";
import OnChainReceive from "~/app/screens/OnChainReceive";
import SendToBitcoinAddress from "~/app/screens/SendToBitcoinAddress";

import RequireAuth from "../RequireAuth";

Expand Down Expand Up @@ -43,6 +44,10 @@ function Popup() {
<Route path="keysend" element={<Keysend />} />
<Route path="confirmPayment" element={<ConfirmPayment />} />
<Route path="lnurlAuth" element={<LNURLAuth />} />
<Route
path="sendToBitcoinAddress"
element={<SendToBitcoinAddress />}
/>
</Route>
<Route
path="unlock"
Expand Down
2 changes: 1 addition & 1 deletion src/app/screens/ConfirmRequestPermission/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const ConfirmRequestPermission: FC = () => {
</div>
</div>
</div>
<div className="mb-4 text-center flex flex-col">
<div className="text-center flex flex-col">
<ConfirmOrCancel
label={tCommon("actions.confirm")}
onCancel={reject}
Expand Down
2 changes: 1 addition & 1 deletion src/app/screens/Enable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ function Enable(props: Props) {
onCancel={reject}
/>
<a
className="underline text-sm text-gray-400 mx-4 overflow-hidden text-ellipsis whitespace-nowrap"
className="mt-4 underline text-sm text-gray-400 overflow-hidden text-ellipsis whitespace-nowrap"
href="#"
onClick={block}
>
Expand Down
4 changes: 2 additions & 2 deletions src/app/screens/Nostr/Confirm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,15 @@ function NostrConfirm() {
</label>
</div>
</div>
<div className="mb-4 text-center flex flex-col">
<div className="text-center flex flex-col">
<ConfirmOrCancel
disabled={loading}
loading={loading}
label={tCommon("actions.confirm")}
onCancel={reject}
/>
<a
className="underline text-sm text-gray-400 mx-4 overflow-hidden text-ellipsis whitespace-nowrap"
className="mt-4 underline text-sm text-gray-400 overflow-hidden text-ellipsis whitespace-nowrap"
href="#"
onClick={block}
>
Expand Down
6 changes: 3 additions & 3 deletions src/app/screens/Nostr/ConfirmGetPublicKey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function NostrConfirmGetPublicKey() {
</div>

<form onSubmit={handleSubmit}>
<div className="flex items-center">
<div className="flex items-center mb-4">
<Checkbox
id="remember_permission"
name="remember_permission"
Expand All @@ -92,15 +92,15 @@ function NostrConfirmGetPublicKey() {
</label>
</div>

<div className="mb-4 text-center flex flex-col">
<div className="text-center flex flex-col">
<ConfirmOrCancel
disabled={loading}
loading={loading}
label={tCommon("actions.confirm")}
onCancel={reject}
/>
<a
className="underline text-sm text-gray-400 mx-4 overflow-hidden text-ellipsis whitespace-nowrap"
className="mt-4 underline text-sm text-gray-400 overflow-hidden text-ellipsis whitespace-nowrap"
href="#"
onClick={block}
>
Expand Down
14 changes: 8 additions & 6 deletions src/app/screens/Nostr/ConfirmSignMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ function ConfirmSignMessage() {
{JSON.stringify(event, null, 2)}
</div>
)}
<div className="flex items-center">
</div>
<div>
<div className="flex items-center mb-4">
<Checkbox
id="remember_permission"
name="remember_permission"
Expand All @@ -118,12 +120,12 @@ function ConfirmSignMessage() {
{tCommon("actions.remember")}
</label>
</div>
<ConfirmOrCancel
disabled={loading}
loading={loading}
onCancel={reject}
/>
</div>
<ConfirmOrCancel
disabled={loading}
loading={loading}
onCancel={reject}
/>
</Container>
</form>
) : (
Expand Down
24 changes: 11 additions & 13 deletions src/app/screens/Receive/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ function Receive() {
function renderInvoice() {
if (!invoice) return null;
return (
<div className="py-4">
<>
<div className="relative p-8 bg-white rounded-lg shadow-sm ring-1 ring-black ring-opacity-5 flex justify-center items-center overflow-hidden">
<QRCode value={invoice.paymentRequest.toUpperCase()} level="M" />
{paid && (
Expand Down Expand Up @@ -241,7 +241,7 @@ function Receive() {
style={{ pointerEvents: "none" }}
/>
)}
</div>
</>
);
}

Expand All @@ -265,7 +265,7 @@ function Receive() {
<form onSubmit={handleSubmit}>
<fieldset disabled={loadingInvoice}>
<Container justifyBetween maxWidth="sm">
<div className="py-4">
<div>
<div className="mb-4">
<DualCurrencyField
id="amount"
Expand All @@ -287,16 +287,14 @@ function Receive() {
/>
</div>
</div>
<div>
<Button
type="submit"
label={t("actions.create_invoice")}
fullWidth
primary
loading={loadingInvoice}
disabled={loadingInvoice}
/>
</div>
<Button
type="submit"
label={t("actions.create_invoice")}
fullWidth
primary
loading={loadingInvoice}
disabled={loadingInvoice}
/>
</Container>
</fieldset>
</form>
Expand Down
20 changes: 18 additions & 2 deletions src/app/screens/Send/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import { useTranslation } from "react-i18next";
import { useLocation, useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import QrcodeAdornment from "~/app/components/QrcodeAdornment";
import { extractLightningTagData } from "~/app/utils";
import { useAccount } from "~/app/context/AccountContext";
import {
extractLightningTagData,
isAlbyOAuthAccount,
isBitcoinAddress,
} from "~/app/utils";
import lnurlLib from "~/common/lib/lnurl";
import { isLNURLDetailsError } from "~/common/utils/typeHelpers";

Expand All @@ -22,6 +27,10 @@ function Send() {
const [invoice, setInvoice] = useState(location.state?.decodedQR || "");
const navigate = useNavigate();
const [loading, setLoading] = useState(false);
const auth = useAccount();
const hint = !isAlbyOAuthAccount(auth.account?.connectorType)
? t("input.hint")
: t("input.hint_with_bitcoin_address");

function isPubKey(str: string) {
return str.length == 66 && (str.startsWith("02") || str.startsWith("03"));
Expand Down Expand Up @@ -91,6 +100,13 @@ function Send() {
},
},
});
} else if (
isAlbyOAuthAccount(auth.account?.connectorType) &&
isBitcoinAddress(invoice)
) {
navigate("/sendToBitcoinAddress", {
state: { args: { bitcoinAddress: invoice } },
});
} else {
lightningPayReq.decode(invoice); // throws if invalid.
navigate("/confirmPayment", {
Expand Down Expand Up @@ -127,7 +143,7 @@ function Send() {
<TextField
id="invoice"
label={t("input.label")}
hint={t("input.hint")}
hint={hint}
value={invoice}
disabled={loading}
autoFocus
Expand Down
Loading

0 comments on commit 42e38ea

Please sign in to comment.