From 0294b94c3079d21be8a91e6b78a6bd38511a3251 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?dni=20=E2=9A=A1?=
Date: Mon, 15 Jul 2024 10:24:59 +0200
Subject: [PATCH 1/9] refactor: simplify blockexplorer link
working on integration a blockexplorer setting i found it very difficult
to understand the BlockExplorerLink component, i would suggest of
removing the general one on the `Pay` page and put it explicitly into
each relevant swap status page. this removed the needs of the
`BlockExplorerLink` component
it can be tested for each status page
---
src/components/BlockExplorerLink.tsx | 89 ------------
src/consts/Types.ts | 5 +
src/context/Global.tsx | 8 --
src/context/Pay.tsx | 6 +-
src/pages/Pay.tsx | 34 -----
src/status/SwapExpired.tsx | 14 +-
tests/components/BlockExplorerLink.spec.tsx | 151 --------------------
7 files changed, 17 insertions(+), 290 deletions(-)
delete mode 100644 src/components/BlockExplorerLink.tsx
delete mode 100644 tests/components/BlockExplorerLink.spec.tsx
diff --git a/src/components/BlockExplorerLink.tsx b/src/components/BlockExplorerLink.tsx
deleted file mode 100644
index 132e08b4..00000000
--- a/src/components/BlockExplorerLink.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import { Accessor, Show, createEffect, createSignal } from "solid-js";
-
-import { SwapType } from "../consts/Enums";
-import {
- ChainSwap,
- ReverseSwap,
- SomeSwap,
- SubmarineSwap,
- getRelevantAssetForSwap,
-} from "../utils/swapCreator";
-import BlockExplorer from "./BlockExplorer";
-
-enum TransactionType {
- Lockup = "lockupTx",
- Claim = "claimTx",
-}
-
-const BlockExplorerLink = ({
- swap,
- swapStatus,
- contractTransaction,
- contractTransactionType,
-}: {
- swap: Accessor;
- swapStatus: Accessor;
- contractTransaction: Accessor;
- contractTransactionType: Accessor;
-}) => {
- // Refund transactions are handled in SwapRefunded
-
- if (swap().type !== SwapType.Chain) {
- return (
- <>
-
-
-
-
-
-
- >
- );
- }
-
- // TODO: RSK
-
- const [hasBeenClaimed, setHasBeenClaimed] = createSignal(false);
-
- createEffect(() => {
- setHasBeenClaimed(swap().claimTx !== undefined);
- });
-
- return (
-
- );
-};
-
-export default BlockExplorerLink;
-export { TransactionType };
diff --git a/src/consts/Types.ts b/src/consts/Types.ts
index bcbd86dd..d3ba064b 100644
--- a/src/consts/Types.ts
+++ b/src/consts/Types.ts
@@ -2,3 +2,8 @@ export type ButtonLabelParams = {
key: string;
params?: Record;
};
+
+export type SwapStatusTransaction = {
+ hex?: string;
+ id?: string;
+};
diff --git a/src/context/Global.tsx b/src/context/Global.tsx
index c30308f9..e520b194 100644
--- a/src/context/Global.tsx
+++ b/src/context/Global.tsx
@@ -37,8 +37,6 @@ export type GlobalContextType = {
setWasmSupported: Setter;
refundAddress: Accessor;
setRefundAddress: Setter;
- transactionToRefund: Accessor;
- setTransactionToRefund: Setter;
i18n: Accessor;
setI18n: Setter;
notification: Accessor;
@@ -107,10 +105,6 @@ const GlobalProvider = (props: { children: any }) => {
const [wasmSupported, setWasmSupported] = createSignal(true);
const [refundAddress, setRefundAddress] = createSignal(null);
- const [transactionToRefund, setTransactionToRefund] = createSignal<
- string | null
- >(null);
-
const [i18n, setI18n] = createSignal(null);
const [notification, setNotification] = createSignal("");
@@ -326,8 +320,6 @@ const GlobalProvider = (props: { children: any }) => {
setWasmSupported,
refundAddress,
setRefundAddress,
- transactionToRefund,
- setTransactionToRefund,
i18n,
setI18n,
notification,
diff --git a/src/context/Pay.tsx b/src/context/Pay.tsx
index 662506d5..03d99e70 100644
--- a/src/context/Pay.tsx
+++ b/src/context/Pay.tsx
@@ -6,6 +6,7 @@ import {
useContext,
} from "solid-js";
+import { SwapStatusTransaction } from "../consts/Types";
import { SomeSwap } from "../utils/swapCreator";
export type PayContextType = {
@@ -21,11 +22,6 @@ export type PayContextType = {
const PayContext = createContext();
-type SwapStatusTransaction = {
- hex?: string;
- id?: string;
-};
-
const PayProvider = (props: { children: any }) => {
const [failureReason, setFailureReason] = createSignal("");
const [swap, setSwap] = createSignal(null, {
diff --git a/src/pages/Pay.tsx b/src/pages/Pay.tsx
index e5c1bdaa..01edfb03 100644
--- a/src/pages/Pay.tsx
+++ b/src/pages/Pay.tsx
@@ -5,18 +5,13 @@ import {
Show,
Switch,
createEffect,
- createSignal,
onCleanup,
} from "solid-js";
-import BlockExplorerLink, {
- TransactionType,
-} from "../components/BlockExplorerLink";
import LoadingSpinner from "../components/LoadingSpinner";
import { SwapIcons } from "../components/SwapIcons";
import SettingsCog from "../components/settings/SettingsCog";
import SettingsMenu from "../components/settings/SettingsMenu";
-import { RBTC } from "../consts/Assets";
import { SwapType } from "../consts/Enums";
import {
swapStatusFailed,
@@ -42,11 +37,6 @@ import { getRelevantAssetForSwap } from "../utils/swapCreator";
const Pay = () => {
const params = useParams();
- const [contractTransaction, setContractTransaction] =
- createSignal(undefined);
- const [contractTransactionType, setContractTransactionType] = createSignal(
- TransactionType.Lockup,
- );
const { getSwap, t } = useGlobalContext();
const {
@@ -68,24 +58,6 @@ const Pay = () => {
setSwapStatus(res.status);
setSwapStatusTransaction(res.transaction);
setFailureReason(res.failureReason);
-
- // RSK
- if (
- asset === RBTC &&
- res.transaction &&
- currentSwap.claimTx === undefined
- ) {
- setContractTransaction(res.transaction.id);
- }
-
- if (asset === RBTC && currentSwap["lockupTx"]) {
- setContractTransaction(currentSwap["lockupTx"]);
- }
-
- if (asset === RBTC && currentSwap.claimTx) {
- setContractTransaction(currentSwap.claimTx);
- setContractTransactionType(TransactionType.Claim);
- }
}
});
@@ -208,12 +180,6 @@ const Pay = () => {
-
diff --git a/src/status/SwapExpired.tsx b/src/status/SwapExpired.tsx
index c1448e3d..3291d2a0 100644
--- a/src/status/SwapExpired.tsx
+++ b/src/status/SwapExpired.tsx
@@ -1,7 +1,9 @@
import { useNavigate } from "@solidjs/router";
import log from "loglevel";
-import { Accessor, Show, createEffect } from "solid-js";
+import { Accessor, Show, createEffect, createSignal } from "solid-js";
+//import { SwapType } from "../consts/Enums";
+import BlockExplorer from "../components/BlockExplorer";
import RefundButton from "../components/RefundButton";
import { useGlobalContext } from "../context/Global";
import { usePayContext } from "../context/Pay";
@@ -11,8 +13,10 @@ import { ChainSwap, SubmarineSwap } from "../utils/swapCreator";
const SwapExpired = () => {
const navigate = useNavigate();
const { failureReason, swap } = usePayContext();
- const { t, setTransactionToRefund, transactionToRefund } =
- useGlobalContext();
+ const { t } = useGlobalContext();
+
+ const [transactionToRefund, setTransactionToRefund] =
+ createSignal("");
createEffect(async () => {
setTransactionToRefund(null);
@@ -40,6 +44,10 @@ const SwapExpired = () => {
swap={swap as Accessor}
/>
+
- }
- />
+
navigate("/swap")}>
diff --git a/src/status/TransactionMempool.tsx b/src/status/TransactionMempool.tsx
index 3188cd90..8543377a 100644
--- a/src/status/TransactionMempool.tsx
+++ b/src/status/TransactionMempool.tsx
@@ -15,8 +15,8 @@ const TransactionMempool = () => {
diff --git a/src/utils/boltzClient.ts b/src/utils/boltzClient.ts
index 0f946f8b..addb64f9 100644
--- a/src/utils/boltzClient.ts
+++ b/src/utils/boltzClient.ts
@@ -63,17 +63,11 @@ type ChainPairTypeTaproot = PairType & {
};
};
-type SubmarinePairsTaproot = Record<
- string,
- Record
->;
+type SubmarinePairsTaproot = Record;
-type ReversePairsTaproot = Record<
- string,
- Record
->;
+type ReversePairsTaproot = Record;
-type ChainPairsTaproot = Record>;
+type ChainPairsTaproot = Record;
type Pairs = {
[SwapType.Submarine]: SubmarinePairsTaproot;
@@ -90,7 +84,7 @@ type Contracts = {
network: {
chainId: number;
};
- tokens: Record;
+ tokens: Record;
swapContracts: {
EtherSwap: string;
ERC20Swap: string;
@@ -168,7 +162,7 @@ type ChainSwapTransaction = {
type TransactionInterface = Transaction | LiquidTransaction;
-export const getPairs = async (asset: string): Promise => {
+export const getPairs = async (asset: string): Promise => {
const [submarine, reverse, chain] = await Promise.all([
fetcher("/v2/swap/submarine", asset),
fetcher("/v2/swap/reverse", asset),
@@ -196,7 +190,7 @@ export const createSubmarineSwap = (
pairHash: string,
referralId: string,
refundPublicKey?: string,
-): Promise =>
+): Promise =>
fetcher("/v2/swap/submarine", to, {
from,
to,
@@ -215,7 +209,7 @@ export const createReverseSwap = (
referralId: string,
claimPublicKey?: string,
claimAddress?: string,
-): Promise =>
+): Promise =>
fetcher("/v2/swap/reverse", to, {
from,
to,
@@ -237,7 +231,7 @@ export const createChainSwap = (
claimAddress: string | undefined,
pairHash: string,
referralId: string,
-): Promise =>
+): Promise =>
fetcher("/v2/swap/chain", to, {
from,
to,
@@ -257,7 +251,7 @@ export const getPartialRefundSignature = async (
pubNonce: Buffer,
transaction: TransactionInterface,
index: number,
-): Promise => {
+): Promise => {
checkCooperative();
const res = await fetcher(
`/v2/swap/${
@@ -283,7 +277,7 @@ export const getPartialReverseClaimSignature = async (
pubNonce: Buffer,
transaction: TransactionInterface,
index: number,
-): Promise => {
+): Promise => {
checkCooperative();
const res = await fetcher(`/v2/swap/reverse/${id}/claim`, asset, {
index,
@@ -332,7 +326,7 @@ export const getEipRefundSignature = (
};
export const getFeeEstimations = (asset: string) =>
- fetcher>("/v2/chain/fees", asset);
+ fetcher("/v2/chain/fees", asset);
export const getNodes = (asset: string) =>
fetcher<{
@@ -355,7 +349,7 @@ export const getNodeStats = (asset: string) =>
}>("/v2/nodes/stats", asset);
export const getContracts = (asset: string) =>
- fetcher>("/v2/chain/contracts", asset);
+ fetcher("/v2/chain/contracts", asset);
export const broadcastTransaction = (asset: string, txHex: string) =>
fetcher<{ id: string }>(`/v2/chain/${asset}/transaction`, asset, {
@@ -373,7 +367,7 @@ export const getLockupTransaction = async (
asset: string,
id: string,
type: SwapType,
-): Promise => {
+): Promise => {
switch (type) {
case SwapType.Submarine:
return fetcher<{
@@ -404,14 +398,16 @@ export const getReverseTransaction = (asset: string, id: string) =>
timeoutBlockHeight: number;
}>(`/v2/swap/reverse/${id}/transaction`, asset);
+export type SwapStatusTransaction = {
+ hex: string;
+ id: string;
+};
+
export type SwapStatus = {
status: string;
failureReason?: string;
zeroConfRejected?: boolean;
- transaction?: {
- id: string;
- hex: string;
- };
+ transaction?: SwapStatusTransaction;
};
export const getSwapStatus = (asset: string, id: string) =>
diff --git a/tests/status/SwapExpired.spec.tsx b/tests/status/SwapExpired.spec.tsx
new file mode 100644
index 00000000..67e96be2
--- /dev/null
+++ b/tests/status/SwapExpired.spec.tsx
@@ -0,0 +1,48 @@
+import { render, screen } from "@solidjs/testing-library";
+
+import { BTC } from "../../src/consts/Assets";
+import i18n from "../../src/i18n/i18n";
+import SwapExpired from "../../src/status/SwapExpired";
+import { TestComponent, contextWrapper, payContext } from "../helper";
+
+jest.mock("../../src/utils/boltzClient", () => {
+ const originalModule = jest.requireActual("../../src/utils/boltzClient");
+
+ return {
+ __esModule: true,
+ ...originalModule,
+ getLockupTransaction: jest.fn(() => {
+ return { id: "txid" };
+ }),
+ };
+});
+
+describe("SwapExpired", () => {
+ test("should show blockexplorer lockup transaction button", async () => {
+ render(
+ () => (
+ <>
+
+
+ >
+ ),
+ {
+ wrapper: contextWrapper,
+ },
+ );
+ payContext.setSwap({
+ assetSend: BTC,
+ id: "swapid",
+ } as any);
+
+ const type_label = i18n.en[`blockexplorer_lockup_tx`];
+ const label = i18n.en.blockexplorer.replace(
+ "{{ typeLabel }}",
+ type_label,
+ );
+
+ const button = await screen.findByText(label);
+ expect(button).not.toBeUndefined();
+ expect(button.getAttribute("href")).toMatch("txid");
+ });
+});
diff --git a/tests/status/TransactionClaimed.spec.tsx b/tests/status/TransactionClaimed.spec.tsx
index 044e54cd..1e3103bb 100644
--- a/tests/status/TransactionClaimed.spec.tsx
+++ b/tests/status/TransactionClaimed.spec.tsx
@@ -1,19 +1,20 @@
import { render, screen } from "@solidjs/testing-library";
import { BTC, LBTC, LN, RBTC } from "../../src/consts/Assets";
+import { SwapType } from "../../src/consts/Enums";
import i18n from "../../src/i18n/i18n";
import TransactionClaimed from "../../src/status/TransactionClaimed";
import { TestComponent, contextWrapper, payContext } from "../helper";
describe("TransactionClaimed", () => {
test.each`
- name | swap
- ${"normal swaps"} | ${{ assetSend: RBTC, assetReceive: LN, address: "address" }}
- ${"reverse swaps to RBTC"} | ${{ assetSend: LN, assetReceive: RBTC, claimTx: "txid" }}
- ${"reverse swaps to BTC with claim transactions"} | ${{ assetSend: LN, assetReceive: LBTC, claimTx: "txid" }}
- ${"reverse swaps to L-BTC with claim transactions"} | ${{ assetSend: LN, assetReceive: BTC, claimTx: "txid" }}
- ${"chain swaps BTC to L-BTC with claim transactions"} | ${{ assetSend: BTC, assetReceive: LBTC, claimTx: "txid" }}
- `("should show success for $name", async ({ swap }) => {
+ name | label | swap
+ ${"normal swaps"} | ${"lockup_address"} | ${{ type: SwapType.Submarine, assetSend: RBTC, assetReceive: LN, address: "bc12" }}
+ ${"reverse swaps to RBTC"} | ${"claim_tx"} | ${{ type: SwapType.Reverse, assetSend: LN, assetReceive: RBTC, claimTx: "txid" }}
+ ${"reverse swaps to BTC with claim transactions"} | ${"claim_tx"} | ${{ type: SwapType.Reverse, assetSend: LN, assetReceive: LBTC, claimTx: "txid" }}
+ ${"reverse swaps to L-BTC with claim transactions"} | ${"claim_tx"} | ${{ type: SwapType.Reverse, assetSend: LN, assetReceive: BTC, claimTx: "txid" }}
+ ${"chain swaps BTC to L-BTC with claim transactions"} | ${"claim_tx"} | ${{ type: SwapType.Chain, assetSend: BTC, assetReceive: LBTC, claimTx: "txid" }}
+ `("should show success for $name", async ({ label, swap }) => {
render(
() => (
<>
@@ -30,5 +31,16 @@ describe("TransactionClaimed", () => {
await expect(
screen.findByText(i18n.en.congrats),
).resolves.not.toBeUndefined();
+
+ const type_label = i18n.en[`blockexplorer_${label}`];
+ const _label = i18n.en.blockexplorer.replace(
+ "{{ typeLabel }}",
+ type_label,
+ );
+ const address_or_tx =
+ swap.type === SwapType.Submarine ? swap.address : swap.claimTx;
+ const button = screen.getByText(_label);
+ expect(button).not.toBeUndefined();
+ expect(button.getAttribute("href")).toMatch(address_or_tx);
});
});
diff --git a/tests/status/TransactionLockupFailed.spec.tsx b/tests/status/TransactionLockupFailed.spec.tsx
index eb1b0406..dfe9ac2d 100644
--- a/tests/status/TransactionLockupFailed.spec.tsx
+++ b/tests/status/TransactionLockupFailed.spec.tsx
@@ -1,7 +1,8 @@
import { render, screen } from "@solidjs/testing-library";
import { OutputType } from "boltz-core";
-import { BTC, RBTC } from "../../src/consts/Assets";
+import { BTC, LBTC, RBTC } from "../../src/consts/Assets";
+import { SwapType } from "../../src/consts/Enums";
import i18n from "../../src/i18n/i18n";
import TransactionLockupFailed from "../../src/status/TransactionLockupFailed";
import { TestComponent, contextWrapper, payContext } from "../helper";
@@ -84,4 +85,36 @@ describe("TransactionLockupFailed", () => {
screen.findByText(i18n.en.refund),
).resolves.not.toBeUndefined();
});
+
+ test.each`
+ swap
+ ${{ assetSend: BTC, type: SwapType.Submarine, address: "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" }}
+ ${{ assetSend: LBTC, type: SwapType.Chain, lockupDetails: { lockupAddress: "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" } }}
+ `("should show blockexplorer lockup address button", async ({ swap }) => {
+ render(
+ () => (
+ <>
+
+
+ >
+ ),
+ {
+ wrapper: contextWrapper,
+ },
+ );
+ const lockup_address =
+ swap.type === SwapType.Submarine
+ ? swap.address
+ : swap.lockupDetails.lockupAddress;
+ payContext.setSwap(swap);
+
+ const type_label = i18n.en.blockexplorer_lockup_address;
+ const label = i18n.en.blockexplorer.replace(
+ "{{ typeLabel }}",
+ type_label,
+ );
+ const button = screen.getByText(label);
+ expect(button).not.toBeUndefined();
+ expect(button.getAttribute("href")).toMatch(lockup_address);
+ });
});
diff --git a/tests/status/TransactionMempool.spec.tsx b/tests/status/TransactionMempool.spec.tsx
new file mode 100644
index 00000000..acf3e372
--- /dev/null
+++ b/tests/status/TransactionMempool.spec.tsx
@@ -0,0 +1,40 @@
+import { render, screen } from "@solidjs/testing-library";
+
+import { BTC } from "../../src/consts/Assets";
+import i18n from "../../src/i18n/i18n";
+import TransactionMempool from "../../src/status/TransactionMempool";
+import { TestComponent, contextWrapper, payContext } from "../helper";
+
+describe("TransactionMempool", () => {
+ test("should show blockexplorer lockup transaction button", async () => {
+ render(
+ () => (
+ <>
+
+
+ >
+ ),
+ {
+ wrapper: contextWrapper,
+ },
+ );
+ payContext.setSwap({
+ assetSend: BTC,
+ } as any);
+
+ payContext.setSwapStatusTransaction({
+ id: "txid",
+ hex: "hex",
+ });
+
+ const type_label = i18n.en[`blockexplorer_lockup_tx`];
+ const label = i18n.en.blockexplorer.replace(
+ "{{ typeLabel }}",
+ type_label,
+ );
+
+ const button = await screen.findByText(label);
+ expect(button).not.toBeUndefined();
+ expect(button.getAttribute("href")).toMatch("txid");
+ });
+});