wip: WithdrawDialog migrated to Tauri IPC

This commit is contained in:
binarybaron 2024-08-09 19:46:58 +02:00
parent 47821cbe79
commit 3d16ff6d5c
No known key found for this signature in database
GPG key ID: 99B75D3E1476A26E
118 changed files with 1779 additions and 1868 deletions

View file

@ -1,17 +1,17 @@
import { Box, Button, makeStyles, Typography } from '@material-ui/core';
import InfoBox from '../../modal/swap/InfoBox';
import { Box, Button, makeStyles, Typography } from "@material-ui/core";
import InfoBox from "../../modal/swap/InfoBox";
const useStyles = makeStyles((theme) => ({
spacedBox: {
display: 'flex',
display: "flex",
gap: theme.spacing(1),
},
}));
const GITHUB_ISSUE_URL =
'https://github.com/UnstoppableSwap/unstoppableswap-gui/issues/new/choose';
const MATRIX_ROOM_URL = 'https://matrix.to/#/#unstoppableswap:matrix.org';
export const DISCORD_URL = 'https://discord.gg/APJ6rJmq';
"https://github.com/UnstoppableSwap/unstoppableswap-gui/issues/new/choose";
const MATRIX_ROOM_URL = "https://matrix.to/#/#unstoppableswap:matrix.org";
export const DISCORD_URL = "https://discord.gg/APJ6rJmq";
export default function ContactInfoBox() {
const classes = useStyles();

View file

@ -1,9 +1,9 @@
import { Typography } from '@material-ui/core';
import DepositAddressInfoBox from '../../modal/swap/DepositAddressInfoBox';
import MoneroIcon from '../../icons/MoneroIcon';
import { Typography } from "@material-ui/core";
import DepositAddressInfoBox from "../../modal/swap/DepositAddressInfoBox";
import MoneroIcon from "../../icons/MoneroIcon";
const XMR_DONATE_ADDRESS =
'87jS4C7ngk9EHdqFFuxGFgg8AyH63dRUoULshWDybFJaP75UA89qsutG5B1L1QTc4w228nsqsv8EjhL7bz8fB3611Mh98mg';
"87jS4C7ngk9EHdqFFuxGFgg8AyH63dRUoULshWDybFJaP75UA89qsutG5B1L1QTc4w228nsqsv8EjhL7bz8fB3611Mh98mg";
export default function DonateInfoBox() {
return (

View file

@ -1,7 +1,7 @@
import { Button, Typography } from '@material-ui/core';
import { useState } from 'react';
import InfoBox from '../../modal/swap/InfoBox';
import FeedbackDialog from '../../modal/feedback/FeedbackDialog';
import { Button, Typography } from "@material-ui/core";
import { useState } from "react";
import InfoBox from "../../modal/swap/InfoBox";
import FeedbackDialog from "../../modal/feedback/FeedbackDialog";
export default function FeedbackInfoBox() {
const [showDialog, setShowDialog] = useState(false);

View file

@ -1,15 +1,15 @@
import { Box, makeStyles } from '@material-ui/core';
import ContactInfoBox from './ContactInfoBox';
import FeedbackInfoBox from './FeedbackInfoBox';
import DonateInfoBox from './DonateInfoBox';
import TorInfoBox from './TorInfoBox';
import RpcControlBox from './RpcControlBox';
import { Box, makeStyles } from "@material-ui/core";
import ContactInfoBox from "./ContactInfoBox";
import FeedbackInfoBox from "./FeedbackInfoBox";
import DonateInfoBox from "./DonateInfoBox";
import TorInfoBox from "./TorInfoBox";
import RpcControlBox from "./RpcControlBox";
const useStyles = makeStyles((theme) => ({
outer: {
display: 'flex',
display: "flex",
gap: theme.spacing(2),
flexDirection: 'column',
flexDirection: "column",
},
}));

View file

@ -1,18 +1,18 @@
import { Box, makeStyles } from '@material-ui/core';
import IpcInvokeButton from 'renderer/components/IpcInvokeButton';
import { useAppSelector } from 'store/hooks';
import StopIcon from '@material-ui/icons/Stop';
import PlayArrowIcon from '@material-ui/icons/PlayArrow';
import { RpcProcessStateType } from 'models/rpcModel';
import InfoBox from '../../modal/swap/InfoBox';
import CliLogsBox from '../../other/RenderedCliLog';
import FolderOpenIcon from '@material-ui/icons/FolderOpen';
import { Box, makeStyles } from "@material-ui/core";
import IpcInvokeButton from "renderer/components/IpcInvokeButton";
import { useAppSelector } from "store/hooks";
import StopIcon from "@material-ui/icons/Stop";
import PlayArrowIcon from "@material-ui/icons/PlayArrow";
import { RpcProcessStateType } from "models/rpcModel";
import InfoBox from "../../modal/swap/InfoBox";
import CliLogsBox from "../../other/RenderedCliLog";
import FolderOpenIcon from "@material-ui/icons/FolderOpen";
const useStyles = makeStyles((theme) => ({
actionsOuter: {
display: 'flex',
display: "flex",
gap: theme.spacing(1),
alignItems: 'center',
alignItems: "center",
},
}));

View file

@ -1,14 +1,14 @@
import { Box, makeStyles, Typography } from '@material-ui/core';
import IpcInvokeButton from 'renderer/components/IpcInvokeButton';
import { useAppSelector } from 'store/hooks';
import StopIcon from '@material-ui/icons/Stop';
import PlayArrowIcon from '@material-ui/icons/PlayArrow';
import InfoBox from '../../modal/swap/InfoBox';
import CliLogsBox from '../../other/RenderedCliLog';
import { Box, makeStyles, Typography } from "@material-ui/core";
import IpcInvokeButton from "renderer/components/IpcInvokeButton";
import { useAppSelector } from "store/hooks";
import StopIcon from "@material-ui/icons/Stop";
import PlayArrowIcon from "@material-ui/icons/PlayArrow";
import InfoBox from "../../modal/swap/InfoBox";
import CliLogsBox from "../../other/RenderedCliLog";
const useStyles = makeStyles((theme) => ({
actionsOuter: {
display: 'flex',
display: "flex",
gap: theme.spacing(1),
},
}));
@ -24,10 +24,10 @@ export default function TorInfoBox() {
mainContent={
<Box
style={{
width: '100%',
display: 'flex',
flexDirection: 'column',
gap: '8px',
width: "100%",
display: "flex",
flexDirection: "column",
gap: "8px",
}}
>
<Typography variant="subtitle2">
@ -37,7 +37,7 @@ export default function TorInfoBox() {
below. If Tor is running, all traffic will be routed through it and
the swap provider will not be able to see your IP address.
</Typography>
<CliLogsBox label="Tor Daemon Logs" logs={torStdOut.split('\n')} />
<CliLogsBox label="Tor Daemon Logs" logs={torStdOut.split("\n")} />
</Box>
}
additionalContent={

View file

@ -1,8 +1,8 @@
import { Typography } from '@material-ui/core';
import { useIsSwapRunning } from 'store/hooks';
import HistoryTable from './table/HistoryTable';
import SwapDialog from '../../modal/swap/SwapDialog';
import SwapTxLockAlertsBox from '../../alert/SwapTxLockAlertsBox';
import { Typography } from "@material-ui/core";
import { useIsSwapRunning } from "store/hooks";
import HistoryTable from "./table/HistoryTable";
import SwapDialog from "../../modal/swap/SwapDialog";
import SwapTxLockAlertsBox from "../../alert/SwapTxLockAlertsBox";
export default function HistoryPage() {
const showDialog = useIsSwapRunning();

View file

@ -1,98 +1,86 @@
import {
Box,
Collapse,
IconButton,
makeStyles,
TableCell,
TableRow,
Box,
Collapse,
IconButton,
makeStyles,
TableCell,
TableRow,
} from "@material-ui/core";
import { useState } from "react";
import ArrowForwardIcon from "@material-ui/icons/ArrowForward";
import KeyboardArrowDownIcon from "@material-ui/icons/KeyboardArrowDown";
import KeyboardArrowUpIcon from "@material-ui/icons/KeyboardArrowUp";
import {
getHumanReadableDbStateType,
getSwapBtcAmount,
getSwapXmrAmount,
GetSwapInfoResponse,
getHumanReadableDbStateType,
getSwapBtcAmount,
getSwapXmrAmount,
GetSwapInfoResponse,
} from "../../../../../models/rpcModel";
import HistoryRowActions from "./HistoryRowActions";
import HistoryRowExpanded from "./HistoryRowExpanded";
import { BitcoinAmount, MoneroAmount } from "../../../other/Units";
type HistoryRowProps = {
swap: GetSwapInfoResponse;
swap: GetSwapInfoResponse;
};
const useStyles = makeStyles((theme) => ({
amountTransferContainer: {
display: "flex",
alignItems: "center",
gap: theme.spacing(1),
},
amountTransferContainer: {
display: "flex",
alignItems: "center",
gap: theme.spacing(1),
},
}));
function AmountTransfer({
btcAmount,
xmrAmount,
btcAmount,
xmrAmount,
}: {
xmrAmount: number;
btcAmount: number;
xmrAmount: number;
btcAmount: number;
}) {
const classes = useStyles();
const classes = useStyles();
return (
<Box className={classes.amountTransferContainer}>
<BitcoinAmount amount={btcAmount} />
<ArrowForwardIcon />
<MoneroAmount amount={xmrAmount} />
</Box>
);
return (
<Box className={classes.amountTransferContainer}>
<BitcoinAmount amount={btcAmount} />
<ArrowForwardIcon />
<MoneroAmount amount={xmrAmount} />
</Box>
);
}
export default function HistoryRow({ swap }: HistoryRowProps) {
const btcAmount = getSwapBtcAmount(swap);
const xmrAmount = getSwapXmrAmount(swap);
const btcAmount = getSwapBtcAmount(swap);
const xmrAmount = getSwapXmrAmount(swap);
const [expanded, setExpanded] = useState(false);
const [expanded, setExpanded] = useState(false);
return (
<>
<TableRow>
<TableCell>
<IconButton
size="small"
onClick={() => setExpanded(!expanded)}
>
{expanded ? (
<KeyboardArrowUpIcon />
) : (
<KeyboardArrowDownIcon />
)}
</IconButton>
</TableCell>
<TableCell>{swap.swap_id.substring(0, 5)}...</TableCell>
<TableCell>
<AmountTransfer
xmrAmount={xmrAmount}
btcAmount={btcAmount}
/>
</TableCell>
<TableCell>
{getHumanReadableDbStateType(swap.state_name)}
</TableCell>
<TableCell>
<HistoryRowActions swap={swap} />
</TableCell>
</TableRow>
return (
<>
<TableRow>
<TableCell>
<IconButton size="small" onClick={() => setExpanded(!expanded)}>
{expanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
</IconButton>
</TableCell>
<TableCell>{swap.swap_id.substring(0, 5)}...</TableCell>
<TableCell>
<AmountTransfer xmrAmount={xmrAmount} btcAmount={btcAmount} />
</TableCell>
<TableCell>{getHumanReadableDbStateType(swap.state_name)}</TableCell>
<TableCell>
<HistoryRowActions swap={swap} />
</TableCell>
</TableRow>
<TableRow>
<TableCell style={{ padding: 0 }} colSpan={6}>
<Collapse in={expanded} timeout="auto">
{expanded && <HistoryRowExpanded swap={swap} />}
</Collapse>
</TableCell>
</TableRow>
</>
);
<TableRow>
<TableCell style={{ padding: 0 }} colSpan={6}>
<Collapse in={expanded} timeout="auto">
{expanded && <HistoryRowExpanded swap={swap} />}
</Collapse>
</TableCell>
</TableRow>
</>
);
}

View file

@ -6,85 +6,85 @@ import { green, red } from "@material-ui/core/colors";
import PlayArrowIcon from "@material-ui/icons/PlayArrow";
import IpcInvokeButton from "../../../IpcInvokeButton";
import {
GetSwapInfoResponse,
SwapStateName,
isSwapStateNamePossiblyCancellableSwap,
isSwapStateNamePossiblyRefundableSwap,
GetSwapInfoResponse,
SwapStateName,
isSwapStateNamePossiblyCancellableSwap,
isSwapStateNamePossiblyRefundableSwap,
} from "../../../../../models/rpcModel";
export function SwapResumeButton({
swap,
...props
swap,
...props
}: { swap: GetSwapInfoResponse } & ButtonProps) {
return (
<IpcInvokeButton
variant="contained"
color="primary"
disabled={swap.completed}
ipcChannel="spawn-resume-swap"
ipcArgs={[swap.swap_id]}
endIcon={<PlayArrowIcon />}
requiresRpc
{...props}
>
Resume
</IpcInvokeButton>
);
return (
<IpcInvokeButton
variant="contained"
color="primary"
disabled={swap.completed}
ipcChannel="spawn-resume-swap"
ipcArgs={[swap.swap_id]}
endIcon={<PlayArrowIcon />}
requiresRpc
{...props}
>
Resume
</IpcInvokeButton>
);
}
export function SwapCancelRefundButton({
swap,
...props
swap,
...props
}: { swap: GetSwapInfoResponse } & ButtonProps) {
const cancelOrRefundable =
isSwapStateNamePossiblyCancellableSwap(swap.state_name) ||
isSwapStateNamePossiblyRefundableSwap(swap.state_name);
const cancelOrRefundable =
isSwapStateNamePossiblyCancellableSwap(swap.state_name) ||
isSwapStateNamePossiblyRefundableSwap(swap.state_name);
if (!cancelOrRefundable) {
return <></>;
}
if (!cancelOrRefundable) {
return <></>;
}
return (
<IpcInvokeButton
ipcChannel="spawn-cancel-refund"
ipcArgs={[swap.swap_id]}
requiresRpc
displayErrorSnackbar={false}
{...props}
>
Attempt manual Cancel & Refund
</IpcInvokeButton>
);
return (
<IpcInvokeButton
ipcChannel="spawn-cancel-refund"
ipcArgs={[swap.swap_id]}
requiresRpc
displayErrorSnackbar={false}
{...props}
>
Attempt manual Cancel & Refund
</IpcInvokeButton>
);
}
export default function HistoryRowActions({
swap,
swap,
}: {
swap: GetSwapInfoResponse;
swap: GetSwapInfoResponse;
}) {
if (swap.state_name === SwapStateName.XmrRedeemed) {
return (
<Tooltip title="The swap is completed because you have redeemed the XMR">
<DoneIcon style={{ color: green[500] }} />
</Tooltip>
);
}
if (swap.state_name === SwapStateName.XmrRedeemed) {
return (
<Tooltip title="The swap is completed because you have redeemed the XMR">
<DoneIcon style={{ color: green[500] }} />
</Tooltip>
);
}
if (swap.state_name === SwapStateName.BtcRefunded) {
return (
<Tooltip title="The swap is completed because your BTC have been refunded">
<DoneIcon style={{ color: green[500] }} />
</Tooltip>
);
}
if (swap.state_name === SwapStateName.BtcRefunded) {
return (
<Tooltip title="The swap is completed because your BTC have been refunded">
<DoneIcon style={{ color: green[500] }} />
</Tooltip>
);
}
if (swap.state_name === SwapStateName.BtcPunished) {
return (
<Tooltip title="The swap is completed because you have been punished">
<ErrorIcon style={{ color: red[500] }} />
</Tooltip>
);
}
if (swap.state_name === SwapStateName.BtcPunished) {
return (
<Tooltip title="The swap is completed because you have been punished">
<ErrorIcon style={{ color: red[500] }} />
</Tooltip>
);
}
return <SwapResumeButton swap={swap} />;
return <SwapResumeButton swap={swap} />;
}

View file

@ -1,143 +1,134 @@
import {
Box,
Link,
makeStyles,
Table,
TableBody,
TableCell,
TableContainer,
TableRow,
Box,
Link,
makeStyles,
Table,
TableBody,
TableCell,
TableContainer,
TableRow,
} from "@material-ui/core";
import { getBitcoinTxExplorerUrl } from "utils/conversionUtils";
import { isTestnet } from "store/config";
import {
getHumanReadableDbStateType,
getSwapBtcAmount,
getSwapExchangeRate,
getSwapTxFees,
getSwapXmrAmount,
GetSwapInfoResponse,
getHumanReadableDbStateType,
getSwapBtcAmount,
getSwapExchangeRate,
getSwapTxFees,
getSwapXmrAmount,
GetSwapInfoResponse,
} from "../../../../../models/rpcModel";
import SwapLogFileOpenButton from "./SwapLogFileOpenButton";
import { SwapCancelRefundButton } from "./HistoryRowActions";
import { SwapMoneroRecoveryButton } from "./SwapMoneroRecoveryButton";
import {
BitcoinAmount,
MoneroAmount,
MoneroBitcoinExchangeRate,
BitcoinAmount,
MoneroAmount,
MoneroBitcoinExchangeRate,
} from "renderer/components/other/Units";
const useStyles = makeStyles((theme) => ({
outer: {
display: "grid",
padding: theme.spacing(1),
gap: theme.spacing(1),
},
actionsOuter: {
display: "flex",
flexDirection: "row",
gap: theme.spacing(1),
},
outer: {
display: "grid",
padding: theme.spacing(1),
gap: theme.spacing(1),
},
actionsOuter: {
display: "flex",
flexDirection: "row",
gap: theme.spacing(1),
},
}));
export default function HistoryRowExpanded({
swap,
swap,
}: {
swap: GetSwapInfoResponse;
swap: GetSwapInfoResponse;
}) {
const classes = useStyles();
const classes = useStyles();
const { seller, start_date: startDate } = swap;
const btcAmount = getSwapBtcAmount(swap);
const xmrAmount = getSwapXmrAmount(swap);
const txFees = getSwapTxFees(swap);
const exchangeRate = getSwapExchangeRate(swap);
const { seller, start_date: startDate } = swap;
const btcAmount = getSwapBtcAmount(swap);
const xmrAmount = getSwapXmrAmount(swap);
const txFees = getSwapTxFees(swap);
const exchangeRate = getSwapExchangeRate(swap);
return (
<Box className={classes.outer}>
<TableContainer>
<Table>
<TableBody>
<TableRow>
<TableCell>Started on</TableCell>
<TableCell>{startDate}</TableCell>
</TableRow>
<TableRow>
<TableCell>Swap ID</TableCell>
<TableCell>{swap.swap_id}</TableCell>
</TableRow>
<TableRow>
<TableCell>State Name</TableCell>
<TableCell>
{getHumanReadableDbStateType(swap.state_name)}
</TableCell>
</TableRow>
<TableRow>
<TableCell>Monero Amount</TableCell>
<TableCell>
<MoneroAmount amount={xmrAmount} />
</TableCell>
</TableRow>
<TableRow>
<TableCell>Bitcoin Amount</TableCell>
<TableCell>
<BitcoinAmount amount={btcAmount} />
</TableCell>
</TableRow>
<TableRow>
<TableCell>Exchange Rate</TableCell>
<TableCell>
<MoneroBitcoinExchangeRate
rate={exchangeRate}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>Bitcoin Network Fees</TableCell>
<TableCell>
<BitcoinAmount amount={txFees} />
</TableCell>
</TableRow>
<TableRow>
<TableCell>Provider Address</TableCell>
<TableCell>
<Box>{seller.addresses.join(", ")}</Box>
</TableCell>
</TableRow>
<TableRow>
<TableCell>Bitcoin lock transaction</TableCell>
<TableCell>
<Link
href={getBitcoinTxExplorerUrl(
swap.tx_lock_id,
isTestnet(),
)}
target="_blank"
>
{swap.tx_lock_id}
</Link>
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
<Box className={classes.actionsOuter}>
<SwapLogFileOpenButton
swapId={swap.swap_id}
variant="outlined"
size="small"
/>
<SwapCancelRefundButton
swap={swap}
variant="contained"
size="small"
/>
<SwapMoneroRecoveryButton
swap={swap}
variant="contained"
size="small"
/>
</Box>
</Box>
);
return (
<Box className={classes.outer}>
<TableContainer>
<Table>
<TableBody>
<TableRow>
<TableCell>Started on</TableCell>
<TableCell>{startDate}</TableCell>
</TableRow>
<TableRow>
<TableCell>Swap ID</TableCell>
<TableCell>{swap.swap_id}</TableCell>
</TableRow>
<TableRow>
<TableCell>State Name</TableCell>
<TableCell>
{getHumanReadableDbStateType(swap.state_name)}
</TableCell>
</TableRow>
<TableRow>
<TableCell>Monero Amount</TableCell>
<TableCell>
<MoneroAmount amount={xmrAmount} />
</TableCell>
</TableRow>
<TableRow>
<TableCell>Bitcoin Amount</TableCell>
<TableCell>
<BitcoinAmount amount={btcAmount} />
</TableCell>
</TableRow>
<TableRow>
<TableCell>Exchange Rate</TableCell>
<TableCell>
<MoneroBitcoinExchangeRate rate={exchangeRate} />
</TableCell>
</TableRow>
<TableRow>
<TableCell>Bitcoin Network Fees</TableCell>
<TableCell>
<BitcoinAmount amount={txFees} />
</TableCell>
</TableRow>
<TableRow>
<TableCell>Provider Address</TableCell>
<TableCell>
<Box>{seller.addresses.join(", ")}</Box>
</TableCell>
</TableRow>
<TableRow>
<TableCell>Bitcoin lock transaction</TableCell>
<TableCell>
<Link
href={getBitcoinTxExplorerUrl(swap.tx_lock_id, isTestnet())}
target="_blank"
>
{swap.tx_lock_id}
</Link>
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
<Box className={classes.actionsOuter}>
<SwapLogFileOpenButton
swapId={swap.swap_id}
variant="outlined"
size="small"
/>
<SwapCancelRefundButton swap={swap} variant="contained" size="small" />
<SwapMoneroRecoveryButton
swap={swap}
variant="contained"
size="small"
/>
</Box>
</Box>
);
}

View file

@ -1,53 +1,53 @@
import {
Box,
makeStyles,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Box,
makeStyles,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
} from "@material-ui/core";
import { sortBy } from "lodash";
import { parseDateString } from "utils/parseUtils";
import {
useAppSelector,
useSwapInfosSortedByDate,
useAppSelector,
useSwapInfosSortedByDate,
} from "../../../../../store/hooks";
import HistoryRow from "./HistoryRow";
const useStyles = makeStyles((theme) => ({
outer: {
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(1),
},
outer: {
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(1),
},
}));
export default function HistoryTable() {
const classes = useStyles();
const swapSortedByDate = useSwapInfosSortedByDate();
const classes = useStyles();
const swapSortedByDate = useSwapInfosSortedByDate();
return (
<Box className={classes.outer}>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell />
<TableCell>ID</TableCell>
<TableCell>Amount</TableCell>
<TableCell>State</TableCell>
<TableCell />
</TableRow>
</TableHead>
<TableBody>
{swapSortedByDate.map((swap) => (
<HistoryRow swap={swap} key={swap.swap_id} />
))}
</TableBody>
</Table>
</TableContainer>
</Box>
);
return (
<Box className={classes.outer}>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell />
<TableCell>ID</TableCell>
<TableCell>Amount</TableCell>
<TableCell>State</TableCell>
<TableCell />
</TableRow>
</TableHead>
<TableBody>
{swapSortedByDate.map((swap) => (
<HistoryRow swap={swap} key={swap.swap_id} />
))}
</TableBody>
</Table>
</TableContainer>
</Box>
);
}

View file

@ -1,15 +1,15 @@
import { ButtonProps } from '@material-ui/core/Button/Button';
import { ButtonProps } from "@material-ui/core/Button/Button";
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
} from '@material-ui/core';
import { useState } from 'react';
import { CliLog } from 'models/cliModel';
import IpcInvokeButton from '../../../IpcInvokeButton';
import CliLogsBox from '../../../other/RenderedCliLog';
} from "@material-ui/core";
import { useState } from "react";
import { CliLog } from "models/cliModel";
import IpcInvokeButton from "../../../IpcInvokeButton";
import CliLogsBox from "../../../other/RenderedCliLog";
export default function SwapLogFileOpenButton({
swapId,

View file

@ -1,120 +1,119 @@
import { ButtonProps } from "@material-ui/core/Button/Button";
import {
Box,
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
Link,
Box,
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
Link,
} from "@material-ui/core";
import { useAppDispatch, useAppSelector } from "store/hooks";
import { rpcResetMoneroRecoveryKeys } from "store/features/rpcSlice";
import {
GetSwapInfoResponse,
isSwapMoneroRecoverable,
GetSwapInfoResponse,
isSwapMoneroRecoverable,
} from "../../../../../models/rpcModel";
import IpcInvokeButton from "../../../IpcInvokeButton";
import DialogHeader from "../../../modal/DialogHeader";
import ScrollablePaperTextBox from "../../../other/ScrollablePaperTextBox";
function MoneroRecoveryKeysDialog({ swap }: { swap: GetSwapInfoResponse }) {
const dispatch = useAppDispatch();
const keys = useAppSelector((s) => s.rpc.state.moneroRecovery);
const dispatch = useAppDispatch();
const keys = useAppSelector((s) => s.rpc.state.moneroRecovery);
function onClose() {
dispatch(rpcResetMoneroRecoveryKeys());
}
function onClose() {
dispatch(rpcResetMoneroRecoveryKeys());
}
if (keys === null || keys.swapId !== swap.swap_id) {
return <></>;
}
if (keys === null || keys.swapId !== swap.swap_id) {
return <></>;
}
return (
<Dialog open onClose={onClose} maxWidth="sm" fullWidth>
<DialogHeader
title={`Recovery Keys for swap ${swap.swap_id.substring(0, 5)}...`}
return (
<Dialog open onClose={onClose} maxWidth="sm" fullWidth>
<DialogHeader
title={`Recovery Keys for swap ${swap.swap_id.substring(0, 5)}...`}
/>
<DialogContent>
<DialogContentText>
You can use the keys below to manually redeem the Monero funds from
the multi-signature wallet.
<ul>
<li>
This is useful if the swap daemon fails to redeem the funds itself
</li>
<li>
If you have come this far, there is no risk of losing funds. You
are the only one with access to these keys and can use them to
access your funds
</li>
<li>
View{" "}
<Link
href="https://www.getmonero.org/resources/user-guides/restore_from_keys.html"
target="_blank"
rel="noreferrer"
>
this guide
</Link>{" "}
for a detailed description on how to import the keys and spend the
funds.
</li>
</ul>
</DialogContentText>
<Box
style={{
display: "flex",
gap: "0.5rem",
flexDirection: "column",
}}
>
{[
["Primary Address", keys.keys.address],
["View Key", keys.keys.view_key],
["Spend Key", keys.keys.spend_key],
["Restore Height", keys.keys.restore_height.toString()],
].map(([title, value]) => (
<ScrollablePaperTextBox
minHeight="2rem"
title={title}
copyValue={value}
rows={[value]}
/>
<DialogContent>
<DialogContentText>
You can use the keys below to manually redeem the Monero
funds from the multi-signature wallet.
<ul>
<li>
This is useful if the swap daemon fails to redeem
the funds itself
</li>
<li>
If you have come this far, there is no risk of
losing funds. You are the only one with access to
these keys and can use them to access your funds
</li>
<li>
View{" "}
<Link
href="https://www.getmonero.org/resources/user-guides/restore_from_keys.html"
target="_blank"
rel="noreferrer"
>
this guide
</Link>{" "}
for a detailed description on how to import the keys
and spend the funds.
</li>
</ul>
</DialogContentText>
<Box
style={{
display: "flex",
gap: "0.5rem",
flexDirection: "column",
}}
>
{[
["Primary Address", keys.keys.address],
["View Key", keys.keys.view_key],
["Spend Key", keys.keys.spend_key],
["Restore Height", keys.keys.restore_height.toString()],
].map(([title, value]) => (
<ScrollablePaperTextBox
minHeight="2rem"
title={title}
copyValue={value}
rows={[value]}
/>
))}
</Box>
</DialogContent>
<DialogActions>
<Button onClick={onClose} color="primary" variant="contained">
Done
</Button>
</DialogActions>
</Dialog>
);
))}
</Box>
</DialogContent>
<DialogActions>
<Button onClick={onClose} color="primary" variant="contained">
Done
</Button>
</DialogActions>
</Dialog>
);
}
export function SwapMoneroRecoveryButton({
swap,
...props
swap,
...props
}: { swap: GetSwapInfoResponse } & ButtonProps) {
const isRecoverable = isSwapMoneroRecoverable(swap.state_name);
const isRecoverable = isSwapMoneroRecoverable(swap.state_name);
if (!isRecoverable) {
return <></>;
}
if (!isRecoverable) {
return <></>;
}
return (
<>
<IpcInvokeButton
ipcChannel="spawn-monero-recovery"
ipcArgs={[swap.swap_id]}
requiresRpc
{...props}
>
Display Monero Recovery Keys
</IpcInvokeButton>
<MoneroRecoveryKeysDialog swap={swap} />
</>
);
return (
<>
<IpcInvokeButton
ipcChannel="spawn-monero-recovery"
ipcArgs={[swap.swap_id]}
requiresRpc
{...props}
>
Display Monero Recovery Keys
</IpcInvokeButton>
<MoneroRecoveryKeysDialog swap={swap} />
</>
);
}

View file

@ -1,7 +1,7 @@
import { Box } from '@material-ui/core';
import { Alert, AlertTitle } from '@material-ui/lab';
import { removeAlert } from 'store/features/alertsSlice';
import { useAppDispatch, useAppSelector } from 'store/hooks';
import { Box } from "@material-ui/core";
import { Alert, AlertTitle } from "@material-ui/lab";
import { removeAlert } from "store/features/alertsSlice";
import { useAppDispatch, useAppSelector } from "store/hooks";
export default function ApiAlertsBox() {
const alerts = useAppSelector((state) => state.alerts.alerts);
@ -14,7 +14,7 @@ export default function ApiAlertsBox() {
if (alerts.length === 0) return null;
return (
<Box style={{ display: 'flex', justifyContent: 'center', gap: '1rem' }}>
<Box style={{ display: "flex", justifyContent: "center", gap: "1rem" }}>
{alerts.map((alert) => (
<Alert
variant="filled"

View file

@ -1,13 +1,13 @@
import { Box, makeStyles } from '@material-ui/core';
import SwapWidget from './SwapWidget';
import ApiAlertsBox from './ApiAlertsBox';
import { Box, makeStyles } from "@material-ui/core";
import SwapWidget from "./SwapWidget";
import ApiAlertsBox from "./ApiAlertsBox";
const useStyles = makeStyles((theme) => ({
outer: {
display: 'flex',
width: '100%',
flexDirection: 'column',
alignItems: 'center',
display: "flex",
width: "100%",
flexDirection: "column",
alignItems: "center",
paddingBottom: theme.spacing(1),
gap: theme.spacing(1),
},

View file

@ -1,4 +1,4 @@
import { ChangeEvent, useEffect, useState } from 'react';
import { ChangeEvent, useEffect, useState } from "react";
import {
makeStyles,
Box,
@ -7,21 +7,21 @@ import {
TextField,
LinearProgress,
Fab,
} from '@material-ui/core';
import InputAdornment from '@material-ui/core/InputAdornment';
import ArrowDownwardIcon from '@material-ui/icons/ArrowDownward';
import SwapHorizIcon from '@material-ui/icons/SwapHoriz';
import { Alert } from '@material-ui/lab';
import { satsToBtc } from 'utils/conversionUtils';
import { useAppSelector } from 'store/hooks';
import { ExtendedProviderStatus } from 'models/apiModel';
import { isSwapState } from 'models/storeModel';
import SwapDialog from '../../modal/swap/SwapDialog';
import ProviderSelect from '../../modal/provider/ProviderSelect';
} from "@material-ui/core";
import InputAdornment from "@material-ui/core/InputAdornment";
import ArrowDownwardIcon from "@material-ui/icons/ArrowDownward";
import SwapHorizIcon from "@material-ui/icons/SwapHoriz";
import { Alert } from "@material-ui/lab";
import { satsToBtc } from "utils/conversionUtils";
import { useAppSelector } from "store/hooks";
import { ExtendedProviderStatus } from "models/apiModel";
import { isSwapState } from "models/storeModel";
import SwapDialog from "../../modal/swap/SwapDialog";
import ProviderSelect from "../../modal/provider/ProviderSelect";
import {
ListSellersDialogOpenButton,
ProviderSubmitDialogOpenButton,
} from '../../modal/provider/ProviderListDialog';
} from "../../modal/provider/ProviderListDialog";
// After RECONNECTION_ATTEMPTS_UNTIL_ASSUME_DOWN failed reconnection attempts we can assume the public registry is down
const RECONNECTION_ATTEMPTS_UNTIL_ASSUME_DOWN = 1;
@ -32,9 +32,9 @@ function isRegistryDown(reconnectionAttempts: number): boolean {
const useStyles = makeStyles((theme) => ({
inner: {
width: 'min(480px, 100%)',
minHeight: '150px',
display: 'grid',
width: "min(480px, 100%)",
minHeight: "150px",
display: "grid",
padding: theme.spacing(1),
gridGap: theme.spacing(1),
},
@ -48,19 +48,19 @@ const useStyles = makeStyles((theme) => ({
padding: theme.spacing(1),
},
swapIconOuter: {
display: 'flex',
justifyContent: 'center',
display: "flex",
justifyContent: "center",
},
swapIcon: {
marginRight: theme.spacing(1),
},
noProvidersAlertOuter: {
display: 'flex',
flexDirection: 'column',
display: "flex",
flexDirection: "column",
gap: theme.spacing(1),
},
noProvidersAlertButtonsOuter: {
display: 'flex',
display: "flex",
gap: theme.spacing(1),
},
}));
@ -111,7 +111,7 @@ function HasProviderSwapWidget({
function getBtcFieldError(): string | null {
const parsedBtcAmount = Number(btcFieldValue);
if (Number.isNaN(parsedBtcAmount)) {
return 'This is not a valid number';
return "This is not a valid number";
}
if (parsedBtcAmount < satsToBtc(selectedProvider.minSwapAmount)) {
return `The minimum swap amount is ${satsToBtc(

View file

@ -1,11 +1,11 @@
import { Box, makeStyles, Typography } from '@material-ui/core';
import { Alert } from '@material-ui/lab';
import WithdrawWidget from './WithdrawWidget';
import { Box, makeStyles, Typography } from "@material-ui/core";
import { Alert } from "@material-ui/lab";
import WithdrawWidget from "./WithdrawWidget";
const useStyles = makeStyles((theme) => ({
outer: {
display: 'flex',
flexDirection: 'column',
display: "flex",
flexDirection: "column",
gridGap: theme.spacing(0.5),
},
}));

View file

@ -1,18 +1,18 @@
import { Box, Button, makeStyles, Typography } from '@material-ui/core';
import { useState } from 'react';
import SendIcon from '@material-ui/icons/Send';
import { useAppSelector, useIsRpcEndpointBusy } from 'store/hooks';
import { RpcMethod } from 'models/rpcModel';
import BitcoinIcon from '../../icons/BitcoinIcon';
import WithdrawDialog from '../../modal/wallet/WithdrawDialog';
import WalletRefreshButton from './WalletRefreshButton';
import InfoBox from '../../modal/swap/InfoBox';
import { SatsAmount } from 'renderer/components/other/Units';
import { Box, Button, makeStyles, Typography } from "@material-ui/core";
import { useState } from "react";
import SendIcon from "@material-ui/icons/Send";
import { useAppSelector, useIsRpcEndpointBusy } from "store/hooks";
import { RpcMethod } from "models/rpcModel";
import BitcoinIcon from "../../icons/BitcoinIcon";
import WithdrawDialog from "../../modal/wallet/WithdrawDialog";
import WalletRefreshButton from "./WalletRefreshButton";
import InfoBox from "../../modal/swap/InfoBox";
import { SatsAmount } from "renderer/components/other/Units";
const useStyles = makeStyles((theme) => ({
title: {
alignItems: 'center',
display: 'flex',
alignItems: "center",
display: "flex",
gap: theme.spacing(0.5),
},
}));