Skip to content

Commit

Permalink
refactor: split up refund page
Browse files Browse the repository at this point in the history
  • Loading branch information
jackstar12 committed Jan 7, 2025
1 parent c76bd47 commit 135b5ca
Show file tree
Hide file tree
Showing 12 changed files with 332 additions and 209 deletions.
1 change: 1 addition & 0 deletions e2e/refund/refundFile.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ test.describe("Refund files", () => {
await page.goto("/");

await page.getByRole("link", { name: "Refund" }).click();
await page.getByRole("button", { name: "Refund external swap" }).click();
await page.getByTestId("refundUpload").click();

await page
Expand Down
7 changes: 3 additions & 4 deletions src/components/RefundButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,9 @@ const RefundButton = (props: {
currentSwap.refundTx = res.refundTx;
await setSwapStorage(currentSwap);
setSwap(currentSwap);
} else {
if (props.setRefundTxId) {
props.setRefundTxId(res.refundTx);
}
}
if (props.setRefundTxId) {
props.setRefundTxId(res.refundTx);
}
} catch (error) {
log.warn("refund failed", error);
Expand Down
3 changes: 2 additions & 1 deletion src/components/SwapList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { SwapIcons } from "./SwapIcons";

const SwapList = (props: {
swapsSignal: Accessor<SomeSwap[]>;
action: string;
onDelete?: () => Promise<unknown>;
}) => {
const navigate = useNavigate();
Expand Down Expand Up @@ -51,7 +52,7 @@ const SwapList = (props: {
class="swaplist-item"
onClick={() => navigate(`/swap/${swap.id}`)}>
<a class="btn-small hidden-mobile" href="#">
{t("view")}
{props.action}
</a>
<SwapIcons swap={swap} />
<span class="swaplist-asset-id">
Expand Down
11 changes: 11 additions & 0 deletions src/i18n/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ const dict = {
refund_past_swaps: "Past swaps",
refund_past_swaps_subline:
"Swaps that got saved into your browsers storage",
no_refundable_swaps:
"No refundable swaps found in your browser history",
cant_find_swap: "Can't find your swap?",
refund_external_explainer:
"Try refunding an external swap via refund file and other emergency methods",
refund_external_explainer_rsk:
"Connect your Rootstock Wallet to scan for refundable swaps that are not saved in this browser’s swap history.",
connected_wallet_no_swaps:
"The connected Rootstock Wallet does NOT contain any refundable swaps.",
rsk_log_endpoint_not_available: "Log endpoint not available",
refund_external_swap: "Refund External Swap",
history_no_swaps: "Looks like you didn't do any swaps yet.",
refund_address_header:
"Enter address of your {{ asset }} wallet to refund",
Expand Down
3 changes: 3 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import NotFound from "./pages/NotFound";
import Pay from "./pages/Pay";
import Refund from "./pages/Refund";
import RefundEvm from "./pages/RefundEvm";
import RefundExternal from "./pages/RefundExternal";
import RefundStep from "./pages/RefundStep";
import "./style/index.scss";
import "./utils/patches";
Expand Down Expand Up @@ -105,6 +106,8 @@ const cleanup = render(
<Route path="/swap/refund/:id" component={RefundStep} />
<Route path="/error" component={() => <Error />} />
<Route path="/refund" component={Refund} />
<Route path="/refund/external" component={RefundExternal} />
<Route path="/refund/external/:type" component={RefundExternal} />
<Route path="/history" component={History} />
<Route path="*404" component={NotFound} />
</Router>
Expand Down
1 change: 1 addition & 0 deletions src/pages/History.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ const History = () => {
onDelete={async () => {
setSwaps(await getSwaps());
}}
action={t("view")}
/>
<Show when={swaps().length > 0}>
<Show when={!isIos()}>
Expand Down
222 changes: 20 additions & 202 deletions src/pages/Refund.tsx
Original file line number Diff line number Diff line change
@@ -1,158 +1,26 @@
import { useNavigate } from "@solidjs/router";
import log from "loglevel";
import QrScanner from "qr-scanner";
import { Show, createEffect, createSignal, onCleanup, onMount } from "solid-js";
import { Show, createSignal, onMount } from "solid-js";

import BlockExplorer from "../components/BlockExplorer";
import ConnectWallet from "../components/ConnectWallet";
import RefundButton from "../components/RefundButton";
import SwapList from "../components/SwapList";
import SwapListLogs from "../components/SwapListLogs";
import SettingsCog from "../components/settings/SettingsCog";
import SettingsMenu from "../components/settings/SettingsMenu";
import { RBTC } from "../consts/Assets";
import { SwapType } from "../consts/Enums";
import { swapStatusFailed, swapStatusSuccess } from "../consts/SwapStatus";
import { useGlobalContext } from "../context/Global";
import { useWeb3Signer } from "../context/Web3";
import "../style/tabs.scss";
import { getLockupTransaction, getSwapStatus } from "../utils/boltzClient";
import {
LogRefundData,
scanLogsForPossibleRefunds,
} from "../utils/contractLogs";
import { validateRefundFile } from "../utils/refundFile";
import { SomeSwap } from "../utils/swapCreator";
import ErrorWasm from "./ErrorWasm";

enum RefundError {
InvalidData,
}

const Refund = () => {
const navigate = useNavigate();
const { getSwap, getSwaps, updateSwapStatus, wasmSupported, t } =
useGlobalContext();
const { signer, providers, getEtherSwap } = useWeb3Signer();

const [swapFound, setSwapFound] = createSignal(null);
const [refundInvalid, setRefundInvalid] = createSignal<
RefundError | undefined
>(undefined);
const [refundJson, setRefundJson] = createSignal(null);
const [refundTxId, setRefundTxId] = createSignal<string>("");

const checkRefundJsonKeys = async (
input: HTMLInputElement,
json: Record<string, string | object | number>,
) => {
log.debug("checking refund json", json);

try {
const data = validateRefundFile(json);

// When the swap id is found in the local storage, show a redirect to it
const localStorageSwap = await getSwap(data.id);
if (localStorageSwap !== null) {
setSwapFound(data.id);
return;
}

setRefundJson(data);
setRefundInvalid(undefined);
} catch (e) {
log.warn("Refund json validation failed", e);
setRefundInvalid(RefundError.InvalidData);
input.setCustomValidity(t("invalid_refund_file"));
}
};

const uploadChange = async (e: Event) => {
const input = e.currentTarget as HTMLInputElement;
const inputFile = input.files[0];
input.setCustomValidity("");
setRefundJson(null);
setSwapFound(null);
setRefundInvalid(undefined);

if (["image/png", "image/jpg", "image/jpeg"].includes(inputFile.type)) {
try {
const res = await QrScanner.scanImage(inputFile, {
returnDetailedScanResult: true,
});
await checkRefundJsonKeys(input, JSON.parse(res.data));
} catch (e) {
log.error("invalid QR code upload", e);
setRefundInvalid(RefundError.InvalidData);
input.setCustomValidity(t("invalid_refund_file"));
}
} else {
try {
const data = await inputFile.text();
await checkRefundJsonKeys(input, JSON.parse(data));
} catch (e) {
log.error("invalid file upload", e);
setRefundInvalid(RefundError.InvalidData);
input.setCustomValidity(t("invalid_refund_file"));
}
}
};
const { getSwaps, updateSwapStatus, wasmSupported, t } = useGlobalContext();

const refundSwapsSanityFilter = (swap: SomeSwap) =>
swap.type !== SwapType.Reverse && swap.refundTx === undefined;

const [refundableSwaps, setRefundableSwaps] = createSignal<SomeSwap[]>([]);
const [logRefundableSwaps, setLogRefundableSwaps] = createSignal<
LogRefundData[]
>([]);
const [refundScanProgress, setRefundScanProgress] = createSignal<
string | undefined
>(undefined);

let refundScanAbort: AbortController | undefined = undefined;

onCleanup(() => {
if (refundScanAbort) {
refundScanAbort.abort();
}
});

// eslint-disable-next-line solid/reactivity
createEffect(async () => {
setLogRefundableSwaps([]);

if (refundScanAbort !== undefined) {
refundScanAbort.abort("signer changed");
}

if (signer() === undefined) {
return;
}

setRefundScanProgress(
t("logs_scan_progress", {
value: Number(0).toFixed(2),
}),
);

refundScanAbort = new AbortController();

const generator = scanLogsForPossibleRefunds(
refundScanAbort.signal,
signer(),
getEtherSwap(),
);

for await (const value of generator) {
setRefundScanProgress(
t("logs_scan_progress", {
value: (value.progress * 100).toFixed(2),
}),
);
setLogRefundableSwaps(logRefundableSwaps().concat(value.events));
}

setRefundScanProgress(undefined);
});

onMount(async () => {
const addToRefundableSwaps = (swap: SomeSwap) => {
Expand Down Expand Up @@ -204,80 +72,30 @@ const Refund = () => {
<Show when={wasmSupported()} fallback={<ErrorWasm />}>
<div id="refund">
<div class="frame" data-testid="refundFrame">
<SettingsCog />
<header>
<SettingsCog />
<h2>{t("refund_a_swap")}</h2>
</header>
<Show
when={refundJson() !== null}
when={refundableSwaps().length > 0}
fallback={
<>
<h2>{t("refund_a_swap")}</h2>
<p>{t("refund_a_swap_subline")}</p>
<p>{t("no_refundable_swaps")}</p>
<hr />
</>
}>
<h2>{t("refund_swap", { id: refundJson().id })}</h2>
</Show>

<Show when={logRefundableSwaps().length > 0}>
<SwapListLogs swaps={logRefundableSwaps} />
</Show>
<Show when={refundableSwaps().length > 0}>
<SwapList swapsSignal={refundableSwaps} />
</Show>
<input
required
type="file"
id="refundUpload"
data-testid="refundUpload"
accept="application/json,image/png,imagine/jpg,image/jpeg"
onChange={(e) => uploadChange(e)}
/>
<Show
when={
import.meta.env.VITE_RSK_LOG_SCAN_ENDPOINT !==
undefined &&
Object.keys(providers()).length > 0 &&
(refundJson() === null ||
refundJson().assetSend === RBTC)
}>
<hr />
<ConnectWallet addressOverride={refundScanProgress} />
</Show>
<Show when={swapFound() !== null}>
<hr />
<p>{t("swap_in_history")}</p>
<button
class="btn btn-success"
onClick={() => navigate(`/swap/${swapFound()}`)}>
{t("open_swap")}
</button>
</Show>
<Show when={refundInvalid() !== undefined}>
<hr />
<button class="btn" disabled={true}>
{(() => {
switch (refundInvalid()) {
case RefundError.InvalidData:
return t("invalid_refund_file");
}
})()}
</button>
</Show>
<Show when={refundTxId() === "" && refundJson() !== null}>
<hr />
<RefundButton
swap={refundJson}
setRefundTxId={setRefundTxId}
/>
</Show>
<Show when={refundTxId() !== ""}>
<hr />
<p>{t("refunded")}</p>
<hr />
<BlockExplorer
typeLabel={"refund_tx"}
asset={refundJson().asset || refundJson().assetSend}
txId={refundTxId()}
<SwapList
swapsSignal={refundableSwaps}
action={t("refund")}
/>
</Show>
<h4>{t("cant_find_swap")}</h4>
<p>{t("refund_external_explainer")}</p>
<button
class="btn"
onClick={() => navigate(`/refund/external`)}>
{t("refund_external_swap")}
</button>
<SettingsMenu />
</div>
</div>
Expand Down
Loading

0 comments on commit 135b5ca

Please sign in to comment.